* [PATCH 01/70] drm/amd/display: Correct pipe usage for populating stream config
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 02/70] drm/amd/display: Add Writeback Watermarks and Latency Fields Wayne Lin
` (68 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dillon Varone, Wayne Lin
From: Dillon Varone <Dillon.Varone@amd.com>
[WHY&HOW]
Was incorrectly using stream index to index pipes, when should have
been using callback to get otg master pipe for stream.
Acked-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
.../dml2_0/dml21/dml21_translation_helper.c | 28 +++++++++++--------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
index c1a3e2496983..51260369cd8a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
@@ -90,7 +90,7 @@ static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stre
static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cfg *timing,
struct dc_stream_state *stream,
- struct pipe_ctx *pipe_ctx,
+ struct pipe_ctx *otg_master_pipe,
struct dml2_context *dml_ctx)
{
const unsigned int min_v_front_porch = (stream->timing.flags.INTERLACE != 0) ? 2 : 1;
@@ -99,24 +99,24 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf
uint64_t min_hardware_refresh_in_uhz;
uint32_t pix_clk_100hz;
- timing->h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + pipe_ctx->dsc_padding_params.dsc_hactive_padding;
+ timing->h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + otg_master_pipe->dsc_padding_params.dsc_hactive_padding;
timing->v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
timing->h_front_porch = stream->timing.h_front_porch;
timing->v_front_porch = stream->timing.v_front_porch > min_v_front_porch ?
stream->timing.v_front_porch : min_v_front_porch;
timing->pixel_clock_khz = stream->timing.pix_clk_100hz / 10;
- if (pipe_ctx->dsc_padding_params.dsc_hactive_padding != 0)
- timing->pixel_clock_khz = pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz / 10;
+ if (otg_master_pipe->dsc_padding_params.dsc_hactive_padding != 0)
+ timing->pixel_clock_khz = otg_master_pipe->dsc_padding_params.dsc_pix_clk_100hz / 10;
if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
timing->pixel_clock_khz *= 2;
- timing->h_total = stream->timing.h_total + pipe_ctx->dsc_padding_params.dsc_htotal_padding;
+ timing->h_total = stream->timing.h_total + otg_master_pipe->dsc_padding_params.dsc_htotal_padding;
timing->v_total = stream->timing.v_total;
timing->h_sync_width = stream->timing.h_sync_width;
timing->interlaced = (stream->timing.flags.INTERLACE != 0);
hblank_start = stream->timing.h_total - stream->timing.h_front_porch;
- timing->h_blank_end = hblank_start - stream->timing.h_addressable - pipe_ctx->dsc_padding_params.dsc_hactive_padding
+ timing->h_blank_end = hblank_start - stream->timing.h_addressable - otg_master_pipe->dsc_padding_params.dsc_hactive_padding
- stream->timing.h_border_left - stream->timing.h_border_right;
if (hblank_start < stream->timing.h_addressable)
@@ -135,8 +135,8 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf
/* limit min refresh rate to DC cap */
min_hardware_refresh_in_uhz = stream->timing.min_refresh_in_uhz;
if (stream->ctx->dc->caps.max_v_total != 0) {
- if (pipe_ctx->dsc_padding_params.dsc_hactive_padding != 0) {
- pix_clk_100hz = pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz;
+ if (otg_master_pipe->dsc_padding_params.dsc_hactive_padding != 0) {
+ pix_clk_100hz = otg_master_pipe->dsc_padding_params.dsc_pix_clk_100hz;
} else {
pix_clk_100hz = stream->timing.pix_clk_100hz;
}
@@ -197,7 +197,7 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf
}
static void populate_dml21_output_config_from_stream_state(struct dml2_link_output_cfg *output,
- struct dc_stream_state *stream, const struct pipe_ctx *pipe)
+ struct dc_stream_state *stream, const struct pipe_ctx *otg_master_pipe)
{
output->output_dp_lane_count = 4;
@@ -205,7 +205,7 @@ static void populate_dml21_output_config_from_stream_state(struct dml2_link_outp
case SIGNAL_TYPE_DISPLAY_PORT_MST:
case SIGNAL_TYPE_DISPLAY_PORT:
output->output_encoder = dml2_dp;
- if (check_dp2p0_output_encoder(pipe))
+ if (check_dp2p0_output_encoder(otg_master_pipe))
output->output_encoder = dml2_dp2p0;
break;
case SIGNAL_TYPE_EDP:
@@ -795,6 +795,7 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s
int disp_cfg_stream_location, disp_cfg_plane_location;
struct dml2_display_cfg *dml_dispcfg = &dml_ctx->v21.display_config;
unsigned int plane_count = 0;
+ struct pipe_ctx *otg_master_pipe;
memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
@@ -819,9 +820,12 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s
if (disp_cfg_stream_location < 0)
disp_cfg_stream_location = dml_dispcfg->num_streams++;
+ otg_master_pipe = dml_ctx->config.callbacks.get_otg_master_for_stream(&context->res_ctx, context->streams[stream_index]);
+ ASSERT(otg_master_pipe);
+
ASSERT(disp_cfg_stream_location >= 0 && disp_cfg_stream_location < __DML2_WRAPPER_MAX_STREAMS_PLANES__);
- populate_dml21_timing_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, context->streams[stream_index], &context->res_ctx.pipe_ctx[stream_index], dml_ctx);
- populate_dml21_output_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].output, context->streams[stream_index], &context->res_ctx.pipe_ctx[stream_index]);
+ populate_dml21_timing_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, context->streams[stream_index], otg_master_pipe, dml_ctx);
+ populate_dml21_output_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].output, context->streams[stream_index], otg_master_pipe);
populate_dml21_stream_overrides_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location], context->streams[stream_index], &context->stream_status[stream_index]);
dml_dispcfg->stream_descriptors[disp_cfg_stream_location].overrides.hw.twait_budgeting.fclk_pstate = dml2_twait_budgeting_setting_if_needed;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 02/70] drm/amd/display: Add Writeback Watermarks and Latency Fields
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
2026-07-15 13:37 ` [PATCH 01/70] drm/amd/display: Correct pipe usage for populating stream config Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 03/70] drm/amd/display: Add MCIF ARB programming structures Wayne Lin
` (67 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Austin Zheng, Wayne Lin
From: Austin Zheng <Austin.Zheng@amd.com>
Add fields that can used for writeback watermarks and latency margin
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Reviewed-by: Wayne Lin <Wayne.Lin@amd.com>
---
.../gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h | 1 +
.../dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 3 +++
.../dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h | 2 ++
3 files changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index 8d7960a340c2..cdfb5cd09edb 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -457,6 +457,7 @@ struct dml2_display_cfg_programming {
double fclk_pstate_change_us;
double usr_retraining_us;
double temp_read_or_ppt_watermark_us;
+ double writeback_temp_read_or_ppt_watermark_us;
} watermarks;
struct {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
index 51a66e1be7a1..b667fc9ad75f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
@@ -317,6 +317,7 @@ dml_get_var_func(meta_trip_memory_us, double, mode_lib->mp.MetaTripToMemory);
dml_get_var_func(wm_fclk_change, double, mode_lib->mp.Watermark.FCLKChangeWatermark);
dml_get_var_func(wm_usr_retraining, double, mode_lib->mp.Watermark.USRRetrainingWatermark);
dml_get_var_func(wm_temp_read_or_ppt, double, mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us);
+dml_get_var_func(wm_writeback_temp_read_or_ppt, double, mode_lib->mp.Watermark.writeback_temp_read_or_ppt_watermark_us);
dml_get_var_func(wm_dram_clock_change, double, mode_lib->mp.Watermark.DRAMClockChangeWatermark);
dml_get_var_func(fraction_of_urgent_bandwidth, double, mode_lib->mp.FractionOfUrgentBandwidth);
dml_get_var_func(fraction_of_urgent_bandwidth_imm_flip, double, mode_lib->mp.FractionOfUrgentBandwidthImmediateFlip);
@@ -13230,6 +13231,8 @@ void dml2_core_calcs_get_informative(const struct dml2_core_internal_display_mod
out->informative.watermarks.fclk_pstate_change_us = dml_get_wm_fclk_change(mode_lib);
out->informative.watermarks.usr_retraining_us = dml_get_wm_usr_retraining(mode_lib);
out->informative.watermarks.temp_read_or_ppt_watermark_us = dml_get_wm_temp_read_or_ppt(mode_lib);
+ out->informative.watermarks.writeback_temp_read_or_ppt_watermark_us = dml_get_wm_writeback_temp_read_or_ppt(mode_lib);
+
out->informative.mall.total_surface_size_in_mall_bytes = 0;
out->informative.dpp.total_num_dpps_required = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
index e9f970794488..131cec64aa48 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
@@ -212,6 +212,7 @@ struct dml2_core_internal_watermarks {
double Z8StutterEnterPlusExitWatermark;
double USRRetrainingWatermark;
double temp_read_or_ppt_watermark_us;
+ double writeback_temp_read_or_ppt_watermark_us;
};
struct dml2_core_internal_mode_support_info {
@@ -1269,6 +1270,7 @@ struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_local
double FullDETBufferingTimeC;
double WritebackDRAMClockChangeLatencyMargin;
double WritebackFCLKChangeLatencyMargin;
+ double WritebackTempReadOrPptLatencyMargin;
double WritebackLatencyHiding;
unsigned int TotalActiveWriteback;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 03/70] drm/amd/display: Add MCIF ARB programming structures
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
2026-07-15 13:37 ` [PATCH 01/70] drm/amd/display: Correct pipe usage for populating stream config Wayne Lin
2026-07-15 13:37 ` [PATCH 02/70] drm/amd/display: Add Writeback Watermarks and Latency Fields Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 04/70] drm/amd/display: Increase HDMI AV mute wait from 2 to 3 frames Wayne Lin
` (66 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dillon Varone, Wayne Lin
From: Dillon Varone <Dillon.Varone@amd.com>
[WHY&HOW]
Adds required structures to configure MCIF ARB for DWB.
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Reviewed-by: Wayne Lin <Wayne.Lin@amd.com>
---
.../dml21/inc/dml_top_dchub_registers.h | 20 +++++++++++++++++++
.../dc/dml2_0/dml21/inc/dml_top_types.h | 2 ++
2 files changed, 22 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
index bf57df42d1d9..5669be0a7340 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
@@ -153,6 +153,13 @@ struct dml2_dchub_per_pipe_register_set {
uint32_t det_size;
};
+struct dml2_mcif_per_pipe_register_set {
+ unsigned int time_per_pixel; // U6.6 format
+ unsigned int arbitration_slice;
+ unsigned int slice_lines;
+ unsigned int max_scaled_time_ns;
+};
+
struct dml2_dchub_watermark_regs {
/* watermarks */
uint32_t urgent;
@@ -188,4 +195,17 @@ struct dml2_dchub_global_register_set {
unsigned int num_watermark_sets;
};
+struct dml2_mcif_watermark_regs {
+ /* watermarks */
+ uint32_t urgent; /* (CLI) */
+ uint32_t uclk_pstate;
+ uint32_t fclk_pstate;
+ uint32_t temp_read_or_ppt;
+};
+
+struct dml2_mcif_global_register_set {
+ struct dml2_mcif_watermark_regs wm_regs[DML2_DCHUB_WATERMARK_SET_NUM];
+ unsigned int num_watermark_sets;
+};
+
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index cdfb5cd09edb..bd0d7549d20f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -436,12 +436,14 @@ struct dml2_display_cfg_programming {
} z8_stutter;
struct dml2_dchub_global_register_set global_regs;
+ struct dml2_mcif_global_register_set mcif_global_regs;
struct dml2_per_plane_programming plane_programming[DML2_MAX_PLANES];
struct dml2_per_stream_programming stream_programming[DML2_MAX_PLANES];
// Don't access this structure directly, access it through plane_programming.pipe_regs
struct dml2_dchub_per_pipe_register_set pipe_regs[DML2_MAX_PLANES];
+ struct dml2_mcif_per_pipe_register_set mcif_regs[DML2_MAX_WRITEBACK];
struct {
struct {
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 04/70] drm/amd/display: Increase HDMI AV mute wait from 2 to 3 frames
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (2 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 03/70] drm/amd/display: Add MCIF ARB programming structures Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 05/70] drm/amd/display: add dm_dmub_hw_init KUnit coverage Wayne Lin
` (65 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ray Wu
From: Ray Wu <ray.wu@amd.com>
Some HDMI sinks need additional GCP packets to properly process the
mute state before the timing generator is disabled, especially after
link re-establishment with HDMI 2.0 scrambling enabled. Waiting for
only 2 frames is insufficient for certain monitor firmware, resulting
in garbled display output on resume from suspend.
Increase the AV mute wait in dcn30_set_avmute() from 2 to 3 frames
to ensure the sink receives enough GCP packets.
Assisted-by: Cursor:Claude-Opus-4.6
Reviewed-by: Wayne Lin <wayne.lin@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
.../drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index aed9d06ec538..aa7707b2b25b 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -849,13 +849,19 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
pipe_ctx->stream_res.stream_enc,
enable);
- /* Wait for two frame to make sure AV mute is sent out */
+ /* Wait for three frames to make sure AV mute is sent out.
+ * Some HDMI sinks need additional GCP packets to properly
+ * process the mute state, especially after link re-establishment
+ * with HDMI 2.0 scrambling enabled.
+ */
if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
+ int i;
+
pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ for (i = 0; i < 3; i++) {
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+ }
}
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 05/70] drm/amd/display: add dm_dmub_hw_init KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (3 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 04/70] drm/amd/display: Increase HDMI AV mute wait from 2 to 3 frames Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 06/70] drm/amd/display: add dm_dmub_hw_resume " Wayne Lin
` (64 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for dm_dmub_hw_init() beyond the existing
early-return cases. Introduce reusable fake-DMUB fixtures (fake
dmub_srv/firmware, DMCU/ABM stubs, and adev builders) so the init path
runs without real register access, TTM allocation, or firmware loading.
New cases cover the fake-DMUB success path, unsupported hardware, BSS
data copy, hardware-init failure, auto-load timeout, the APU/DPIA DCN3.5
params, the DCN3.1.x sanity-check ranges, and DMCU/ABM initialization.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 315 ++++++++++++++++++
1 file changed, 315 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index bf90ccfbf431..4c01f7919170 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -6,14 +6,20 @@
*/
#include <kunit/test.h>
+#include <linux/firmware.h>
#include "dc.h"
#include "dc/inc/core_types.h"
+#include "dc/inc/hw/dmcu.h"
+#include "dc/inc/hw/abm.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
+#include "dm_services.h"
#include "dmub/dmub_srv.h"
#include "amdgpu_dm_dmub.h"
+#define DM_TEST_FW_SIZE 512
+
/* Tests for dm_register_dmub_notify_callback() */
static void dummy_callback(struct amdgpu_device *adev,
@@ -21,6 +27,99 @@ static void dummy_callback(struct amdgpu_device *adev,
{
}
+static bool dm_test_dmub_supported(struct dmub_srv *dmub)
+{
+ return true;
+}
+
+static bool dm_test_dmub_unsupported(struct dmub_srv *dmub)
+{
+ return false;
+}
+
+static bool dm_test_dmub_hw_initialized(struct dmub_srv *dmub)
+{
+ return true;
+}
+
+static union dmub_fw_boot_status dm_test_dmub_fw_ready(struct dmub_srv *dmub)
+{
+ union dmub_fw_boot_status status = { 0 };
+
+ status.bits.dal_fw = 1;
+ status.bits.mailbox_rdy = 1;
+ return status;
+}
+
+static union dmub_fw_boot_status dm_test_dmub_fw_not_ready(struct dmub_srv *dmub)
+{
+ union dmub_fw_boot_status status = { 0 };
+
+ return status;
+}
+
+static void dm_test_dmub_init_reg_offsets(struct dmub_srv *dmub,
+ struct dc_context *ctx)
+{
+}
+
+static bool dm_test_dmcu_init(struct dmcu *dmcu)
+{
+ return true;
+}
+
+static bool dm_test_dmcu_is_initialized(struct dmcu *dmcu)
+{
+ return true;
+}
+
+static const struct dmcu_funcs dm_test_dmcu_funcs = {
+ .dmcu_init = dm_test_dmcu_init,
+ .is_dmcu_initialized = dm_test_dmcu_is_initialized,
+};
+
+static struct dmub_srv *dm_test_alloc_dmub_srv(struct kunit *test)
+{
+ struct dmub_srv *dmub_srv;
+
+ dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
+
+ dmub_srv->sw_init = true;
+ dmub_srv->hw_init = true;
+ dmub_srv->power_state = DMUB_POWER_STATE_D0;
+ dmub_srv->hw_funcs.is_supported = dm_test_dmub_supported;
+ dmub_srv->hw_funcs.is_hw_init = dm_test_dmub_hw_initialized;
+ dmub_srv->hw_funcs.get_fw_status = dm_test_dmub_fw_ready;
+ dmub_srv->hw_funcs.init_reg_offsets = dm_test_dmub_init_reg_offsets;
+
+ return dmub_srv;
+}
+
+static const struct firmware *dm_test_alloc_dmub_fw(struct kunit *test)
+{
+ struct dmcub_firmware_header_v1_0 *hdr;
+ struct firmware *fw;
+ u8 *data;
+
+ fw = kunit_kzalloc(test, sizeof(*fw), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fw);
+
+ data = kunit_kzalloc(test, DM_TEST_FW_SIZE, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, data);
+
+ hdr = (struct dmcub_firmware_header_v1_0 *)data;
+ hdr->header.ucode_array_offset_bytes = cpu_to_le32(0);
+ hdr->header.ucode_version = cpu_to_le32(DMUB_FW_VERSION(9, 9, 9));
+ hdr->inst_const_bytes = cpu_to_le32(PSP_HEADER_BYTES_256);
+ hdr->bss_data_bytes = cpu_to_le32(0);
+
+ fw->size = DM_TEST_FW_SIZE;
+ fw->data = data;
+
+ return fw;
+}
+
/**
* dm_test_register_dmub_notify_callback_null_callback - Test null callback is rejected
* @test: The KUnit test context
@@ -395,6 +494,7 @@ static void dm_test_get_default_ips_mode_newer_default(struct kunit *test)
static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test)
{
struct amdgpu_device *adev;
+ struct dc_context *ctx;
struct dc *dc;
struct resource_pool *res_pool;
@@ -407,12 +507,47 @@ static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test)
res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
dc->res_pool = res_pool;
+ dc->ctx = ctx;
+ ctx->dc = dc;
+ ctx->driver_context = adev;
adev->dm.dc = dc;
return adev;
}
+static struct amdgpu_device *dm_test_alloc_adev_with_dmub(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dmub_srv_fb_info *fb_info;
+ int i;
+
+ adev = dm_test_alloc_adev_with_dc(test);
+
+ fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info);
+
+ fb_info->num_fb = DMUB_WINDOW_TOTAL;
+ for (i = 0; i < DMUB_WINDOW_TOTAL; i++) {
+ fb_info->fb[i].size = PAGE_SIZE;
+ fb_info->fb[i].cpu_addr = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info->fb[i].cpu_addr);
+ }
+
+ adev->dm.dmub_srv = dm_test_alloc_dmub_srv(test);
+ adev->dm.dmub_fb_info = fb_info;
+ adev->dm.dmub_fw = dm_test_alloc_dmub_fw(test);
+ adev->bios = kunit_kzalloc(test, 4, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->bios);
+ adev->bios_size = 4;
+ adev->dm.fw_inst_size = 0;
+
+ return adev;
+}
+
/**
* dm_test_dmub_hw_init_no_dmub_srv - Test hw init returns 0 when DMUB unsupported
* @test: The KUnit test context
@@ -476,6 +611,177 @@ static void dm_test_dmub_hw_init_no_firmware(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL);
}
+/**
+ * dm_test_dmub_hw_init_success_fake_dmub - Test hw init with a fake DMUB service
+ * @test: The KUnit test context
+ *
+ * With fake DMUB callbacks and preallocated framebuffer windows, the init path
+ * should reach DMUB service initialization without real register access.
+ */
+static void dm_test_dmub_hw_init_success_fake_dmub(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_TRUE(test, adev->dm.dmub_srv->hw_init);
+ KUNIT_EXPECT_NOT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_init_no_hw_support - Test hw init returns 0 when HW is unsupported
+ * @test: The KUnit test context
+ *
+ * When the DMUB service reports no hardware support, dm_dmub_hw_init() should
+ * log and return 0 without initializing the DMUB hardware.
+ */
+static void dm_test_dmub_hw_init_no_hw_support(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->dm.dmub_srv->hw_funcs.is_supported = dm_test_dmub_unsupported;
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_init_bss_data - Test hw init copies BSS data into FB memory
+ * @test: The KUnit test context
+ *
+ * When the DMUB firmware declares a non-zero BSS data size, dm_dmub_hw_init()
+ * should copy that region into the BSS framebuffer window.
+ */
+static void dm_test_dmub_hw_init_bss_data(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+ struct dmcub_firmware_header_v1_0 *hdr;
+
+ hdr = (struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data;
+ hdr->bss_data_bytes = cpu_to_le32(16);
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_TRUE(test, adev->dm.dmub_srv->hw_init);
+}
+
+/**
+ * dm_test_dmub_hw_init_hw_init_fails - Test hw init returns -EINVAL on DMUB init failure
+ * @test: The KUnit test context
+ *
+ * A framebuffer-info window count below the required total makes
+ * dmub_srv_hw_init() reject the request, so dm_dmub_hw_init() logs and
+ * returns -EINVAL. (The rejection path emits a one-time WARN via ASSERT.)
+ */
+static void dm_test_dmub_hw_init_hw_init_fails(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->dm.dmub_fb_info->num_fb = 0;
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL);
+}
+
+/**
+ * dm_test_dmub_hw_init_auto_load_timeout - Test hw init tolerates an auto-load timeout
+ * @test: The KUnit test context
+ *
+ * When the DMUB firmware never reports ready, dmub_srv_wait_for_auto_load()
+ * times out; dm_dmub_hw_init() only warns and still completes successfully.
+ */
+static void dm_test_dmub_hw_init_auto_load_timeout(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->dm.dmub_srv->hw_funcs.get_fw_status = dm_test_dmub_fw_not_ready;
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_NOT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_init_apu_dpia_dcn35 - Test hw init APU DPIA and DCN35 hw params
+ * @test: The KUnit test context
+ *
+ * On a DCN3.5 APU with a USB4 DPIA link, dm_dmub_hw_init() should populate the
+ * DPIA hw params and the DCN3.5 IPS-sequential hw params before initializing
+ * the fake DMUB service.
+ */
+static void dm_test_dmub_hw_init_apu_dpia_dcn35(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
+ adev->dm.dc->caps.is_apu = true;
+ adev->dm.dc->res_pool->usb4_dpia_count = 1;
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_TRUE(test, adev->dm.dmub_srv->hw_init);
+}
+
+/**
+ * dm_test_dmub_hw_init_sanity_checks_dcn31 - Test hw init enables DCN31 sanity checks
+ * @test: The KUnit test context
+ *
+ * On DCN3.1.2 with a DMCUB firmware version in the affected range,
+ * dm_dmub_hw_init() should enable the DC sanity-check debug flag.
+ */
+static void dm_test_dmub_hw_init_sanity_checks_dcn31(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 2);
+ adev->dm.dmcub_fw_version = DMUB_FW_VERSION(4, 0, 10);
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_TRUE(test, adev->dm.dc->debug.sanity_checks);
+}
+
+/**
+ * dm_test_dmub_hw_init_sanity_checks_dcn314 - Test hw init enables DCN314 sanity checks
+ * @test: The KUnit test context
+ *
+ * On DCN3.1.4 with a DMCUB firmware version in the affected range,
+ * dm_dmub_hw_init() should enable the DC sanity-check debug flag.
+ */
+static void dm_test_dmub_hw_init_sanity_checks_dcn314(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 4);
+ adev->dm.dmcub_fw_version = DMUB_FW_VERSION(4, 0, 10);
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_TRUE(test, adev->dm.dc->debug.sanity_checks);
+}
+
+/**
+ * dm_test_dmub_hw_init_dmcu_abm - Test hw init initializes DMCU and ABM when present
+ * @test: The KUnit test context
+ *
+ * When the resource pool exposes a DMCU and ABM, dm_dmub_hw_init() should
+ * program the PSP version, invoke the DMCU init callback, and record the
+ * running state reported by the DMCU.
+ */
+static void dm_test_dmub_hw_init_dmcu_abm(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+ struct dmcu *dmcu;
+ struct abm *abm;
+
+ dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmcu);
+
+ abm = kunit_kzalloc(test, sizeof(*abm), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, abm);
+
+ dmcu->funcs = &dm_test_dmcu_funcs;
+ dmcu->psp_version = 0x12345678;
+ adev->dm.dc->res_pool->dmcu = dmcu;
+ adev->dm.dc->res_pool->abm = abm;
+
+ KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0);
+ KUNIT_EXPECT_TRUE(test, abm->dmcu_is_running);
+}
+
/* Tests for dm_dmub_hw_resume() */
/**
@@ -561,6 +867,15 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
KUNIT_CASE(dm_test_dmub_hw_init_no_dmub_srv),
KUNIT_CASE(dm_test_dmub_hw_init_no_fb_info),
KUNIT_CASE(dm_test_dmub_hw_init_no_firmware),
+ KUNIT_CASE(dm_test_dmub_hw_init_success_fake_dmub),
+ KUNIT_CASE(dm_test_dmub_hw_init_no_hw_support),
+ KUNIT_CASE(dm_test_dmub_hw_init_bss_data),
+ KUNIT_CASE(dm_test_dmub_hw_init_hw_init_fails),
+ KUNIT_CASE(dm_test_dmub_hw_init_auto_load_timeout),
+ KUNIT_CASE(dm_test_dmub_hw_init_apu_dpia_dcn35),
+ KUNIT_CASE(dm_test_dmub_hw_init_sanity_checks_dcn31),
+ KUNIT_CASE(dm_test_dmub_hw_init_sanity_checks_dcn314),
+ KUNIT_CASE(dm_test_dmub_hw_init_dmcu_abm),
/* dm_dmub_hw_resume() */
KUNIT_CASE(dm_test_dmub_hw_resume_no_dmub_srv),
/* dm_dmub_sw_init() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 06/70] drm/amd/display: add dm_dmub_hw_resume KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (4 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 05/70] drm/amd/display: add dm_dmub_hw_init KUnit coverage Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 07/70] drm/amd/display: add fused IO " Wayne Lin
` (63 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Extend KUnit coverage for dm_dmub_hw_resume() using the fake-DMUB
fixtures. New cases cover the already-initialized wait path, the full
reinitialization path, a failed init-state query, and an auto-load
timeout, none of which require real hardware.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index 4c01f7919170..bae34436c89e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -801,6 +801,79 @@ static void dm_test_dmub_hw_resume_no_dmub_srv(struct kunit *test)
dm_dmub_hw_resume(adev);
}
+/**
+ * dm_test_dmub_hw_resume_initialized_dmub - Test resume waits for initialized DMUB
+ * @test: The KUnit test context
+ *
+ * When the fake DMUB service reports hardware already initialized, resume
+ * should only wait for firmware readiness and skip full reinitialization.
+ */
+static void dm_test_dmub_hw_resume_initialized_dmub(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test);
+
+ adev->dm.dmub_srv = dm_test_alloc_dmub_srv(test);
+
+ /* Must not crash. */
+ dm_dmub_hw_resume(adev);
+}
+
+/**
+ * dm_test_dmub_hw_resume_full_init - Test resume performs full init when uninitialized
+ * @test: The KUnit test context
+ *
+ * When the fake DMUB service reports hardware not yet initialized, resume
+ * should continue into a full dm_dmub_hw_init() and create the DC DMUB
+ * server.
+ */
+static void dm_test_dmub_hw_resume_full_init(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->dm.dmub_srv->hw_init = false;
+
+ dm_dmub_hw_resume(adev);
+
+ KUNIT_EXPECT_NOT_NULL(test, adev->dm.dc->ctx->dmub_srv);
+}
+
+/**
+ * dm_test_dmub_hw_resume_init_check_failed - Test resume handles a failed init check
+ * @test: The KUnit test context
+ *
+ * When the DMUB service is not software-initialized, the init-state query
+ * fails and resume continues into dm_dmub_hw_init(), which also fails; the
+ * call must warn and return without crashing.
+ */
+static void dm_test_dmub_hw_resume_init_check_failed(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dmub(test);
+
+ adev->dm.dmub_srv->sw_init = false;
+
+ /* Must not crash. */
+ dm_dmub_hw_resume(adev);
+}
+
+/**
+ * dm_test_dmub_hw_resume_auto_load_timeout - Test resume tolerates an auto-load timeout
+ * @test: The KUnit test context
+ *
+ * When the DMUB reports hardware already initialized but the firmware never
+ * signals ready, resume's auto-load wait times out and only warns; the call
+ * must not crash.
+ */
+static void dm_test_dmub_hw_resume_auto_load_timeout(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test);
+
+ adev->dm.dmub_srv = dm_test_alloc_dmub_srv(test);
+ adev->dm.dmub_srv->hw_funcs.get_fw_status = dm_test_dmub_fw_not_ready;
+
+ /* Must not crash; auto-load times out and only warns. */
+ dm_dmub_hw_resume(adev);
+}
+
/* Tests for dm_dmub_sw_init() */
/**
@@ -878,6 +951,10 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
KUNIT_CASE(dm_test_dmub_hw_init_dmcu_abm),
/* dm_dmub_hw_resume() */
KUNIT_CASE(dm_test_dmub_hw_resume_no_dmub_srv),
+ KUNIT_CASE(dm_test_dmub_hw_resume_initialized_dmub),
+ KUNIT_CASE(dm_test_dmub_hw_resume_full_init),
+ KUNIT_CASE(dm_test_dmub_hw_resume_init_check_failed),
+ KUNIT_CASE(dm_test_dmub_hw_resume_auto_load_timeout),
/* dm_dmub_sw_init() */
KUNIT_CASE(dm_test_dmub_sw_init_unsupported_asic),
/* dm_init_microcode() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 07/70] drm/amd/display: add fused IO KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (5 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 06/70] drm/amd/display: add dm_dmub_hw_resume " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 08/70] drm/amd/display: add DMUB command sync " Wayne Lin
` (62 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for the DMUB fused IO helpers: the
dm_dmub_aux_fused_io_callback() NULL-argument guard and the
abort_fused_io() no-DMUB-service path.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_dmub.c | 3 +-
.../amd/display/amdgpu_dm/amdgpu_dm_dmub.h | 8 +++
.../amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 52 +++++++++++++++++++
3 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
index d2148b62073d..b6f09a687969 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
@@ -831,7 +831,7 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(
return ret;
}
-static void abort_fused_io(
+STATIC_IFN_KUNIT void abort_fused_io(
struct dc_context *ctx,
const struct dmub_cmd_fused_request *request
)
@@ -845,6 +845,7 @@ static void abort_fused_io(
io->request = *request;
dm_execute_dmub_cmd(ctx, &command, DM_DMUB_WAIT_TYPE_NO_WAIT);
}
+EXPORT_IF_KUNIT(abort_fused_io);
static bool execute_fused_io(
struct amdgpu_device *dev,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
index a4a03e40ec37..ba50e1af80c1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
@@ -65,4 +65,12 @@ int dm_init_microcode(struct amdgpu_device *adev);
#define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin"
#define FIRMWARE_NAVI12_DMCU "amdgpu/navi12_dmcu.bin"
+#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+struct dc_context;
+struct dmub_cmd_fused_request;
+
+void abort_fused_io(struct dc_context *ctx,
+ const struct dmub_cmd_fused_request *request);
+#endif
+
#endif /* AMDGPU_DM_AMDGPU_DM_DMUB_H_ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index bae34436c89e..c3bd93b15d0a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -396,6 +396,22 @@ static void dm_test_dmub_aux_fused_io_callback_max_ddc_line(struct kunit *test)
KUNIT_EXPECT_EQ(test, reply_ddc_line, notify_ddc_line);
}
+/**
+ * dm_test_dmub_aux_fused_io_callback_null_args - Test the NULL-argument guard
+ * @test: The KUnit test context
+ *
+ * Passing a NULL device triggers the defensive guard (an ASSERT that maps to
+ * WARN_ON_ONCE in this build) and returns early without dereferencing the
+ * arguments. The call must not crash.
+ */
+static void dm_test_dmub_aux_fused_io_callback_null_args(struct kunit *test)
+{
+ struct dmub_notification notify = {};
+
+ /* Must not crash; guard hits ASSERT (WARN_ON_ONCE) and returns. */
+ dm_dmub_aux_fused_io_callback(NULL, ¬ify);
+}
+
/* Tests for dm_get_default_ips_mode() */
/**
@@ -916,6 +932,39 @@ static void dm_test_init_microcode_unsupported_asic(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_init_microcode(adev), 0);
}
+/* Tests for abort_fused_io() */
+
+/**
+ * dm_test_abort_fused_io_no_dmub_srv - Test fused IO abort is a safe no-op without DMUB service
+ * @test: The KUnit test context
+ *
+ * abort_fused_io() builds an abort command and submits it via
+ * dm_execute_dmub_cmd(); with no DC DMUB service the submission fails
+ * silently and the call must not crash.
+ */
+static void dm_test_abort_fused_io_no_dmub_srv(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ struct dmub_cmd_fused_request *req;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ req = kunit_kzalloc(test, sizeof(*req), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, req);
+
+ spin_lock_init(&adev->dm.dmub_lock);
+ ctx->driver_context = adev;
+ ctx->dmub_srv = NULL;
+
+ /* Must not crash. */
+ abort_fused_io(ctx, req);
+}
+
static struct kunit_case amdgpu_dm_dmub_tests[] = {
/* dm_register_dmub_notify_callback() */
KUNIT_CASE(dm_test_register_dmub_notify_callback_null_callback),
@@ -930,6 +979,7 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
/* dm_dmub_aux_fused_io_callback() */
KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes),
KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_max_ddc_line),
+ KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_null_args),
/* dm_get_default_ips_mode() */
KUNIT_CASE(dm_test_get_default_ips_mode_dcn35),
KUNIT_CASE(dm_test_get_default_ips_mode_dcn351),
@@ -959,6 +1009,8 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
KUNIT_CASE(dm_test_dmub_sw_init_unsupported_asic),
/* dm_init_microcode() */
KUNIT_CASE(dm_test_init_microcode_unsupported_asic),
+ /* abort_fused_io() */
+ KUNIT_CASE(dm_test_abort_fused_io_no_dmub_srv),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 08/70] drm/amd/display: add DMUB command sync KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (6 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 07/70] drm/amd/display: add fused IO " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 09/70] drm/amd/display: add VBIOS bounding box KUnit test Wayne Lin
` (61 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for the synchronous DMUB command helpers:
dm_execute_dmub_cmd(), amdgpu_dm_process_dmub_aux_transfer_sync(), and
amdgpu_dm_process_dmub_set_config_sync(). Cover command submission
without a DC DMUB service, AUX engine-acquire failure, protocol-error
propagation, the bounded reply-data copy, the zero-length reply branch,
and the SET_CONFIG completed-with-unknown-error path.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_dmub.c | 3 +
.../amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 369 ++++++++++++++++++
2 files changed, 372 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
index b6f09a687969..992d9f525ffc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
@@ -830,6 +830,7 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(
mutex_unlock(&adev->dm.dpia_aux_lock);
return ret;
}
+EXPORT_IF_KUNIT(amdgpu_dm_process_dmub_aux_transfer_sync);
STATIC_IFN_KUNIT void abort_fused_io(
struct dc_context *ctx,
@@ -933,6 +934,7 @@ int amdgpu_dm_process_dmub_set_config_sync(
mutex_unlock(&adev->dm.dpia_aux_lock);
return ret;
}
+EXPORT_IF_KUNIT(amdgpu_dm_process_dmub_set_config_sync);
bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
{
@@ -941,6 +943,7 @@ bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, e
guard(spinlock_irqsave)(&adev->dm.dmub_lock);
return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type);
}
+EXPORT_IF_KUNIT(dm_execute_dmub_cmd);
bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index c3bd93b15d0a..d75ee1c930ee 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -932,6 +932,366 @@ static void dm_test_init_microcode_unsupported_asic(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_init_microcode(adev), 0);
}
+/* Tests for dm_execute_dmub_cmd() */
+
+/**
+ * dm_test_execute_dmub_cmd_null_dmub_srv - Test command execution fails without DMUB service
+ * @test: The KUnit test context
+ *
+ * With no DC DMUB service on the context, dc_dmub_srv_cmd_run() returns false
+ * and dm_execute_dmub_cmd() propagates that failure.
+ */
+static void dm_test_execute_dmub_cmd_null_dmub_srv(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ union dmub_rb_cmd *cmd;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ cmd = kunit_kzalloc(test, sizeof(*cmd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cmd);
+
+ spin_lock_init(&adev->dm.dmub_lock);
+ ctx->driver_context = adev;
+ ctx->dmub_srv = NULL;
+
+ KUNIT_EXPECT_FALSE(test,
+ dm_execute_dmub_cmd(ctx, cmd, DM_DMUB_WAIT_TYPE_NO_WAIT));
+}
+
+/* Tests for amdgpu_dm_process_dmub_aux_transfer_sync() */
+
+/**
+ * dm_test_process_dmub_aux_transfer_sync_engine_acquire - Test AUX transfer engine-acquire failure
+ * @test: The KUnit test context
+ *
+ * With dc->link_count == 0, dc_process_dmub_aux_transfer_async() rejects the
+ * link index and amdgpu_dm_process_dmub_aux_transfer_sync() reports an
+ * engine-acquire error and returns -1.
+ */
+static void dm_test_process_dmub_aux_transfer_sync_engine_acquire(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ struct dc *dc;
+ struct aux_payload *payload;
+ struct dmub_notification *notify;
+ enum aux_return_code_type result = AUX_RET_SUCCESS;
+ int ret;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+
+ payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+
+ notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+
+ dc->link_count = 0;
+ ctx->dc = dc;
+ ctx->driver_context = adev;
+ adev->dm.dmub_notify = notify;
+ mutex_init(&adev->dm.dpia_aux_lock);
+ init_completion(&adev->dm.dmub_aux_transfer_done);
+
+ ret = amdgpu_dm_process_dmub_aux_transfer_sync(ctx, 0, payload, &result);
+
+ KUNIT_EXPECT_EQ(test, ret, -1);
+ KUNIT_EXPECT_EQ(test, result, AUX_RET_ERROR_ENGINE_ACQUIRE);
+}
+
+/**
+ * dm_test_process_dmub_aux_transfer_sync_protocol_error - Test AUX protocol error result
+ * @test: The KUnit test context
+ *
+ * With the completion pre-signaled and a fake DC DMUB service that rejects the
+ * command after construction, the sync helper should propagate the notification
+ * result without waiting for real firmware.
+ */
+static void dm_test_process_dmub_aux_transfer_sync_protocol_error(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ struct dc_context *dc_ctx;
+ struct dc *dc;
+ struct dc_link *link;
+ struct ddc_service *ddc;
+ struct aux_payload *payload;
+ struct dmub_notification *notify;
+ enum aux_return_code_type result = AUX_RET_SUCCESS;
+ int ret;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+
+ link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+
+ ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc);
+
+ payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+
+ notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+
+ link->ddc = ddc;
+ dc->ctx = dc_ctx;
+ dc->link_count = 1;
+ dc->links[0] = link;
+ dc_ctx->dc = dc;
+ dc_ctx->driver_context = adev;
+ dc_ctx->dmub_srv = NULL;
+ ctx->dc = dc;
+ ctx->driver_context = adev;
+ spin_lock_init(&adev->dm.dmub_lock);
+ adev->dm.dmub_notify = notify;
+ mutex_init(&adev->dm.dpia_aux_lock);
+ init_completion(&adev->dm.dmub_aux_transfer_done);
+ complete(&adev->dm.dmub_aux_transfer_done);
+ notify->result = AUX_RET_ERROR_PROTOCOL_ERROR;
+
+ ret = amdgpu_dm_process_dmub_aux_transfer_sync(ctx, 0, payload, &result);
+
+ KUNIT_EXPECT_EQ(test, ret, -1);
+ KUNIT_EXPECT_EQ(test, result, AUX_RET_ERROR_PROTOCOL_ERROR);
+}
+
+/**
+ * dm_test_process_dmub_aux_transfer_sync_copies_data - Test AUX reply data copy
+ * @test: The KUnit test context
+ *
+ * On a successful notification, the sync helper should copy the bounded reply
+ * data and report the high-nibble command reply when present.
+ */
+static void dm_test_process_dmub_aux_transfer_sync_copies_data(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ struct dc_context *dc_ctx;
+ struct dc *dc;
+ struct dc_link *link;
+ struct ddc_service *ddc;
+ struct aux_payload *payload;
+ struct dmub_notification *notify;
+ enum aux_return_code_type result = AUX_RET_ERROR_UNKNOWN;
+ u8 data[4] = { 0 };
+ u8 reply = 0;
+ int ret;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+
+ link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+
+ ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc);
+
+ payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+
+ notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+
+ link->ddc = ddc;
+ dc->ctx = dc_ctx;
+ dc->link_count = 1;
+ dc->links[0] = link;
+ dc_ctx->dc = dc;
+ dc_ctx->driver_context = adev;
+ dc_ctx->dmub_srv = NULL;
+ ctx->dc = dc;
+ ctx->driver_context = adev;
+ spin_lock_init(&adev->dm.dmub_lock);
+ adev->dm.dmub_notify = notify;
+ mutex_init(&adev->dm.dpia_aux_lock);
+ init_completion(&adev->dm.dmub_aux_transfer_done);
+ complete(&adev->dm.dmub_aux_transfer_done);
+ payload->data = data;
+ payload->reply = &reply;
+ payload->length = sizeof(data);
+ notify->result = AUX_RET_SUCCESS;
+ notify->aux_reply.command = 0xA4;
+ notify->aux_reply.length = 3;
+ notify->aux_reply.data[0] = 0x11;
+ notify->aux_reply.data[1] = 0x22;
+ notify->aux_reply.data[2] = 0x33;
+
+ ret = amdgpu_dm_process_dmub_aux_transfer_sync(ctx, 0, payload, &result);
+
+ KUNIT_EXPECT_EQ(test, ret, 3);
+ KUNIT_EXPECT_EQ(test, result, AUX_RET_SUCCESS);
+ KUNIT_EXPECT_EQ(test, reply, 0xA);
+ KUNIT_EXPECT_EQ(test, data[0], 0x11);
+ KUNIT_EXPECT_EQ(test, data[1], 0x22);
+ KUNIT_EXPECT_EQ(test, data[2], 0x33);
+}
+
+/**
+ * dm_test_process_dmub_aux_transfer_sync_zero_length - Test AUX reply with no data
+ * @test: The KUnit test context
+ *
+ * On a successful notification whose reply carries no data, the sync helper
+ * takes the zero-length branch and returns the reply length (0) without
+ * copying any payload data.
+ */
+static void dm_test_process_dmub_aux_transfer_sync_zero_length(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ struct dc_context *dc_ctx;
+ struct dc *dc;
+ struct dc_link *link;
+ struct ddc_service *ddc;
+ struct aux_payload *payload;
+ struct dmub_notification *notify;
+ enum aux_return_code_type result = AUX_RET_ERROR_UNKNOWN;
+ u8 data[4] = { 0 };
+ u8 reply = 0;
+ int ret;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+
+ link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+
+ ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc);
+
+ payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+
+ notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+
+ link->ddc = ddc;
+ dc->ctx = dc_ctx;
+ dc->link_count = 1;
+ dc->links[0] = link;
+ dc_ctx->dc = dc;
+ dc_ctx->driver_context = adev;
+ dc_ctx->dmub_srv = NULL;
+ ctx->dc = dc;
+ ctx->driver_context = adev;
+ spin_lock_init(&adev->dm.dmub_lock);
+ adev->dm.dmub_notify = notify;
+ mutex_init(&adev->dm.dpia_aux_lock);
+ init_completion(&adev->dm.dmub_aux_transfer_done);
+ complete(&adev->dm.dmub_aux_transfer_done);
+ payload->data = data;
+ payload->reply = &reply;
+ payload->length = sizeof(data);
+ notify->result = AUX_RET_SUCCESS;
+ notify->aux_reply.command = 0x03;
+ notify->aux_reply.length = 0;
+
+ ret = amdgpu_dm_process_dmub_aux_transfer_sync(ctx, 0, payload, &result);
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, result, AUX_RET_SUCCESS);
+ KUNIT_EXPECT_EQ(test, reply, 0x3);
+}
+
+/* Tests for amdgpu_dm_process_dmub_set_config_sync() */
+
+/**
+ * dm_test_process_dmub_set_config_sync_unknown_error - Test SET_CONFIG completes with unknown error
+ * @test: The KUnit test context
+ *
+ * With no DC DMUB service, dc_process_dmub_set_config_async() cannot reach the
+ * firmware and reports the command as completed with SET_CONFIG_UNKNOWN_ERROR,
+ * so amdgpu_dm_process_dmub_set_config_sync() returns 0 with that status.
+ */
+static void dm_test_process_dmub_set_config_sync_unknown_error(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct dc_context *ctx;
+ struct dc_context *dc_ctx;
+ struct dc *dc;
+ struct dc_link *link;
+ struct set_config_cmd_payload *payload;
+ struct dmub_notification *notify;
+ enum set_config_status result = SET_CONFIG_PENDING;
+ int ret;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
+
+ link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
+
+ payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload);
+
+ notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify);
+
+ dc->ctx = dc_ctx;
+ dc_ctx->dmub_srv = NULL;
+ dc->links[0] = link;
+ ctx->dc = dc;
+ ctx->driver_context = adev;
+ adev->dm.dmub_notify = notify;
+ mutex_init(&adev->dm.dpia_aux_lock);
+ init_completion(&adev->dm.dmub_aux_transfer_done);
+
+ ret = amdgpu_dm_process_dmub_set_config_sync(ctx, 0, payload, &result);
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, result, SET_CONFIG_UNKNOWN_ERROR);
+}
+
/* Tests for abort_fused_io() */
/**
@@ -1009,6 +1369,15 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
KUNIT_CASE(dm_test_dmub_sw_init_unsupported_asic),
/* dm_init_microcode() */
KUNIT_CASE(dm_test_init_microcode_unsupported_asic),
+ /* dm_execute_dmub_cmd() */
+ KUNIT_CASE(dm_test_execute_dmub_cmd_null_dmub_srv),
+ /* amdgpu_dm_process_dmub_aux_transfer_sync() */
+ KUNIT_CASE(dm_test_process_dmub_aux_transfer_sync_engine_acquire),
+ KUNIT_CASE(dm_test_process_dmub_aux_transfer_sync_protocol_error),
+ KUNIT_CASE(dm_test_process_dmub_aux_transfer_sync_copies_data),
+ KUNIT_CASE(dm_test_process_dmub_aux_transfer_sync_zero_length),
+ /* amdgpu_dm_process_dmub_set_config_sync() */
+ KUNIT_CASE(dm_test_process_dmub_set_config_sync_unknown_error),
/* abort_fused_io() */
KUNIT_CASE(dm_test_abort_fused_io_no_dmub_srv),
{}
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 09/70] drm/amd/display: add VBIOS bounding box KUnit test
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (7 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 08/70] drm/amd/display: add DMUB command sync " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 10/70] drm/amd/display: Drop CONFIG_DRM_AMD_DC_DCN4_2 from 3dlut code Wayne Lin
` (60 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for dm_dmub_get_vbios_bounding_box() covering the
default IP-version path that returns NULL without allocating GPU memory
or issuing GPINT commands.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_dmub.c | 3 ++-
.../amd/display/amdgpu_dm/amdgpu_dm_dmub.h | 1 +
.../amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 24 +++++++++++++++++++
3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
index 992d9f525ffc..21f6a01840ef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
@@ -385,7 +385,7 @@ dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev,
return DMUB_STATUS_TIMEOUT;
}
-static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
{
void *bb;
long long addr;
@@ -440,6 +440,7 @@ static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
return NULL;
}
+EXPORT_IF_KUNIT(dm_dmub_get_vbios_bounding_box);
enum dmub_ips_disable_type dm_get_default_ips_mode(
struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
index ba50e1af80c1..c53728d1c131 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
@@ -69,6 +69,7 @@ int dm_init_microcode(struct amdgpu_device *adev);
struct dc_context;
struct dmub_cmd_fused_request;
+void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev);
void abort_fused_io(struct dc_context *ctx,
const struct dmub_cmd_fused_request *request);
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
index d75ee1c930ee..ead43eeb38c7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
@@ -932,6 +932,28 @@ static void dm_test_init_microcode_unsupported_asic(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_init_microcode(adev), 0);
}
+/* Tests for dm_dmub_get_vbios_bounding_box() */
+
+/**
+ * dm_test_dmub_get_vbios_bounding_box_default_null - Test default IP version returns NULL
+ * @test: The KUnit test context
+ *
+ * For an IP version without a bounding-box size mapping, the switch falls
+ * through to the default case and dm_dmub_get_vbios_bounding_box() returns
+ * NULL without allocating GPU memory or issuing GPINT commands.
+ */
+static void dm_test_dmub_get_vbios_bounding_box_default_null(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
+
+ KUNIT_EXPECT_NULL(test, dm_dmub_get_vbios_bounding_box(adev));
+}
+
/* Tests for dm_execute_dmub_cmd() */
/**
@@ -1369,6 +1391,8 @@ static struct kunit_case amdgpu_dm_dmub_tests[] = {
KUNIT_CASE(dm_test_dmub_sw_init_unsupported_asic),
/* dm_init_microcode() */
KUNIT_CASE(dm_test_init_microcode_unsupported_asic),
+ /* dm_dmub_get_vbios_bounding_box() */
+ KUNIT_CASE(dm_test_dmub_get_vbios_bounding_box_default_null),
/* dm_execute_dmub_cmd() */
KUNIT_CASE(dm_test_execute_dmub_cmd_null_dmub_srv),
/* amdgpu_dm_process_dmub_aux_transfer_sync() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 10/70] drm/amd/display: Drop CONFIG_DRM_AMD_DC_DCN4_2 from 3dlut code
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (8 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 09/70] drm/amd/display: add VBIOS bounding box KUnit test Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 11/70] drm/amd/display: Refactor DPP_PROGRAM_GAMUT_REMAP to drop pipe_ctx param Wayne Lin
` (59 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tomasz Siemek, Rafal Ostrowski
From: Tomasz Siemek <tomasz.siemek@amd.com>
[why]
CONFIG_DRM_AMD_DC_DCN4_2 were readded to DAL by mistake resulting
in parts of dcn42 3dlut code not being compiled.
[how]
Remove readded CONFIG_DRM_AMD_DC_DCN4_2 guards.
Reviewed-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc.h | 4 ----
drivers/gpu/drm/amd/display/dc/dc_types.h | 8 --------
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 2 --
drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c | 7 +------
4 files changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index e1b7d359d917..436277acd034 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1508,13 +1508,9 @@ union dc_plane_cm_flags {
unsigned int blend_enable : 1;
/* whether legacy (lut3d_func) or DMA is valid */
unsigned int lut3d_dma_enable : 1;
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
/* RMCM lut to be used instead of MCM */
unsigned int rmcm_enable : 1;
unsigned int reserved: 27;
-#else
- unsigned int reserved: 28;
-#endif
} bits;
};
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 5ba7a2fffcf0..fccf9cb359f0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -1414,28 +1414,20 @@ enum dc_cm_lut_swizzle {
enum dc_cm_lut_pixel_format {
CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB,
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
CM_LUT_PIXEL_FORMAT_BGRA16161616_UNORM_12MSB,
-#endif
CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB,
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
CM_LUT_PIXEL_FORMAT_BGRA16161616_UNORM_12LSB,
-#endif
CM_LUT_PIXEL_FORMAT_RGBA16161616_FLOAT_FP1_5_10,
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
CM_LUT_PIXEL_FORMAT_BGRA16161616_FLOAT_FP1_5_10
-#endif
};
enum dc_cm_lut_size {
CM_LUT_SIZE_NONE,
CM_LUT_SIZE_999,
CM_LUT_SIZE_171717,
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
CM_LUT_SIZE_333333,
CM_LUT_SIZE_454545,
CM_LUT_SIZE_656565,
-#endif
};
#ifndef TRIM_CM2
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 1862670ea042..308085d24775 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -515,12 +515,10 @@ void dcn401_populate_mcm_luts(struct dc *dc,
/* Select width based on the requested LUT size */
switch (cm->lut3d_dma.size) {
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
case CM_LUT_SIZE_333333:
if (dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_33)
width = hubp_3dlut_fl_width_33;
break;
-#endif // CONFIG_DRM_AMD_DC_DCN4_2
case CM_LUT_SIZE_171717:
width = hubp_3dlut_fl_width_17;
break;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
index cc8e96ffe7d1..4376bf26f4ce 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
@@ -470,7 +470,6 @@ static bool dc_is_rmcm_3dlut_supported(struct hubp *hubp, struct mpc *mpc)
return false;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
static bool is_rmcm_3dlut_fl_supported(struct dc *dc)
{
/* size was previously hard-coded to TRANSFORMED in local_mcm,
@@ -480,7 +479,6 @@ static bool is_rmcm_3dlut_fl_supported(struct dc *dc)
return false;
return dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_17 != 0u;
}
-#endif
static void dcn42_set_mcm_location_post_blend(struct dc *dc, struct pipe_ctx *pipe_ctx, bool bPostBlend)
{
@@ -724,9 +722,8 @@ void dcn42_populate_mcm_luts(struct dc *dc,
false);
//RMCM - 3dLUT+Shaper
-#if defined(CONFIG_DRM_AMD_DC_DCN4_2)
if (cm->flags.bits.rmcm_enable &&
- is_rmcm_3dlut_fl_supported(dc)) {
+ is_rmcm_3dlut_fl_supported(dc))
dcn42_program_rmcm_luts(
hubp,
pipe_ctx,
@@ -734,8 +731,6 @@ void dcn42_populate_mcm_luts(struct dc *dc,
mpc,
lut_bank_a,
mpcc_id);
- }
-#endif /* CONFIG_DRM_AMD_DC_DCN4_2 */
/* 1D LUT */
{
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 11/70] drm/amd/display: Refactor DPP_PROGRAM_GAMUT_REMAP to drop pipe_ctx param
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (9 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 10/70] drm/amd/display: Drop CONFIG_DRM_AMD_DC_DCN4_2 from 3dlut code Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 12/70] drm/amd/display: Refactor DPP_SET_OUTPUT_TRANSFER_FUNC to drop pipe_ctx Wayne Lin
` (58 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tomasz Siemek, Alvin Lee
From: Tomasz Siemek <tomasz.siemek@amd.com>
[why]
Pipe_ctx shouldn't be passed as block sequence block parameter.
[how]
- Adjust program_gamut_remap_params struct.
- Adjust program_gamut_remap interface and implementations.
- Adjust program_gamut_remap callsites to match new signature.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 10 ++++-
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 37 +++++++++++++++----
.../amd/display/dc/hwss/dce110/dce110_hwseq.c | 11 ++++--
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 20 ++++++----
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 2 +-
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 2 +-
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 24 +++++++-----
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.h | 2 +-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 25 +++++++------
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 2 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 12 ++++--
11 files changed, 99 insertions(+), 48 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 7b3a83ba7459..188615873791 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -831,7 +831,15 @@ bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stre
for (i = 0; i < MAX_PIPES; i++) {
if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) {
pipes = &dc->current_state->res_ctx.pipe_ctx[i];
- dc->hwss.program_gamut_remap(pipes);
+ dc->hwss.program_gamut_remap(&(struct program_gamut_remap_params) {
+ .xfm = pipes->plane_res.xfm,
+ .dpp = pipes->plane_res.dpp,
+ .mpc = dc->res_pool->mpc,
+ .mpcc_id = pipes->plane_res.mpcc_inst,
+ .stream = pipes->stream,
+ .plane = pipes->plane_state,
+ .is_top_pipe = pipes->top_pipe == NULL,
+ });
ret = true;
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index e47c8cf5d036..4f30d9ac4a0d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -1069,7 +1069,14 @@ void hwss_build_fast_sequence(struct dc *dc,
if (dc->hwss.program_gamut_remap &&
(current_mpc_pipe->plane_state->update_bits.gamut_remap_change ||
current_mpc_pipe->stream->update_flags.bits.gamut_remap)) {
- block_sequence[*num_steps].params.program_gamut_remap_params.pipe_ctx = current_mpc_pipe;
+ struct program_gamut_remap_params *params = &block_sequence[*num_steps].params.program_gamut_remap_params;
+ params->dpp = current_mpc_pipe->plane_res.dpp;
+ params->mpc = dc->res_pool->mpc;
+ params->xfm = current_mpc_pipe->plane_res.xfm;
+ params->mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
+ params->plane = current_mpc_pipe->plane_state;
+ params->stream = current_mpc_pipe->stream;
+ params->is_top_pipe = current_mpc_pipe->top_pipe == NULL;
block_sequence[*num_steps].func = DPP_PROGRAM_GAMUT_REMAP;
(*num_steps)++;
}
@@ -1236,7 +1243,8 @@ void hwss_execute_sequence(struct dc *dc,
params->set_input_transfer_func_params.plane_state);
break;
case DPP_PROGRAM_GAMUT_REMAP:
- hwss_program_gamut_remap(params);
+ if (dc->hwss.program_gamut_remap)
+ dc->hwss.program_gamut_remap(¶ms->program_gamut_remap_params);
break;
case HUBP_ENABLE_3DLUT_FL:
hwss_hubp_enable_3dlut_fl(params);
@@ -1779,7 +1787,14 @@ void hwss_add_dpp_program_gamut_remap(struct block_sequence_state *seq_state,
struct pipe_ctx *pipe_ctx)
{
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].params.program_gamut_remap_params.pipe_ctx = pipe_ctx;
+ struct program_gamut_remap_params *params = &seq_state->steps[*seq_state->num_steps].params.program_gamut_remap_params;
+ params->xfm = pipe_ctx->plane_res.xfm;
+ params->dpp = pipe_ctx->plane_res.dpp;
+ params->mpc = pipe_ctx->stream->ctx->dc->res_pool->mpc;
+ params->mpcc_id = pipe_ctx->plane_res.hubp->inst;
+ params->plane = pipe_ctx->plane_state;
+ params->stream = pipe_ctx->stream;
+ params->is_top_pipe = pipe_ctx->top_pipe == NULL;
seq_state->steps[*seq_state->num_steps].func = DPP_PROGRAM_GAMUT_REMAP;
(*seq_state->num_steps)++;
}
@@ -3617,12 +3632,20 @@ void hwss_set_cursor_sdr_white_level(union block_sequence_params *params)
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
}
-void hwss_program_gamut_remap(union block_sequence_params *params)
+void hwss_program_gamut_remap(struct pipe_ctx *pipe_ctx)
{
- struct dc *dc = params->program_gamut_remap_params.pipe_ctx->stream->ctx->dc;
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
- if (dc && dc->hwss.program_gamut_remap)
- dc->hwss.program_gamut_remap(params->program_gamut_remap_params.pipe_ctx);
+ if (dc->hwss.program_gamut_remap)
+ dc->hwss.program_gamut_remap(&(struct program_gamut_remap_params) {
+ .xfm = pipe_ctx->plane_res.xfm,
+ .dpp = pipe_ctx->plane_res.dpp,
+ .mpc = dc->res_pool->mpc,
+ .mpcc_id = pipe_ctx->plane_res.hubp->inst,
+ .stream = pipe_ctx->stream,
+ .plane = pipe_ctx->plane_state,
+ .is_top_pipe = pipe_ctx->top_pipe == NULL,
+ });
}
void hwss_program_output_csc(union block_sequence_params *params)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index cce4f3065575..74b046ab3bc3 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -2810,23 +2810,26 @@ static void program_surface_visibility(const struct dc *dc,
}
-static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
+static void program_gamut_remap(struct program_gamut_remap_params *params)
{
+ struct transform *xfm = params->xfm;
+ const struct dc_stream_state *stream = params->stream;
int i = 0;
struct xfm_grph_csc_adjustment adjust;
+
memset(&adjust, 0, sizeof(adjust));
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
- if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
+ if (stream->gamut_remap_matrix.enable_remap == true) {
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
adjust.temperature_matrix[i] =
- pipe_ctx->stream->gamut_remap_matrix.matrix[i];
+ stream->gamut_remap_matrix.matrix[i];
}
- pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust);
+ xfm->funcs->transform_set_gamut_remap(xfm, &adjust);
}
static void update_plane_addr(const struct dc *dc,
struct pipe_ctx *pipe_ctx)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index f75a1794ae2a..8c636698d6d4 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -2814,28 +2814,32 @@ static void dcn10_enable_plane(
}
-void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
+void dcn10_program_gamut_remap(struct program_gamut_remap_params *params)
{
+ struct dpp *dpp = params->dpp;
+ const struct dc_stream_state *stream = params->stream;
+ const struct dc_plane_state *plane = params->plane;
int i = 0;
struct dpp_grph_csc_adjustment adjust;
+
memset(&adjust, 0, sizeof(adjust));
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
- if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
+ if (stream->gamut_remap_matrix.enable_remap == true) {
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
adjust.temperature_matrix[i] =
- pipe_ctx->stream->gamut_remap_matrix.matrix[i];
- } else if (pipe_ctx->plane_state &&
- pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
+ stream->gamut_remap_matrix.matrix[i];
+ } else if (plane &&
+ plane->gamut_remap_matrix.enable_remap == true) {
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
adjust.temperature_matrix[i] =
- pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
+ plane->gamut_remap_matrix.matrix[i];
}
- pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
+ dpp->funcs->dpp_set_gamut_remap(dpp, &adjust);
}
@@ -3152,7 +3156,7 @@ static void dcn10_update_dchubp_dpp(
if (plane_state->update_bits.full_update) {
/*gamut remap*/
- dc->hwss.program_gamut_remap(pipe_ctx);
+ hwss_program_gamut_remap(pipe_ctx);
dc->hwss.program_output_csc(dc,
pipe_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
index 476095c5dd0c..162972dfdbe8 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
@@ -108,7 +108,7 @@ void dcn10_program_pipe(
struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_state *context);
-void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx);
+void dcn10_program_gamut_remap(struct program_gamut_remap_params *params);
void dcn10_init_hw(struct dc *dc);
void dcn10_init_pipes(struct dc *dc, struct dc_state *context);
void dcn10_power_down_on_boot(struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 95e5b6a6ba0f..83794d5b838c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -1815,7 +1815,7 @@ void dcn20_update_dchubp_dpp(
|| plane_state->update_bits.gamut_remap_change
|| pipe_ctx->stream->update_flags.bits.out_csc) {
/* dpp/cm gamut remap*/
- dc->hwss.program_gamut_remap(pipe_ctx);
+ hwss_program_gamut_remap(pipe_ctx);
/*call the dcn2 method which uses mpc csc*/
dc->hwss.program_output_csc(dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index aa7707b2b25b..82a662efa49f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -357,37 +357,41 @@ bool dcn30_set_input_transfer_func(struct dc *dc,
return result;
}
-void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx)
+void dcn30_program_gamut_remap(struct program_gamut_remap_params *params)
{
+ struct dpp *dpp = params->dpp;
+ struct mpc *mpc = params->mpc;
+ int mpcc_id = params->mpcc_id;
+ const struct dc_stream_state *stream = params->stream;
+ const struct dc_plane_state *plane = params->plane;
+ bool is_top_pipe = params->is_top_pipe;
int i = 0;
struct dpp_grph_csc_adjustment dpp_adjust;
struct mpc_grph_gamut_adjustment mpc_adjust;
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
memset(&dpp_adjust, 0, sizeof(dpp_adjust));
dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
- if (pipe_ctx->plane_state &&
- pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
+ if (plane &&
+ plane->gamut_remap_matrix.enable_remap == true) {
dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
dpp_adjust.temperature_matrix[i] =
- pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
+ plane->gamut_remap_matrix.matrix[i];
}
- pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp,
+ dpp->funcs->dpp_set_gamut_remap(dpp,
&dpp_adjust);
memset(&mpc_adjust, 0, sizeof(mpc_adjust));
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
- if (pipe_ctx->top_pipe == NULL) {
- if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
+ if (is_top_pipe) {
+ if (stream->gamut_remap_matrix.enable_remap == true) {
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
mpc_adjust.temperature_matrix[i] =
- pipe_ctx->stream->gamut_remap_matrix.matrix[i];
+ stream->gamut_remap_matrix.matrix[i];
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
index a963d360a368..4182cf399424 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
@@ -63,7 +63,7 @@ bool dcn30_set_input_transfer_func(struct dc *dc,
struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state);
-void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx);
+void dcn30_program_gamut_remap(struct program_gamut_remap_params *params);
bool dcn30_set_output_transfer_func(struct dc *dc,
struct pipe_ctx *pipe_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 308085d24775..5c1ba5d88c7a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -89,28 +89,31 @@ void dcn401_initialize_min_clocks(struct dc *dc)
true);
}
-void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx)
+void dcn401_program_gamut_remap(struct program_gamut_remap_params *params)
{
+ struct mpc *mpc = params->mpc;
+ int mpcc_id = params->mpcc_id;
+ const struct dc_stream_state *stream = params->stream;
+ const struct dc_plane_state *plane = params->plane;
+ bool is_top_pipe = params->is_top_pipe;
unsigned int i = 0;
struct mpc_grph_gamut_adjustment mpc_adjust;
- unsigned int mpcc_id = pipe_ctx->plane_res.mpcc_inst;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
//For now assert if location is not pre-blend
- if (pipe_ctx->plane_state)
- ASSERT(pipe_ctx->plane_state->mcm_location == MPCC_MOVABLE_CM_LOCATION_BEFORE);
+ if (plane)
+ ASSERT(plane->mcm_location == MPCC_MOVABLE_CM_LOCATION_BEFORE);
// program MPCC_MCM_FIRST_GAMUT_REMAP
memset(&mpc_adjust, 0, sizeof(mpc_adjust));
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_FIRST_GAMUT_REMAP;
- if (pipe_ctx->plane_state &&
- pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
+ if (plane &&
+ plane->gamut_remap_matrix.enable_remap == true) {
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
mpc_adjust.temperature_matrix[i] =
- pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
+ plane->gamut_remap_matrix.matrix[i];
}
mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
@@ -126,12 +129,12 @@ void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx)
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
mpc_adjust.mpcc_gamut_remap_block_id = MPCC_OGAM_GAMUT_REMAP;
- if (pipe_ctx->top_pipe == NULL) {
- if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
+ if (is_top_pipe) {
+ if (stream->gamut_remap_matrix.enable_remap == true) {
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
mpc_adjust.temperature_matrix[i] =
- pipe_ctx->stream->gamut_remap_matrix.matrix[i];
+ stream->gamut_remap_matrix.matrix[i];
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
index a760050eea8c..6d2e93149811 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
@@ -32,7 +32,7 @@ struct ips_ono_region_state {
uint32_t current_pwr_state;
};
-void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx);
+void dcn401_program_gamut_remap(struct program_gamut_remap_params *params);
void dcn401_init_hw(struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index 65df8002d3d7..d8398b39a119 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -95,7 +95,13 @@ struct set_input_transfer_func_params {
};
struct program_gamut_remap_params {
- struct pipe_ctx *pipe_ctx;
+ struct transform *xfm;
+ struct dpp *dpp;
+ struct mpc *mpc;
+ int mpcc_id;
+ const struct dc_stream_state *stream;
+ const struct dc_plane_state *plane;
+ bool is_top_pipe;
};
struct hubp_enable_3dlut_fl_params {
@@ -1389,7 +1395,7 @@ struct hw_sequencer_funcs {
void (*program_cursor_offload_now)(struct dc *dc, const struct pipe_ctx *pipe);
/* Colour Related */
- void (*program_gamut_remap)(struct pipe_ctx *pipe_ctx);
+ void (*program_gamut_remap)(struct program_gamut_remap_params *params);
void (*program_output_csc)(struct dc *dc, struct pipe_ctx *pipe_ctx,
enum dc_color_space colorspace,
uint16_t *matrix, int opp_id);
@@ -1940,7 +1946,7 @@ void hwss_set_cursor_position(union block_sequence_params *params);
void hwss_set_cursor_sdr_white_level(union block_sequence_params *params);
-void hwss_program_gamut_remap(union block_sequence_params *params);
+void hwss_program_gamut_remap(struct pipe_ctx *pipe_ctx);
void hwss_program_output_csc(union block_sequence_params *params);
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 12/70] drm/amd/display: Refactor DPP_SET_OUTPUT_TRANSFER_FUNC to drop pipe_ctx
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (10 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 11/70] drm/amd/display: Refactor DPP_PROGRAM_GAMUT_REMAP to drop pipe_ctx param Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 13/70] drm/amd/display: Fix DP LT failure logging Wayne Lin
` (57 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tomasz Siemek, Alvin Lee
From: Tomasz Siemek <tomasz.siemek@amd.com>
[why]
Pipe_ctx shouldn't be passed as block sequence block parameter.
[how]
Adjust arguments for set_output_transfer_func and implementations.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 50 ++++++++++++++-----
.../amd/display/dc/hwss/dce110/dce110_hwseq.c | 9 ++--
.../amd/display/dc/hwss/dce60/dce60_hwseq.c | 2 +-
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 11 ++--
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 3 +-
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 20 +++++---
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.h | 3 +-
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 31 ++++++------
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.h | 4 +-
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 31 ++++++------
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.h | 8 ++-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 22 ++++----
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 4 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 11 ++--
.../display/dc/hwss/hw_sequencer_private.h | 6 +--
15 files changed, 119 insertions(+), 96 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index 4f30d9ac4a0d..6002175420a0 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -1111,10 +1111,16 @@ void hwss_build_fast_sequence(struct dc *dc,
(*num_steps)++;
}
}
- if (hws->funcs.set_output_transfer_func && current_mpc_pipe->stream->update_flags.bits.out_tf) {
- block_sequence[*num_steps].params.set_output_transfer_func_params.dc = dc;
- block_sequence[*num_steps].params.set_output_transfer_func_params.pipe_ctx = current_mpc_pipe;
- block_sequence[*num_steps].params.set_output_transfer_func_params.stream = current_mpc_pipe->stream;
+ if (current_mpc_pipe->stream->update_flags.bits.out_tf) {
+ struct set_output_transfer_func_params *otf_params =
+ &block_sequence[*num_steps].params.set_output_transfer_func_params;
+
+ otf_params->dpp = current_mpc_pipe->plane_res.dpp;
+ otf_params->xfm = current_mpc_pipe->plane_res.xfm;
+ otf_params->mpc = dc->res_pool->mpc;
+ otf_params->mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
+ otf_params->is_top_pipe = resource_is_pipe_type(pipe_ctx, OPP_HEAD);
+ otf_params->stream = current_mpc_pipe->stream;
block_sequence[*num_steps].func = DPP_SET_OUTPUT_TRANSFER_FUNC;
(*num_steps)++;
}
@@ -1271,9 +1277,7 @@ void hwss_execute_sequence(struct dc *dc,
hwss_program_manual_trigger(params);
break;
case DPP_SET_OUTPUT_TRANSFER_FUNC:
- hws->funcs.set_output_transfer_func(params->set_output_transfer_func_params.dc,
- params->set_output_transfer_func_params.pipe_ctx,
- params->set_output_transfer_func_params.stream);
+ hws->funcs.set_output_transfer_func(¶ms->set_output_transfer_func_params);
break;
case MPC_UPDATE_VISUAL_CONFIRM:
dc->hwss.update_visual_confirm_color(params->update_visual_confirm_params.dc,
@@ -1829,19 +1833,39 @@ void hwss_add_optc_program_manual_trigger(struct block_sequence_state *seq_state
* Helper function to add DPP set output transfer function to block sequence
*/
void hwss_add_dpp_set_output_transfer_func(struct block_sequence_state *seq_state,
- struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- struct dc_stream_state *stream)
+ struct dc *dc, struct pipe_ctx *pipe_ctx)
{
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].params.set_output_transfer_func_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.set_output_transfer_func_params.pipe_ctx = pipe_ctx;
- seq_state->steps[*seq_state->num_steps].params.set_output_transfer_func_params.stream = stream;
+ seq_state->steps[*seq_state->num_steps].params.set_output_transfer_func_params =
+ (struct set_output_transfer_func_params) {
+ .xfm = pipe_ctx->plane_res.xfm,
+ .dpp = pipe_ctx->plane_res.dpp,
+ .mpc = dc->res_pool->mpc,
+ .mpcc_id = pipe_ctx->plane_res.hubp->inst,
+ .is_top_pipe = resource_is_pipe_type(pipe_ctx, OPP_HEAD),
+ .stream = pipe_ctx->stream,
+ };
seq_state->steps[*seq_state->num_steps].func = DPP_SET_OUTPUT_TRANSFER_FUNC;
(*seq_state->num_steps)++;
}
}
+void hwss_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ if (dc->hwseq->funcs.set_output_transfer_func) {
+ dc->hwseq->funcs.set_output_transfer_func(
+ &(struct set_output_transfer_func_params) {
+ .xfm = pipe_ctx->plane_res.xfm,
+ .dpp = pipe_ctx->plane_res.dpp,
+ .mpc = dc->res_pool->mpc,
+ .mpcc_id = pipe_ctx->plane_res.hubp->inst,
+ .is_top_pipe = resource_is_pipe_type(pipe_ctx, OPP_HEAD),
+ .stream = pipe_ctx->stream,
+ }
+ );
+ }
+}
+
/*
* Helper function to add MPC update visual confirm to block sequence
*/
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index 74b046ab3bc3..4830a0d94177 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -607,11 +607,10 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf,
}
static bool
-dce110_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+dce110_set_output_transfer_func(struct set_output_transfer_func_params *params)
{
- (void)dc;
- struct transform *xfm = pipe_ctx->plane_res.xfm;
+ struct transform *xfm = params->xfm;
+ const struct dc_stream_state *stream = params->stream;
xfm->funcs->opp_power_on_regamma_lut(xfm, true);
xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
@@ -3181,7 +3180,7 @@ static void dce110_program_front_end_for_pipe(
hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
if (pipe_ctx->plane_state->update_bits.full_update)
- hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
+ hwss_set_output_transfer_func(dc, pipe_ctx);
DC_LOG_SURFACE(
"Pipe:%d %p: addr hi:0x%x, "
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c
index 26aa303b8237..221996b348ab 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c
@@ -338,7 +338,7 @@ dce60_program_front_end_for_pipe(
hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
if (pipe_ctx->plane_state->update_bits.full_update)
- hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
+ hwss_set_output_transfer_func(dc, pipe_ctx);
DC_LOG_SURFACE(
"Pipe:%d %p: addr hi:0x%x, "
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 8c636698d6d4..3be0bde5aea1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -2154,10 +2154,11 @@ static void log_tf(struct dc_context *ctx,
}
}
-bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+bool dcn10_set_output_transfer_func(struct set_output_transfer_func_params *params)
{
- struct dpp *dpp = pipe_ctx->plane_res.dpp;
+ struct dpp *dpp = params->dpp;
+ const struct dc_stream_state *stream = params->stream;
+ struct dc *dc;
if (!stream)
return false;
@@ -2165,6 +2166,8 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
if (dpp == NULL)
return false;
+ dc = dpp->ctx->dc;
+
dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED &&
@@ -3301,7 +3304,7 @@ void dcn10_program_pipe(
* doing heavy calculation and programming
*/
if (pipe_ctx->plane_state->update_bits.full_update)
- hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
+ hwss_set_output_transfer_func(dc, pipe_ctx);
}
void dcn10_wait_for_pending_cleared(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
index 162972dfdbe8..2cb674ba54e1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
@@ -73,8 +73,7 @@ void dcn10_program_output_csc(struct dc *dc,
enum dc_color_space colorspace,
uint16_t *matrix,
int opp_id);
-bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream);
+bool dcn10_set_output_transfer_func(struct set_output_transfer_func_params *params);
bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state);
void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 83794d5b838c..98778d5e114e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -1019,26 +1019,30 @@ void dcn20_program_output_csc(struct dc *dc,
}
}
-bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+bool dcn20_set_output_transfer_func(struct set_output_transfer_func_params *otf_params)
{
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
+ struct dpp *dpp = otf_params->dpp;
+ struct mpc *mpc = otf_params->mpc;
+ int mpcc_id = otf_params->mpcc_id;
+ bool is_top_pipe = otf_params->is_top_pipe;
+ const struct dc_stream_state *stream = otf_params->stream;
+ struct dc *dc = dpp->ctx->dc;
const struct pwl_params *params = NULL;
+
/*
* program OGAM only for the top pipe
* if there is a pipe split then fix diagnostic is required:
* how to pass OGAM parameter for stream.
* if programming for all pipes is required then remove condition
- * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
+ * is_top_pipe ,but then fix the diagnostic.
*/
if (mpc->funcs->power_on_mpc_mem_pwr)
mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
- if (pipe_ctx->top_pipe == NULL
+ if (is_top_pipe
&& mpc->funcs->set_output_gamma) {
if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func.pwl;
- else if (pipe_ctx->stream->out_transfer_func.type ==
+ else if (stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
cm_helper_translate_curve_to_hw_format(dc->ctx,
&stream->out_transfer_func,
@@ -1991,7 +1995,7 @@ static void dcn20_program_pipe(
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
pipe_ctx->stream->update_flags.bits.out_tf)
- hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
+ hwss_set_output_transfer_func(dc, pipe_ctx);
/* If the pipe has been enabled or has a different opp, we
* should reprogram the fmt. This deals with cases where
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
index 9d1ad3b29ca5..749348d3c793 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
@@ -44,8 +44,7 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
bool dcn20_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state);
-bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream);
+bool dcn20_set_output_transfer_func(struct set_output_transfer_func_params *params);
void dcn20_program_output_csc(struct dc *dc,
struct pipe_ctx *pipe_ctx,
enum dc_color_space colorspace,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index 82a662efa49f..59184e146fc9 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -256,13 +256,10 @@ bool dcn30_set_blend_lut(
return result;
}
-static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+static bool dcn30_set_mpc_shaper_3dlut(struct dpp *dpp, struct mpc *mpc,
+ int mpcc_id, const struct dc_stream_state *stream)
{
- struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
+ struct dc *dc = dpp->ctx->dc;
bool result = false;
uint32_t acquired_rmu = 0;
int mpcc_id_projected = 0;
@@ -274,8 +271,8 @@ static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx,
shaper_lut = &stream->func_shaper->pwl;
} else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
cm_helper_translate_curve_to_hw_format(stream->ctx, stream->func_shaper,
- &dpp_base->shaper_params, true);
- shaper_lut = &dpp_base->shaper_params;
+ &dpp->shaper_params, true);
+ shaper_lut = &dpp->shaper_params;
}
}
@@ -398,23 +395,25 @@ void dcn30_program_gamut_remap(struct program_gamut_remap_params *params)
mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
}
-bool dcn30_set_output_transfer_func(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+bool dcn30_set_output_transfer_func(struct set_output_transfer_func_params *otf_params)
{
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
+ struct dpp *dpp = otf_params->dpp;
+ struct mpc *mpc = otf_params->mpc;
+ int mpcc_id = otf_params->mpcc_id;
+ bool is_top_pipe = otf_params->is_top_pipe;
+ const struct dc_stream_state *stream = otf_params->stream;
+ struct dc *dc = dpp->ctx->dc;
const struct pwl_params *params = NULL;
bool ret = false;
/* program OGAM or 3DLUT only for the top pipe*/
- if (pipe_ctx->top_pipe == NULL) {
+ if (is_top_pipe) {
/*program rmu shaper and 3dlut in MPC*/
- ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream);
+ ret = dcn30_set_mpc_shaper_3dlut(dpp, mpc, mpcc_id, stream);
if (ret == false && mpc->funcs->set_output_gamma) {
if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func.pwl;
- else if (pipe_ctx->stream->out_transfer_func.type ==
+ else if (stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
cm3_helper_translate_curve_to_hw_format(stream->ctx,
&stream->out_transfer_func,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
index 4182cf399424..0399642076eb 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
@@ -65,9 +65,7 @@ bool dcn30_set_input_transfer_func(struct dc *dc,
void dcn30_program_gamut_remap(struct program_gamut_remap_params *params);
-bool dcn30_set_output_transfer_func(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream);
+bool dcn30_set_output_transfer_func(struct set_output_transfer_func_params *params);
void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx);
void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
index c2ea25927765..c5f6eb482f07 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
@@ -443,13 +443,10 @@ void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params)
}
}
-bool dcn32_set_mpc_shaper_3dlut(
- struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
+bool dcn32_set_mpc_shaper_3dlut(struct dpp *dpp, struct mpc *mpc,
+ int mpcc_id, const struct dc_stream_state *stream)
{
- struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
+ struct dc *dc = dpp->ctx->dc;
bool result = false;
const struct pwl_params *shaper_lut = NULL;
@@ -460,8 +457,8 @@ bool dcn32_set_mpc_shaper_3dlut(
else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
cm_helper_translate_curve_to_hw_format(stream->ctx,
stream->func_shaper,
- &dpp_base->shaper_params, true);
- shaper_lut = &dpp_base->shaper_params;
+ &dpp->shaper_params, true);
+ shaper_lut = &dpp->shaper_params;
}
}
@@ -566,24 +563,24 @@ bool dcn32_set_input_transfer_func(struct dc *dc,
return result;
}
-bool dcn32_set_output_transfer_func(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+bool dcn32_set_output_transfer_func(struct set_output_transfer_func_params *otf_params)
{
- (void)dc;
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
+ struct dpp *dpp = otf_params->dpp;
+ struct mpc *mpc = otf_params->mpc;
+ int mpcc_id = otf_params->mpcc_id;
+ bool is_top_pipe = otf_params->is_top_pipe;
+ const struct dc_stream_state *stream = otf_params->stream;
const struct pwl_params *params = NULL;
bool ret = false;
/* program OGAM or 3DLUT only for the top pipe*/
- if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
+ if (is_top_pipe) {
/*program shaper and 3dlut in MPC*/
- ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
+ ret = dcn32_set_mpc_shaper_3dlut(dpp, mpc, mpcc_id, stream);
if (ret == false && mpc->funcs->set_output_gamma) {
if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func.pwl;
- else if (pipe_ctx->stream->out_transfer_func.type ==
+ else if (stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
cm3_helper_translate_curve_to_hw_format(stream->ctx,
&stream->out_transfer_func,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
index 0303a5953673..090d94d38343 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
@@ -54,12 +54,10 @@ bool dcn32_set_input_transfer_func(struct dc *dc,
struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state);
-bool dcn32_set_mpc_shaper_3dlut(
- struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream);
+bool dcn32_set_mpc_shaper_3dlut(struct dpp *dpp_base, struct mpc *mpc,
+ int mpcc_id, const struct dc_stream_state *stream);
-bool dcn32_set_output_transfer_func(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream);
+bool dcn32_set_output_transfer_func(struct set_output_transfer_func_params *params);
void dcn32_init_hw(struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 5c1ba5d88c7a..161ef57ebce1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -696,24 +696,24 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
return result;
}
-bool dcn401_set_output_transfer_func(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream)
+bool dcn401_set_output_transfer_func(struct set_output_transfer_func_params *otf_params)
{
- (void)dc;
- int mpcc_id = pipe_ctx->plane_res.hubp->inst;
- struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
+ struct dpp *dpp = otf_params->dpp;
+ struct mpc *mpc = otf_params->mpc;
+ int mpcc_id = otf_params->mpcc_id;
+ bool is_top_pipe = otf_params->is_top_pipe;
+ const struct dc_stream_state *stream = otf_params->stream;
const struct pwl_params *params = NULL;
bool ret = false;
/* program OGAM or 3DLUT only for the top pipe*/
- if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
+ if (is_top_pipe) {
/*program shaper and 3dlut in MPC*/
- ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
+ ret = dcn32_set_mpc_shaper_3dlut(dpp, mpc, mpcc_id, stream);
if (ret == false && mpc->funcs->set_output_gamma) {
if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func.pwl;
- else if (pipe_ctx->stream->out_transfer_func.type ==
+ else if (stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
cm3_helper_translate_curve_to_hw_format(stream->ctx,
&stream->out_transfer_func,
@@ -2397,7 +2397,7 @@ void dcn401_program_pipe(
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
pipe_ctx->stream->update_flags.bits.out_tf)
- hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
+ hwss_set_output_transfer_func(dc, pipe_ctx);
/* If the pipe has been enabled or has a different opp, we
* should reprogram the fmt. This deals with cases where
@@ -2555,7 +2555,7 @@ void dcn401_program_pipe_sequence(
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
pipe_ctx->stream->update_flags.bits.out_tf) {
- hwss_add_dpp_set_output_transfer_func(seq_state, dc, pipe_ctx, pipe_ctx->stream);
+ hwss_add_dpp_set_output_transfer_func(seq_state, dc, pipe_ctx);
}
/* If the pipe has been enabled or has a different opp, we
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
index 6d2e93149811..f90e25243ead 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
@@ -38,9 +38,7 @@ void dcn401_init_hw(struct dc *dc);
bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state);
-bool dcn401_set_output_transfer_func(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream);
+bool dcn401_set_output_transfer_func(struct set_output_transfer_func_params *params);
void dcn401_trigger_3dlut_dma_load(struct dc *dc,
struct pipe_ctx *pipe_ctx);
void dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx *pipe_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index d8398b39a119..e8bf96a7d63a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -138,8 +138,11 @@ struct program_bias_and_scale_params {
};
struct set_output_transfer_func_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct transform *xfm;
+ struct dpp *dpp;
+ struct mpc *mpc;
+ int mpcc_id;
+ bool is_top_pipe;
const struct dc_stream_state *stream;
};
@@ -1993,7 +1996,9 @@ void hwss_add_optc_program_manual_trigger(struct block_sequence_state *seq_state
struct pipe_ctx *pipe_ctx);
void hwss_add_dpp_set_output_transfer_func(struct block_sequence_state *seq_state,
- struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_stream_state *stream);
+ struct dc *dc, struct pipe_ctx *pipe_ctx);
+
+void hwss_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx);
void hwss_add_mpc_update_visual_confirm(struct block_sequence_state *seq_state,
struct dc *dc, struct pipe_ctx *pipe_ctx, int mpcc_id);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
index b4956893ae9a..31ace62a37d9 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
@@ -67,6 +67,8 @@ struct dc_phy_addr_space_config;
struct dc_virtual_addr_space_config;
struct hubp;
struct dpp;
+struct transform;
+struct mpc;
struct dce_hwseq;
struct timing_generator;
struct tg_color;
@@ -92,9 +94,7 @@ struct hwseq_private_funcs {
bool (*set_input_transfer_func)(struct dc *dc,
struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state);
- bool (*set_output_transfer_func)(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- const struct dc_stream_state *stream);
+ bool (*set_output_transfer_func)(struct set_output_transfer_func_params *params);
void (*power_down)(struct dc *dc);
void (*enable_display_pipe_clock_gating)(struct dc_context *ctx,
bool clock_gating);
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 13/70] drm/amd/display: Fix DP LT failure logging
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (11 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 12/70] drm/amd/display: Refactor DPP_SET_OUTPUT_TRANSFER_FUNC to drop pipe_ctx Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 14/70] drm/amd/display: Add updated MCIF ARB register definitions Wayne Lin
` (56 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ilya Bakoulin, George Shen
From: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
[Why/How]
The final DP LT failure meant to be logged as DC warning is skipped due
to a break statement above. Move logging up to make sure we don't miss
LT fail events.
Reviewed-by: George Shen <george.shen@amd.com>
Signed-off-by: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../dc/link/protocols/link_dp_training.c | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
index 605bf19dc4f2..04eedec8a230 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
@@ -1721,6 +1721,20 @@ bool perform_link_training_with_retries(
}
}
+ if (j == (attempts - 1)) {
+ DC_LOG_WARNING(
+ "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
+ __func__, link->link_index, (unsigned int)j + 1, attempts,
+ cur_link_settings.link_rate, cur_link_settings.lane_count,
+ cur_link_settings.link_spread, status);
+ } else {
+ DC_LOG_HW_LINK_TRAINING(
+ "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
+ __func__, link->link_index, (unsigned int)j + 1, attempts,
+ cur_link_settings.link_rate, cur_link_settings.lane_count,
+ cur_link_settings.link_spread, status);
+ }
+
fail_count++;
dp_trace_lt_fail_count_update(link, fail_count, false);
if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
@@ -1740,20 +1754,6 @@ bool perform_link_training_with_retries(
do_fallback = false;
}
- if (j == (attempts - 1)) {
- DC_LOG_WARNING(
- "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
- __func__, link->link_index, (unsigned int)j + 1, attempts,
- cur_link_settings.link_rate, cur_link_settings.lane_count,
- cur_link_settings.link_spread, status);
- } else {
- DC_LOG_HW_LINK_TRAINING(
- "%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n",
- __func__, link->link_index, (unsigned int)j + 1, attempts,
- cur_link_settings.link_rate, cur_link_settings.lane_count,
- cur_link_settings.link_spread, status);
- }
-
dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
/* Abort link training if failure due to sink being unplugged. */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 14/70] drm/amd/display: Add updated MCIF ARB register definitions
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (12 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 13/70] drm/amd/display: Fix DP LT failure logging Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 15/70] drm/amd/display: Replace amdgpu_dm_kunit_helpers.h with dm_helpers.h Wayne Lin
` (55 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dillon Varone, Austin Zheng
From: Dillon Varone <Dillon.Varone@amd.com>
[WHY&HOW]
DCN4+ use a new structure for MCIF arbiter registers.
Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/dc/inc/hw/mcif_wb.h | 24 ++++++++++++-------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h
index 15cb782f129b..aae0ad7ae835 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h
@@ -27,6 +27,7 @@
#include "dc_hw_types.h"
+#include "dml2_0/dml21/inc/dml_top_dchub_registers.h"
enum mmhubbub_wbif_mode {
PACKED_444 = 0,
@@ -36,14 +37,21 @@ enum mmhubbub_wbif_mode {
};
struct mcif_arb_params {
-
- unsigned int time_per_pixel;
- unsigned int cli_watermark[4];
- unsigned int pstate_watermark[4];
- unsigned int arbitration_slice;
- unsigned int slice_lines;
- unsigned int max_scaled_time;
- unsigned int dram_speed_change_duration;
+ union {
+ struct {
+ unsigned int time_per_pixel;
+ unsigned int cli_watermark[4];
+ unsigned int pstate_watermark[4];
+ unsigned int arbitration_slice;
+ unsigned int slice_lines;
+ unsigned int max_scaled_time;
+ unsigned int dram_speed_change_duration;
+ };
+ struct {
+ struct dml2_mcif_global_register_set global_regs;
+ struct dml2_mcif_per_pipe_register_set inst_regs;
+ } dcn4x; //dcn4+
+ };
};
struct mcif_irq_params {
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 15/70] drm/amd/display: Replace amdgpu_dm_kunit_helpers.h with dm_helpers.h
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (13 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 14/70] drm/amd/display: Add updated MCIF ARB register definitions Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 16/70] drm/amd/display: Add stream creation tests for connector Wayne Lin
` (54 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Drop the amdgpu_dm_kunit_helpers.h include across the amdgpu_dm source
files and use dm_helpers.h instead
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 -
.../amd/display/amdgpu_dm/amdgpu_dm_audio.c | 2 +-
.../display/amdgpu_dm/amdgpu_dm_backlight.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 2 +-
.../display/amdgpu_dm/amdgpu_dm_connector.c | 1 -
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_dmub.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 1 -
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 1 -
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 2 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 2 +-
.../amdgpu_dm/amdgpu_dm_kunit_helpers.h | 20 -------------------
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 1 -
.../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 2 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_quirks.c | 2 +-
.../amd/display/amdgpu_dm/amdgpu_dm_replay.c | 2 +-
.../display/amdgpu_dm/amdgpu_dm_services.c | 2 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c | 2 +-
drivers/gpu/drm/amd/display/dc/dm_helpers.h | 11 ++++++++++
drivers/gpu/drm/amd/display/dc/os_types.h | 10 ++++++++++
24 files changed, 37 insertions(+), 41 deletions(-)
delete mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h
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 f3ac4307eb5a..cb10c5fa374e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -70,7 +70,6 @@
#include "amdgpu_dm_audio.h"
#include "amdgpu_dm_dmub.h"
#include "amdgpu_dm_connector.h"
-#include "amdgpu_dm_kunit_helpers.h"
#include "ivsrcid/ivsrcid_vislands30.h"
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c
index 7bba82ce2182..fb0ff9c9c823 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c
@@ -26,7 +26,7 @@
#include "amdgpu.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_audio.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "dc.h"
#include <linux/component.h>
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
index 373ef4d217f1..43bf6cccb9ac 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
@@ -47,7 +47,7 @@
#include "amdgpu_dm_trace.h"
#include "amd_shared.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
int bl_idx)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 77e0480d469d..bcb2cee8c6e8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -33,7 +33,7 @@
#include "amdgpu_dm_colorop.h"
#include "dc.h"
#include "modules/color/color_gamma.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
/**
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index 0301cb333770..eb4a4722d50f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -31,7 +31,7 @@
#include "amdgpu.h"
#include "amdgpu_dm_colorop.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "dc.h"
const u64 amdgpu_dm_supported_degam_tfs =
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 56e3e32c184f..c7d8810958f6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -42,7 +42,6 @@
#include "amdgpu_display.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_connector.h"
-#include "amdgpu_dm_kunit_helpers.h"
#include "amdgpu_dm_plane.h"
#include "amdgpu_dm_crtc.h"
#include "amdgpu_dm_wb.h"
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 47fd849c58a1..1f9528364e53 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -33,7 +33,7 @@
#include "amdgpu_securedisplay.h"
#include "amdgpu_dm_psr.h"
#include "amdgpu_dm_replay.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
static const char *const pipe_crc_sources[] = {
"none",
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 81574e447728..ec863b9f4466 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -34,7 +34,7 @@
#include "amdgpu_dm_plane.h"
#include "amdgpu_dm_trace.h"
#include "amdgpu_dm_debugfs.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "modules/inc/mod_power.h"
#define HPD_DETECTION_PERIOD_uS 2000000
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
index 21f6a01840ef..7a60b29e021c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
@@ -38,7 +38,7 @@
#include "amdgpu_ucode.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_dmub.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include <linux/component.h>
#include <linux/firmware.h>
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 9a2d2706deb0..f25783bf1b48 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -31,7 +31,6 @@
#include "dm_helpers.h"
#include <drm/display/drm_hdcp_helper.h>
#include "hdcp_psp.h"
-#include "amdgpu_dm_kunit_helpers.h"
/*
* If the SRM version being loaded is less than or equal to the
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index c59da4f447fc..c172bb76bcda 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -48,7 +48,6 @@
#include "dm_helpers.h"
#include "ddc_service_types.h"
#include "clk_mgr.h"
-#include "amdgpu_dm_kunit_helpers.h"
#include "amdgpu_dm_helpers.h"
#define MCCS_DEST_ADDR (0x6E >> 1)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index 087401f7a8e4..e6e2b19e09e7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -33,7 +33,7 @@
#include "amdgpu_display.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_irq.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "amdgpu_dm_crtc.h"
#include "amdgpu_dm_hdcp.h"
#include "amdgpu_dm_mst_types.h"
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
index a9575bf25fc2..4e57572e12b6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
@@ -32,7 +32,7 @@
#include "amdgpu_dm_ism.h"
#include "amdgpu_dm_crtc.h"
#include "amdgpu_dm_trace.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
/**
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h
deleted file mode 100644
index 1f910a6a00c0..000000000000
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright 2026 Advanced Micro Devices, Inc.
- */
-
-#ifndef AMDGPU_DM_KUNIT_HELPERS_H
-#define AMDGPU_DM_KUNIT_HELPERS_H
-
-#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
-#define STATIC_IFN_KUNIT
-#define INLINE_IFN_KUNIT inline
-#define EXPORT_IF_KUNIT(symbol) EXPORT_SYMBOL(symbol)
-
-#else
-#define STATIC_IFN_KUNIT static
-#define INLINE_IFN_KUNIT
-#define EXPORT_IF_KUNIT(symbol)
-#endif
-
-#endif /* AMDGPU_DM_KUNIT_HELPERS_H */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index a7679675dd32..18ef0e875179 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -40,7 +40,6 @@
#include "dc.h"
#include "dm_helpers.h"
-#include "amdgpu_dm_kunit_helpers.h"
#include "ddc_service_types.h"
#include "dpcd_defs.h"
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 4ffbe2dbdf97..c67d068b9a5d 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
@@ -37,7 +37,7 @@
#include "amdgpu_display.h"
#include "amdgpu_dm_trace.h"
#include "amdgpu_dm_plane.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "amdgpu_dm_colorop.h"
#include "gc/gc_11_0_0_offset.h"
#include "gc/gc_11_0_0_sh_mask.h"
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
index 0d2e5294d062..8431e164a0db 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
@@ -33,7 +33,7 @@
#include "amdgpu_dm_irq.h"
#include "amdgpu_pm.h"
#include "dm_pp_smu.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "amdgpu_dm_pp_smu.h"
STATIC_IFN_KUNIT void build_pm_display_cfg(
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
index f87de3d18ac0..dbad0a6d3a2b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
@@ -30,7 +30,7 @@
#include "dc.h"
#include "amdgpu_dm.h"
#include "modules/power/power_helpers.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
STATIC_IFN_KUNIT
bool link_supports_psrsu(struct dc_link *link)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c
index cf28d50c3b5e..0a7602ed70b2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c
@@ -28,7 +28,7 @@
#include "amdgpu.h"
#include "amdgpu_dm.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
struct amdgpu_dm_quirks {
bool aux_hpd_discon;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
index 42e17119461d..ee2e4754b089 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
@@ -31,7 +31,7 @@
#include "modules/power/power_helpers.h"
#include "dmub/inc/dmub_cmd.h"
#include "dc/inc/link_service.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
/*
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
index 6c0464754ed8..dbdda6ed12d4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
@@ -36,7 +36,7 @@
#include "amdgpu_dm_irq.h"
#include "amdgpu_pm.h"
#include "amdgpu_dm_trace.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
unsigned long long
dm_get_elapse_time_in_ns(struct dc_context *ctx,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c
index 9e7bad4d6ed0..a7594012a0b2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c
@@ -29,7 +29,7 @@
#include "amdgpu.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_wb.h"
-#include "amdgpu_dm_kunit_helpers.h"
+#include "dm_helpers.h"
#include "amdgpu_display.h"
#include "dc.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 63704d21a0b5..f5252931ce35 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -192,6 +192,17 @@ void dm_helpers_mccs_vcp_set(
struct dc_link *link,
struct dc_sink *sink);
+#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+#define STATIC_IFN_KUNIT
+#define INLINE_IFN_KUNIT inline
+#define EXPORT_IF_KUNIT(symbol) EXPORT_SYMBOL(symbol)
+
+#else
+#define STATIC_IFN_KUNIT static
+#define INLINE_IFN_KUNIT
+#define EXPORT_IF_KUNIT(symbol)
+#endif
+
bool dm_helpers_dp_handle_test_pattern_request(
struct dc_context *ctx,
const struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h
index 6af831710489..538d00105738 100644
--- a/drivers/gpu/drm/amd/display/dc/os_types.h
+++ b/drivers/gpu/drm/amd/display/dc/os_types.h
@@ -57,6 +57,16 @@
#include "amdgpu_dm/dc_fpu.h"
#endif /* CONFIG_DRM_AMD_DC_FP */
+
+/*
+ * On Linux this is provided by <linux/kconfig.h> and evaluates Kconfig
+ * options for both built-in (=y) and module (=m) cases. Windows has no
+ * Kconfig, so config options are never set here and this always yields 0.
+ */
+#ifndef IS_ENABLED
+#define IS_ENABLED(option) 0
+#endif
+
/*
*
* general debug capabilities
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 16/70] drm/amd/display: Add stream creation tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (14 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 15/70] drm/amd/display: Replace amdgpu_dm_kunit_helpers.h with dm_helpers.h Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 17/70] drm/amd/display: Add detect and poll " Wayne Lin
` (53 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for create_stream_for_sink(): fake sink success,
dm context setup, virtual signal handling, scaling source, and reuse
of an existing sink.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 6 +
.../tests/amdgpu_dm_connector_test.c | 176 ++++++++++++++++++
drivers/gpu/drm/amd/display/dc/core/dc_sink.c | 2 +
.../gpu/drm/amd/display/dc/core/dc_stream.c | 2 +
5 files changed, 188 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index c7d8810958f6..5c3dd1eb7878 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1345,7 +1345,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
}
#endif
-static struct dc_stream_state *
+STATIC_IFN_KUNIT struct dc_stream_state *
create_stream_for_sink(struct drm_connector *connector,
const struct drm_display_mode *drm_mode,
const struct dm_connector_state *dm_state,
@@ -1529,6 +1529,7 @@ create_stream_for_sink(struct drm_connector *connector,
return stream;
}
+EXPORT_IF_KUNIT(create_stream_for_sink);
/**
* amdgpu_dm_connector_poll - Poll a connector to see if it's connected to a display
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index ad277fff57de..51858c92f922 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -158,6 +158,12 @@ void fill_stream_properties_from_drm_display_mode(
const struct drm_connector_state *connector_state,
const struct dc_stream_state *old_stream,
int requested_bpc);
+struct dc_stream_state *
+create_stream_for_sink(struct drm_connector *connector,
+ const struct drm_display_mode *drm_mode,
+ const struct dm_connector_state *dm_state,
+ const struct dc_stream_state *old_stream,
+ int requested_bpc);
enum display_content_type
get_output_content_type(const struct drm_connector_state *connector_state);
bool adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index b3d16123402d..2d58021b48f3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -3604,6 +3604,176 @@ static void dm_test_fill_stream_aspect_ratio(struct kunit *test)
(int)ASPECT_RATIO_16_9);
}
+/* Tests for create_stream_for_sink() */
+
+/*
+ * Build the inputs for create_stream_for_sink(). The connector is registered
+ * against a real kunit drm_device so that to_amdgpu_dm_connector() and the drm
+ * debug helpers resolve. The DC link carries a zeroed dc_context so that
+ * dc_create_stream_for_sink() can allocate and construct a stream.
+ *
+ * By default no dc_sink is attached, so create_stream_for_sink() builds a fake
+ * VIRTUAL sink. The VIRTUAL signal keeps the DSC, audio and DP/HDMI infoframe
+ * paths as no-ops, making the exercised behaviour deterministic.
+ */
+struct dm_test_stream_ctx {
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_context *dc_ctx;
+ struct dc_link *link;
+ struct dm_connector_state *dm_state;
+ struct drm_display_mode *mode;
+};
+
+static struct dm_test_stream_ctx *dm_test_stream_ctx_alloc(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx;
+ struct device *dev;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(*ctx->drm), 0,
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_test_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL), 0);
+
+ ctx->dc_ctx = kunit_kzalloc(test, sizeof(*ctx->dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->dc_ctx);
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->ctx = ctx->dc_ctx;
+ ctx->link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ ctx->aconnector->dc_link = ctx->link;
+ ctx->aconnector->dc_sink = NULL;
+
+ ctx->dm_state = kunit_kzalloc(test, sizeof(*ctx->dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->dm_state);
+ ctx->dm_state->scaling = RMX_OFF;
+
+ ctx->mode = kunit_kzalloc(test, sizeof(*ctx->mode), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->mode);
+ ctx->mode->hdisplay = 1920;
+ ctx->mode->vdisplay = 1080;
+ ctx->mode->clock = 148500;
+
+ return ctx;
+}
+
+/**
+ * dm_test_create_stream_fake_sink_success - Test a stream is built from a fake sink
+ * @test: The KUnit test context
+ */
+static void dm_test_create_stream_fake_sink_success(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_sets_dm_context - Test dm_stream_context points to aconnector
+ * @test: The KUnit test context
+ */
+static void dm_test_create_stream_sets_dm_context(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_PTR_EQ(test, stream->dm_stream_context, ctx->aconnector);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_virtual_signal - Test the fake sink yields a VIRTUAL signal
+ * @test: The KUnit test context
+ */
+static void dm_test_create_stream_virtual_signal(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_VIRTUAL);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_scaling_src - Test the source rect follows the mode
+ * @test: The KUnit test context
+ *
+ * With scaling off the full-screen source viewport matches the requested mode.
+ */
+static void dm_test_create_stream_scaling_src(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->src.width, 1920);
+ KUNIT_EXPECT_EQ(test, (int)stream->src.height, 1080);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_existing_sink - Test the existing-sink retain path
+ * @test: The KUnit test context
+ *
+ * When the connector already has a dc_sink, create_stream_for_sink() reuses it
+ * instead of building a fake sink.
+ */
+static void dm_test_create_stream_existing_sink(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_sink_init_data sink_init = { 0 };
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ sink_init.link = ctx->link;
+ sink_init.sink_signal = SIGNAL_TYPE_VIRTUAL;
+ sink = dc_sink_create(&sink_init);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
+
+ ctx->aconnector->dc_sink = sink;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_PTR_EQ(test, stream->sink, sink);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -3798,6 +3968,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_fill_stream_color_depth_requested_bpc),
KUNIT_CASE(dm_test_fill_stream_content_type),
KUNIT_CASE(dm_test_fill_stream_aspect_ratio),
+ /* create_stream_for_sink */
+ KUNIT_CASE(dm_test_create_stream_fake_sink_success),
+ KUNIT_CASE(dm_test_create_stream_sets_dm_context),
+ KUNIT_CASE(dm_test_create_stream_virtual_signal),
+ KUNIT_CASE(dm_test_create_stream_scaling_src),
+ KUNIT_CASE(dm_test_create_stream_existing_sink),
{}
};
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c
index 455fa5dd1420..436d033361ab 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c
@@ -73,6 +73,7 @@ void dc_sink_release(struct dc_sink *sink)
{
kref_put(&sink->refcount, dc_sink_free);
}
+EXPORT_IF_KUNIT(dc_sink_release);
struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params)
{
@@ -94,6 +95,7 @@ struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params)
alloc_fail:
return NULL;
}
+EXPORT_IF_KUNIT(dc_sink_create);
/*******************************************************************************
* Protected functions - visible only inside of DC (not visible in DM)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index ce045ef6347c..a32b6eb796f7 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -24,6 +24,7 @@
*/
#include "dm_services.h"
+#include "dm_helpers.h"
#include "basics/dc_common.h"
#include "dc.h"
#include "core_types.h"
@@ -203,6 +204,7 @@ void dc_stream_release(struct dc_stream_state *stream)
kref_put(&stream->refcount, dc_stream_free);
}
}
+EXPORT_IF_KUNIT(dc_stream_release);
struct dc_stream_state *dc_create_stream_for_sink(
struct dc_sink *sink)
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 17/70] drm/amd/display: Add detect and poll tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (15 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 16/70] drm/amd/display: Add stream creation tests for connector Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 18/70] drm/amd/display: Add register and unregister " Wayne Lin
` (52 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for amdgpu_dm_connector_detect() and
amdgpu_dm_connector_poll(): force on (analog/digital), force off,
sink present/absent, and the DAC-load cached status path.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 6 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 4 +
.../tests/amdgpu_dm_connector_test.c | 157 ++++++++++++++++++
3 files changed, 165 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 5c3dd1eb7878..94118f7f67c6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1545,7 +1545,7 @@ EXPORT_IF_KUNIT(create_stream_for_sink);
*
* Return: The probed connector status (connected/disconnected/unknown).
*/
-static enum drm_connector_status
+STATIC_IFN_KUNIT enum drm_connector_status
amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
{
struct drm_connector *connector = &aconnector->base;
@@ -1597,6 +1597,7 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
mutex_unlock(&aconnector->hpd_lock);
return status;
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_poll);
/**
* amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display
@@ -1620,7 +1621,7 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
* Return: The connector status (connected, disconnected, or unknown).
*
*/
-static enum drm_connector_status
+STATIC_IFN_KUNIT enum drm_connector_status
amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
@@ -1644,6 +1645,7 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
return (aconnector->dc_sink ? connector_status_connected :
connector_status_disconnected);
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_detect);
int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
struct drm_connector_state *connector_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index 51858c92f922..8c4ba5a90ade 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -164,6 +164,10 @@ create_stream_for_sink(struct drm_connector *connector,
const struct dm_connector_state *dm_state,
const struct dc_stream_state *old_stream,
int requested_bpc);
+enum drm_connector_status
+amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force);
+enum drm_connector_status
+amdgpu_dm_connector_detect(struct drm_connector *connector, bool force);
enum display_content_type
get_output_content_type(const struct drm_connector_state *connector_state);
bool adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 2d58021b48f3..f38706e4d1c2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -3774,6 +3774,155 @@ static void dm_test_create_stream_existing_sink(struct kunit *test)
dc_sink_release(sink);
}
+/* Tests for amdgpu_dm_connector_detect() */
+
+/*
+ * A non-DisplayPort connector keeps update_subconnector_property() a no-op and,
+ * because the kunit thread is not the poll worker, the analog poll branch is
+ * skipped. That leaves the forced-state and dc_sink presence branches as the
+ * deterministic behaviour to exercise.
+ */
+static struct amdgpu_dm_connector *dm_test_detect_connector(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+
+ return dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+}
+
+/**
+ * dm_test_detect_force_on - Test DRM_FORCE_ON reports connected
+ * @test: The KUnit test context
+ */
+static void dm_test_detect_force_on(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test);
+
+ aconnector->base.force = DRM_FORCE_ON;
+
+ KUNIT_EXPECT_EQ(test,
+ (int)amdgpu_dm_connector_detect(&aconnector->base, false),
+ (int)connector_status_connected);
+}
+
+/**
+ * dm_test_detect_force_on_digital - Test DRM_FORCE_ON_DIGITAL reports connected
+ * @test: The KUnit test context
+ */
+static void dm_test_detect_force_on_digital(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test);
+
+ aconnector->base.force = DRM_FORCE_ON_DIGITAL;
+
+ KUNIT_EXPECT_EQ(test,
+ (int)amdgpu_dm_connector_detect(&aconnector->base, false),
+ (int)connector_status_connected);
+}
+
+/**
+ * dm_test_detect_force_off - Test DRM_FORCE_OFF reports disconnected
+ * @test: The KUnit test context
+ */
+static void dm_test_detect_force_off(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test);
+
+ aconnector->base.force = DRM_FORCE_OFF;
+
+ KUNIT_EXPECT_EQ(test,
+ (int)amdgpu_dm_connector_detect(&aconnector->base, false),
+ (int)connector_status_disconnected);
+}
+
+/**
+ * dm_test_detect_sink_present - Test a present dc_sink reports connected
+ * @test: The KUnit test context
+ */
+static void dm_test_detect_sink_present(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test);
+ struct dc_sink *sink;
+
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+
+ aconnector->base.force = DRM_FORCE_UNSPECIFIED;
+ aconnector->dc_sink = sink;
+
+ KUNIT_EXPECT_EQ(test,
+ (int)amdgpu_dm_connector_detect(&aconnector->base, false),
+ (int)connector_status_connected);
+}
+
+/**
+ * dm_test_detect_no_sink - Test a missing dc_sink reports disconnected
+ * @test: The KUnit test context
+ */
+static void dm_test_detect_no_sink(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_detect_connector(test);
+
+ aconnector->base.force = DRM_FORCE_UNSPECIFIED;
+ aconnector->dc_sink = NULL;
+
+ KUNIT_EXPECT_EQ(test,
+ (int)amdgpu_dm_connector_detect(&aconnector->base, false),
+ (int)connector_status_disconnected);
+}
+
+/* Tests for amdgpu_dm_connector_poll() */
+
+/**
+ * dm_test_poll_dac_load_returns_cached - Test the DAC load detection shortcut
+ * @test: The KUnit test context
+ *
+ * When the previous connection was established by analog DAC load detection and
+ * polling is not forced, the connector is not re-detected and its cached status
+ * is returned unchanged. The connector is embedded in an amdgpu_device so that
+ * drm_to_adev() resolves.
+ */
+static void dm_test_poll_dac_load_returns_cached(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+ struct dc_sink *local_sink;
+ struct drm_device *drm;
+ struct device *dev;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*adev),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
+ adev = drm_to_adev(drm);
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(drm, &aconnector->base,
+ &dm_test_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA, NULL), 0);
+
+ link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link);
+ local_sink = kunit_kzalloc(test, sizeof(*local_sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, local_sink);
+
+ link->local_sink = local_sink;
+ link->type = dc_connection_analog_load;
+ aconnector->dc_link = link;
+
+ /* The cached status that the shortcut must return unchanged. */
+ aconnector->base.status = connector_status_connected;
+
+ KUNIT_EXPECT_EQ(test,
+ (int)amdgpu_dm_connector_poll(aconnector, false),
+ (int)connector_status_connected);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -3974,6 +4123,14 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_create_stream_virtual_signal),
KUNIT_CASE(dm_test_create_stream_scaling_src),
KUNIT_CASE(dm_test_create_stream_existing_sink),
+ /* amdgpu_dm_connector_detect */
+ KUNIT_CASE(dm_test_detect_force_on),
+ KUNIT_CASE(dm_test_detect_force_on_digital),
+ KUNIT_CASE(dm_test_detect_force_off),
+ KUNIT_CASE(dm_test_detect_sink_present),
+ KUNIT_CASE(dm_test_detect_no_sink),
+ /* amdgpu_dm_connector_poll */
+ KUNIT_CASE(dm_test_poll_dac_load_returns_cached),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 18/70] drm/amd/display: Add register and unregister tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (16 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 17/70] drm/amd/display: Add detect and poll " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 19/70] drm/amd/display: Add destroy " Wayne Lin
` (51 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for amdgpu_dm_connector_late_register() and
amdgpu_dm_connector_unregister(): non-DP late register succeeds and
non-DP unregister is a no-op.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 6 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 2 +
.../tests/amdgpu_dm_connector_test.c | 70 +++++++++++++++++++
3 files changed, 76 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 94118f7f67c6..131387524aa9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1764,7 +1764,7 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
}
EXPORT_IF_KUNIT(amdgpu_dm_connector_atomic_get_property);
-static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
+STATIC_IFN_KUNIT void amdgpu_dm_connector_unregister(struct drm_connector *connector)
{
struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
@@ -1774,6 +1774,7 @@ static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
cec_notifier_conn_unregister(amdgpu_dm_connector->notifier);
drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux);
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_unregister);
static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
{
@@ -1877,7 +1878,7 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
}
EXPORT_IF_KUNIT(amdgpu_dm_connector_atomic_duplicate_state);
-static int
+STATIC_IFN_KUNIT int
amdgpu_dm_connector_late_register(struct drm_connector *connector)
{
struct amdgpu_dm_connector *amdgpu_dm_connector =
@@ -1907,6 +1908,7 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_late_register);
static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index 8c4ba5a90ade..f7057e83b4d5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -168,6 +168,8 @@ enum drm_connector_status
amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force);
enum drm_connector_status
amdgpu_dm_connector_detect(struct drm_connector *connector, bool force);
+void amdgpu_dm_connector_unregister(struct drm_connector *connector);
+int amdgpu_dm_connector_late_register(struct drm_connector *connector);
enum display_content_type
get_output_content_type(const struct drm_connector_state *connector_state);
bool adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index f38706e4d1c2..645347994734 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -3923,6 +3923,72 @@ static void dm_test_poll_dac_load_returns_cached(struct kunit *test)
(int)connector_status_connected);
}
+/* Tests for amdgpu_dm_connector_late_register() and _unregister() */
+
+/*
+ * Build an amdgpu_dm_connector embedded in an amdgpu_device so drm_to_adev()
+ * resolves. A VGA connector keeps amdgpu_dm_should_create_sysfs() false (sysfs
+ * and DP AUX branches skipped) and bl_idx == -1 turns backlight registration
+ * into a no-op, leaving the register/unregister bookkeeping safe to exercise.
+ */
+static struct amdgpu_dm_connector *dm_test_reg_connector(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_device *drm;
+ struct device *dev;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*adev),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(drm, &aconnector->base,
+ &dm_test_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA, NULL), 0);
+
+ aconnector->bl_idx = -1;
+
+ return aconnector;
+}
+
+/**
+ * dm_test_late_register_non_dp_succeeds - Test late_register on a plain connector
+ * @test: The KUnit test context
+ *
+ * With sysfs, backlight and DP AUX registration all skipped, late_register
+ * completes successfully.
+ */
+static void dm_test_late_register_non_dp_succeeds(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_reg_connector(test);
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_connector_late_register(&aconnector->base), 0);
+}
+
+/**
+ * dm_test_unregister_non_dp_noop - Test unregister tolerates an unregistered connector
+ * @test: The KUnit test context
+ *
+ * No sysfs group was created, the CEC notifier is NULL and the DP AUX channel
+ * was never registered, so unregister must be a safe no-op.
+ */
+static void dm_test_unregister_non_dp_noop(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector = dm_test_reg_connector(test);
+
+ KUNIT_EXPECT_FALSE(test, amdgpu_dm_should_create_sysfs(aconnector));
+
+ amdgpu_dm_connector_unregister(&aconnector->base);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -4131,6 +4197,10 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_detect_no_sink),
/* amdgpu_dm_connector_poll */
KUNIT_CASE(dm_test_poll_dac_load_returns_cached),
+ /* amdgpu_dm_connector_late_register */
+ KUNIT_CASE(dm_test_late_register_non_dp_succeeds),
+ /* amdgpu_dm_connector_unregister */
+ KUNIT_CASE(dm_test_unregister_non_dp_noop),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 19/70] drm/amd/display: Add destroy tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (17 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 18/70] drm/amd/display: Add register and unregister " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 20/70] drm/amd/display: Add encoder helper " Wayne Lin
` (50 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for amdgpu_dm_connector_destroy(): minimal
teardown plus releasing the dc_sink and dc_em_sink references.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 1 +
.../tests/amdgpu_dm_connector_test.c | 149 ++++++++++++++++++
drivers/gpu/drm/amd/display/dc/core/dc_sink.c | 1 +
4 files changed, 153 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 131387524aa9..d1c95199d598 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1776,7 +1776,7 @@ STATIC_IFN_KUNIT void amdgpu_dm_connector_unregister(struct drm_connector *conne
}
EXPORT_IF_KUNIT(amdgpu_dm_connector_unregister);
-static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
+STATIC_IFN_KUNIT void amdgpu_dm_connector_destroy(struct drm_connector *connector)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct amdgpu_device *adev = drm_to_adev(connector->dev);
@@ -1817,6 +1817,7 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
kfree(connector);
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_destroy);
void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index f7057e83b4d5..22423e878b64 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -170,6 +170,7 @@ enum drm_connector_status
amdgpu_dm_connector_detect(struct drm_connector *connector, bool force);
void amdgpu_dm_connector_unregister(struct drm_connector *connector);
int amdgpu_dm_connector_late_register(struct drm_connector *connector);
+void amdgpu_dm_connector_destroy(struct drm_connector *connector);
enum display_content_type
get_output_content_type(const struct drm_connector_state *connector_state);
bool adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 645347994734..efaf5730e893 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -3989,6 +3989,151 @@ static void dm_test_unregister_non_dp_noop(struct kunit *test)
amdgpu_dm_connector_unregister(&aconnector->base);
}
+/* Tests for amdgpu_dm_connector_destroy() */
+
+/*
+ * amdgpu_dm_connector_destroy() ends with drm_connector_cleanup() followed by
+ * kfree(connector), so the connector must be initialised with the unmanaged
+ * drm_connector_init() and allocated with kzalloc() (the function frees it, so
+ * kunit_kzalloc() would double free at teardown). It is embedded in an
+ * amdgpu_device so drm_to_adev() resolves and a dc_link carries a dc_context so
+ * dc_sink_create() works for the sink-release branches.
+ */
+struct dm_test_destroy_ctx {
+ struct drm_device *drm;
+ struct dc_context *dc_ctx;
+ struct dc_link *link;
+};
+
+static struct dm_test_destroy_ctx *dm_test_destroy_ctx_alloc(struct kunit *test)
+{
+ struct dm_test_destroy_ctx *ctx;
+ struct amdgpu_device *adev;
+ struct device *dev;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*adev),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ ctx->dc_ctx = kunit_kzalloc(test, sizeof(*ctx->dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->dc_ctx);
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->ctx = ctx->dc_ctx;
+
+ return ctx;
+}
+
+/*
+ * Allocate a connector the destroy path can free. Uses kzalloc() (not
+ * kunit_kzalloc) and the unmanaged drm_connector_init() because the function
+ * under test calls drm_connector_cleanup() + kfree(connector).
+ *
+ * drm_connector_init() requires funcs->destroy to be set, so a dedicated funcs
+ * table wires it to amdgpu_dm_connector_destroy() (the test invokes it
+ * directly; the connector is removed from the device before teardown).
+ */
+static const struct drm_connector_funcs dm_test_destroy_funcs = {
+ .reset = amdgpu_dm_connector_funcs_reset,
+ .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .destroy = amdgpu_dm_connector_destroy,
+};
+
+static struct amdgpu_dm_connector *
+dm_test_destroy_connector(struct kunit *test, struct drm_device *drm)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ KUNIT_ASSERT_EQ(test,
+ drm_connector_init(drm, &aconnector->base,
+ &dm_test_destroy_funcs,
+ DRM_MODE_CONNECTOR_VGA), 0);
+ aconnector->bl_idx = -1;
+
+ return aconnector;
+}
+
+/**
+ * dm_test_destroy_minimal - Test destroy tears down a bare connector
+ * @test: The KUnit test context
+ *
+ * With no MST, backlight, sinks or registered AUX/CEC, destroy must clean up
+ * and free the connector without crashing.
+ */
+static void dm_test_destroy_minimal(struct kunit *test)
+{
+ struct dm_test_destroy_ctx *ctx = dm_test_destroy_ctx_alloc(test);
+ struct amdgpu_dm_connector *aconnector =
+ dm_test_destroy_connector(test, ctx->drm);
+
+ amdgpu_dm_connector_destroy(&aconnector->base);
+}
+
+/**
+ * dm_test_destroy_releases_dc_sink - Test destroy releases the dc_sink
+ * @test: The KUnit test context
+ */
+static void dm_test_destroy_releases_dc_sink(struct kunit *test)
+{
+ struct dm_test_destroy_ctx *ctx = dm_test_destroy_ctx_alloc(test);
+ struct amdgpu_dm_connector *aconnector =
+ dm_test_destroy_connector(test, ctx->drm);
+ struct dc_sink_init_data sink_init = { 0 };
+ struct dc_sink *sink;
+
+ sink_init.link = ctx->link;
+ sink_init.sink_signal = SIGNAL_TYPE_VIRTUAL;
+ sink = dc_sink_create(&sink_init);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+
+ /* Extra reference so the sink survives destroy for inspection. */
+ dc_sink_retain(sink);
+ aconnector->dc_sink = sink;
+
+ amdgpu_dm_connector_destroy(&aconnector->base);
+
+ KUNIT_EXPECT_EQ(test, (int)kref_read(&sink->refcount), 1);
+ dc_sink_release(sink);
+}
+
+/**
+ * dm_test_destroy_releases_dc_em_sink - Test destroy releases the emulated sink
+ * @test: The KUnit test context
+ */
+static void dm_test_destroy_releases_dc_em_sink(struct kunit *test)
+{
+ struct dm_test_destroy_ctx *ctx = dm_test_destroy_ctx_alloc(test);
+ struct amdgpu_dm_connector *aconnector =
+ dm_test_destroy_connector(test, ctx->drm);
+ struct dc_sink_init_data sink_init = { 0 };
+ struct dc_sink *sink;
+
+ sink_init.link = ctx->link;
+ sink_init.sink_signal = SIGNAL_TYPE_VIRTUAL;
+ sink = dc_sink_create(&sink_init);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+
+ dc_sink_retain(sink);
+ aconnector->dc_em_sink = sink;
+
+ amdgpu_dm_connector_destroy(&aconnector->base);
+
+ KUNIT_EXPECT_EQ(test, (int)kref_read(&sink->refcount), 1);
+ dc_sink_release(sink);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -4201,6 +4346,10 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_late_register_non_dp_succeeds),
/* amdgpu_dm_connector_unregister */
KUNIT_CASE(dm_test_unregister_non_dp_noop),
+ /* amdgpu_dm_connector_destroy */
+ KUNIT_CASE(dm_test_destroy_minimal),
+ KUNIT_CASE(dm_test_destroy_releases_dc_sink),
+ KUNIT_CASE(dm_test_destroy_releases_dc_em_sink),
{}
};
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c
index 436d033361ab..79b9738e9c68 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c
@@ -61,6 +61,7 @@ void dc_sink_retain(struct dc_sink *sink)
{
kref_get(&sink->refcount);
}
+EXPORT_IF_KUNIT(dc_sink_retain);
static void dc_sink_free(struct kref *kref)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 20/70] drm/amd/display: Add encoder helper tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (18 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 19/70] drm/amd/display: Add destroy " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 21/70] drm/amd/display: Add EDID management " Wayne Lin
` (49 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for the encoder helpers dm_encoder_helper_disable()
and dm_encoder_helper_atomic_check(): disable no-op, eDP native keeps
scaling, LVDS non-native enables scaling, and the non-MST zero return.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 6 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 4 +
.../tests/amdgpu_dm_connector_test.c | 139 ++++++++++++++++++
3 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index d1c95199d598..a4648acde71b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -90,11 +90,12 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
.destroy = amdgpu_dm_encoder_destroy,
};
-static void dm_encoder_helper_disable(struct drm_encoder *encoder)
+STATIC_IFN_KUNIT void dm_encoder_helper_disable(struct drm_encoder *encoder)
{
}
+EXPORT_IF_KUNIT(dm_encoder_helper_disable);
-static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
+STATIC_IFN_KUNIT int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
@@ -164,6 +165,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
}
return 0;
}
+EXPORT_IF_KUNIT(dm_encoder_helper_atomic_check);
const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
.disable = dm_encoder_helper_disable,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index 22423e878b64..a5fff31b23bf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -146,6 +146,10 @@ int amdgpu_dm_encoder_init(struct drm_device *dev,
uint32_t link_index);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+void dm_encoder_helper_disable(struct drm_encoder *encoder);
+int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state);
enum drm_mode_subconnector get_subconnector_type(struct dc_link *link);
void update_subconnector_property(struct amdgpu_dm_connector *aconnector);
void amdgpu_dm_fbc_init(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index efaf5730e893..441180d427c9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -4134,6 +4134,139 @@ static void dm_test_destroy_releases_dc_em_sink(struct kunit *test)
dc_sink_release(sink);
}
+/* Tests for dm_encoder_helper_disable() */
+
+/**
+ * dm_test_encoder_disable_noop - Test the disable hook is a no-op
+ * @test: The KUnit test context
+ *
+ * dm_encoder_helper_disable() has an empty body; calling it must neither touch
+ * the encoder nor crash.
+ */
+static void dm_test_encoder_disable_noop(struct kunit *test)
+{
+ struct drm_encoder *encoder;
+
+ encoder = kunit_kzalloc(test, sizeof(*encoder), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, encoder);
+
+ dm_encoder_helper_disable(encoder);
+}
+
+/* Tests for dm_encoder_helper_atomic_check() */
+
+/*
+ * dm_encoder_helper_atomic_check() reads back through to_amdgpu_encoder(),
+ * to_amdgpu_dm_connector() and to_dm_connector_state(), so the encoder,
+ * connector and connector-state are stacked in their containers and wired
+ * together through conn_state->connector.
+ */
+struct dm_test_atomic_check_ctx {
+ struct drm_device *drm;
+ struct amdgpu_encoder *aenc;
+ struct amdgpu_dm_connector *aconnector;
+ struct dm_connector_state *dm_state;
+ struct drm_crtc_state *crtc_state;
+};
+
+static struct dm_test_atomic_check_ctx *
+dm_test_atomic_check_ctx_alloc(struct kunit *test, int connector_type)
+{
+ struct dm_test_atomic_check_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->drm = dm_test_alloc_drm(test);
+
+ ctx->aenc = kunit_kzalloc(test, sizeof(*ctx->aenc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aenc);
+ ctx->aenc->base.dev = ctx->drm;
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ ctx->aconnector->base.connector_type = connector_type;
+
+ ctx->dm_state = kunit_kzalloc(test, sizeof(*ctx->dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->dm_state);
+ ctx->dm_state->base.connector = &ctx->aconnector->base;
+
+ ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+
+ return ctx;
+}
+
+/**
+ * dm_test_atomic_check_edp_native_keeps_scaling - Test native eDP mode is left alone
+ * @test: The KUnit test context
+ *
+ * On an eDP connector whose adjusted mode matches the panel's native mode,
+ * drm_crtc_helper_mode_valid_fixed() returns MODE_OK so scaling is untouched.
+ */
+static void dm_test_atomic_check_edp_native_keeps_scaling(struct kunit *test)
+{
+ struct dm_test_atomic_check_ctx *ctx =
+ dm_test_atomic_check_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+
+ ctx->aenc->native_mode.hdisplay = 1920;
+ ctx->aenc->native_mode.vdisplay = 1080;
+ ctx->crtc_state->adjusted_mode.hdisplay = 1920;
+ ctx->crtc_state->adjusted_mode.vdisplay = 1080;
+ ctx->dm_state->scaling = RMX_OFF;
+
+ KUNIT_EXPECT_EQ(test,
+ dm_encoder_helper_atomic_check(&ctx->aenc->base,
+ ctx->crtc_state,
+ &ctx->dm_state->base), 0);
+ KUNIT_EXPECT_EQ(test, (int)ctx->dm_state->scaling, (int)RMX_OFF);
+}
+
+/**
+ * dm_test_atomic_check_lvds_non_native_enables_scaling - Test non-native LVDS turns on scaling
+ * @test: The KUnit test context
+ *
+ * On an LVDS connector whose adjusted mode differs from the native mode and is
+ * currently RMX_OFF, the check enables RMX_ASPECT scaling and still returns 0.
+ */
+static void dm_test_atomic_check_lvds_non_native_enables_scaling(struct kunit *test)
+{
+ struct dm_test_atomic_check_ctx *ctx =
+ dm_test_atomic_check_ctx_alloc(test, DRM_MODE_CONNECTOR_LVDS);
+
+ ctx->aenc->native_mode.hdisplay = 1920;
+ ctx->aenc->native_mode.vdisplay = 1080;
+ ctx->crtc_state->adjusted_mode.hdisplay = 1280;
+ ctx->crtc_state->adjusted_mode.vdisplay = 720;
+ ctx->dm_state->scaling = RMX_OFF;
+
+ KUNIT_EXPECT_EQ(test,
+ dm_encoder_helper_atomic_check(&ctx->aenc->base,
+ ctx->crtc_state,
+ &ctx->dm_state->base), 0);
+ KUNIT_EXPECT_EQ(test, (int)ctx->dm_state->scaling, (int)RMX_ASPECT);
+}
+
+/**
+ * dm_test_atomic_check_non_mst_returns_zero - Test non-MST connectors short-circuit
+ * @test: The KUnit test context
+ *
+ * A non-eDP/LVDS connector with no MST output port hits the early ``return 0``
+ * before any topology state is touched.
+ */
+static void dm_test_atomic_check_non_mst_returns_zero(struct kunit *test)
+{
+ struct dm_test_atomic_check_ctx *ctx =
+ dm_test_atomic_check_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ ctx->aconnector->mst_output_port = NULL;
+
+ KUNIT_EXPECT_EQ(test,
+ dm_encoder_helper_atomic_check(&ctx->aenc->base,
+ ctx->crtc_state,
+ &ctx->dm_state->base), 0);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -4350,6 +4483,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_destroy_minimal),
KUNIT_CASE(dm_test_destroy_releases_dc_sink),
KUNIT_CASE(dm_test_destroy_releases_dc_em_sink),
+ /* dm_encoder_helper_disable */
+ KUNIT_CASE(dm_test_encoder_disable_noop),
+ /* dm_encoder_helper_atomic_check */
+ KUNIT_CASE(dm_test_atomic_check_edp_native_keeps_scaling),
+ KUNIT_CASE(dm_test_atomic_check_lvds_non_native_enables_scaling),
+ KUNIT_CASE(dm_test_atomic_check_non_mst_returns_zero),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 21/70] drm/amd/display: Add EDID management tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (19 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 20/70] drm/amd/display: Add encoder helper " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 22/70] drm/amd/display: fix debug flags assignment in dmub_replay.c Wayne Lin
` (48 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for hdmi_cec_unset_edid(), create_eml_sink() and
handle_edid_mgmt(): unset edid with no notifier, eml sink with no
edid, and DP vs non-DP edid management link caps handling.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 9 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 3 +
.../tests/amdgpu_dm_connector_test.c | 119 ++++++++++++++++++
3 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index a4648acde71b..6d358cb84961 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -334,7 +334,7 @@ int amdgpu_dm_detect_mst_link_for_all_connectors(struct drm_device *dev)
}
EXPORT_IF_KUNIT(amdgpu_dm_detect_mst_link_for_all_connectors);
-static void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector)
+STATIC_IFN_KUNIT void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector)
{
struct cec_notifier *n = aconnector->notifier;
@@ -343,6 +343,7 @@ static void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector)
cec_notifier_phys_addr_invalidate(n);
}
+EXPORT_IF_KUNIT(hdmi_cec_unset_edid);
void amdgpu_dm_hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector)
{
@@ -1969,7 +1970,7 @@ static int get_modes(struct drm_connector *connector)
return amdgpu_dm_connector_get_modes(connector);
}
-static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
+STATIC_IFN_KUNIT void create_eml_sink(struct amdgpu_dm_connector *aconnector)
{
struct drm_connector *connector = &aconnector->base;
struct dc_link *dc_link = aconnector->dc_link;
@@ -2014,8 +2015,9 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
dc_sink_retain(aconnector->dc_sink);
}
}
+EXPORT_IF_KUNIT(create_eml_sink);
-static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
+STATIC_IFN_KUNIT void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
{
struct dc_link *link = (struct dc_link *)aconnector->dc_link;
@@ -2030,6 +2032,7 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
create_eml_sink(aconnector);
}
+EXPORT_IF_KUNIT(handle_edid_mgmt);
static enum dc_status dm_validate_stream_and_context(struct dc *dc,
struct dc_stream_state *stream)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index a5fff31b23bf..f7ec4b906e13 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -146,6 +146,9 @@ int amdgpu_dm_encoder_init(struct drm_device *dev,
uint32_t link_index);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector);
+void create_eml_sink(struct amdgpu_dm_connector *aconnector);
+void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector);
void dm_encoder_helper_disable(struct drm_encoder *encoder);
int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 441180d427c9..59f2f8235486 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -4267,6 +4267,118 @@ static void dm_test_atomic_check_non_mst_returns_zero(struct kunit *test)
&ctx->dm_state->base), 0);
}
+/* Tests for hdmi_cec_unset_edid() */
+
+/**
+ * dm_test_hdmi_cec_unset_edid_no_notifier - Test the no-notifier no-op path
+ * @test: The KUnit test context
+ *
+ * With aconnector->notifier NULL the function returns early and must not crash.
+ */
+static void dm_test_hdmi_cec_unset_edid_no_notifier(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ hdmi_cec_unset_edid(aconnector);
+}
+
+/* Tests for create_eml_sink() and handle_edid_mgmt() */
+
+/*
+ * create_eml_sink() reads EDID off the connector's DDC. Forcing the connector
+ * DRM_FORCE_OFF makes drm_edid_read_ddc() return NULL before touching any i2c
+ * adapter, exercising the "no EDID" branch without real hardware. aux_mode is
+ * set so the embedded DP AUX ddc is selected (no i2c adapter pointer needed).
+ */
+struct dm_test_edid_ctx {
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+};
+
+static struct dm_test_edid_ctx *
+dm_test_edid_ctx_alloc(struct kunit *test, int connector_type)
+{
+ struct dm_test_edid_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->drm = dm_test_alloc_drm(test);
+ ctx->aconnector = dm_test_add_connector(test, ctx->drm, connector_type);
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->aux_mode = true;
+ ctx->aconnector->dc_link = ctx->link;
+
+ ctx->aconnector->base.force = DRM_FORCE_OFF;
+
+ return ctx;
+}
+
+/**
+ * dm_test_create_eml_sink_no_edid - Test the no-EDID branch creates no sink
+ * @test: The KUnit test context
+ *
+ * When no EDID can be read the function logs an error and returns without
+ * allocating an emulated sink.
+ */
+static void dm_test_create_eml_sink_no_edid(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+
+ create_eml_sink(ctx->aconnector);
+
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->dc_em_sink);
+}
+
+/**
+ * dm_test_handle_edid_mgmt_dp_sets_link_caps - Test DP seeds verified link caps
+ * @test: The KUnit test context
+ *
+ * For a DisplayPort link the function primes verified_link_cap before reading
+ * EDID so a headless force-on connector can still modeset.
+ */
+static void dm_test_handle_edid_mgmt_dp_sets_link_caps(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+
+ ctx->link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ handle_edid_mgmt(ctx->aconnector);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->link->verified_link_cap.lane_count,
+ (int)LANE_COUNT_FOUR);
+ KUNIT_EXPECT_EQ(test, (int)ctx->link->verified_link_cap.link_rate,
+ (int)LINK_RATE_HIGH2);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->dc_em_sink);
+}
+
+/**
+ * dm_test_handle_edid_mgmt_non_dp_leaves_caps - Test non-DP links keep zeroed caps
+ * @test: The KUnit test context
+ *
+ * A non-DisplayPort link skips the verified_link_cap seeding entirely.
+ */
+static void dm_test_handle_edid_mgmt_non_dp_leaves_caps(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ ctx->link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
+
+ handle_edid_mgmt(ctx->aconnector);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->link->verified_link_cap.lane_count, 0);
+ KUNIT_EXPECT_EQ(test, (int)ctx->link->verified_link_cap.link_rate, 0);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -4489,6 +4601,13 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_atomic_check_edp_native_keeps_scaling),
KUNIT_CASE(dm_test_atomic_check_lvds_non_native_enables_scaling),
KUNIT_CASE(dm_test_atomic_check_non_mst_returns_zero),
+ /* hdmi_cec_unset_edid */
+ KUNIT_CASE(dm_test_hdmi_cec_unset_edid_no_notifier),
+ /* create_eml_sink */
+ KUNIT_CASE(dm_test_create_eml_sink_no_edid),
+ /* handle_edid_mgmt */
+ KUNIT_CASE(dm_test_handle_edid_mgmt_dp_sets_link_caps),
+ KUNIT_CASE(dm_test_handle_edid_mgmt_non_dp_leaves_caps),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 22/70] drm/amd/display: fix debug flags assignment in dmub_replay.c
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (20 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 21/70] drm/amd/display: Add EDID management " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 23/70] drm/amd/display: Add DWB validation support to DML2.1 wrapper Wayne Lin
` (47 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Robin Chen, ChunTao Tso
From: Robin Chen <robin.chen@amd.com>
[WHY]
Fix incorrect casting of debug flags to uint16_t, which could
truncate the value.
Reviewed-by: ChunTao Tso <chuntao.tso@amd.com>
Signed-off-by: Robin Chen <robin.chen@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
index 6d19da2230ae..0f66164a3004 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
@@ -165,7 +165,7 @@ static bool dmub_replay_copy_settings(struct dmub_replay *dmub,
// Misc
copy_settings_data->line_time_in_ns = (uint16_t)replay_context->line_time_in_ns;
copy_settings_data->panel_inst = (uint16_t)panel_inst;
- copy_settings_data->debug.u32All = (uint16_t)link->replay_settings.config.debug_flags;
+ copy_settings_data->debug.u32All = link->replay_settings.config.debug_flags;
copy_settings_data->pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line;
copy_settings_data->max_deviation_line = (uint16_t)link->dpcd_caps.pr_info.max_deviation_line;
copy_settings_data->smu_optimizations_en = link->replay_settings.replay_smu_opt_enable;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 23/70] drm/amd/display: Add DWB validation support to DML2.1 wrapper
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (21 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 22/70] drm/amd/display: fix debug flags assignment in dmub_replay.c Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 24/70] drm/amd/display: Split DPMS ON into parts Wayne Lin
` (46 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dillon Varone, Austin Zheng
From: Dillon Varone <Dillon.Varone@amd.com>
[WHY&HOW]
DML2.1 wrapper was lacking translation for DWB. This change adds the
necessary translation for DWB validation and programming support.
Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../dml2_0/dml21/dml21_translation_helper.c | 56 +++++++++++++++
.../amd/display/dc/dml2_0/dml21/dml21_utils.c | 17 +++++
.../amd/display/dc/dml2_0/dml21/dml21_utils.h | 5 ++
.../dc/dml2_0/dml21/dml21_wrapper_fpu.c | 10 +++
.../dc/dml2_0/dml21/inc/dml_top_types.h | 2 +
.../dml21/src/dml2_core/dml2_core_dcn4.c | 34 +++++++++-
.../src/dml2_core/dml2_core_dcn4_calcs.c | 68 ++++++++++++++++---
.../src/dml2_core/dml2_core_dcn4_calcs.h | 2 +
.../dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c | 21 ++++++
9 files changed, 206 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
index 51260369cd8a..a76dcde1efbf 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
@@ -267,6 +267,61 @@ static void populate_dml21_output_config_from_stream_state(struct dml2_link_outp
// output->validate_output
}
+static void populate_dml21_writeback_config_from_stream_state(struct dml2_writeback_cfg *writeback,
+ const struct dc_stream_state *stream)
+{
+ if (stream->num_wb_info > 0) {
+ writeback->active_writebacks_per_stream = stream->num_wb_info <= DML2_MAX_WRITEBACK ?
+ stream->num_wb_info : DML2_MAX_WRITEBACK;
+
+ ASSERT(stream->num_wb_info <= DML2_MAX_WRITEBACK);
+
+ for (unsigned int wb_index = 0; wb_index < stream->num_wb_info; wb_index++) {
+ const struct dc_writeback_info *dc_wb_info = &stream->writeback_info[wb_index];
+ struct dml2_writeback_info *wb_info = &writeback->writeback_stream[wb_index];
+
+ switch (dc_wb_info->dwb_params.cnv_params.fc_out_format) {
+ case DWB_OUT_FORMAT_64BPP_ARGB:
+ case DWB_OUT_FORMAT_64BPP_RGBA:
+ wb_info->pixel_format = dml2_444_64;
+ break;
+ case DWB_OUT_FORMAT_32BPP_ARGB:
+ case DWB_OUT_FORMAT_32BPP_RGBA:
+ default:
+ wb_info->pixel_format = dml2_444_32;
+ break;
+ }
+
+ wb_info->input_width = dc_wb_info->dwb_params.cnv_params.crop_en ?
+ dc_wb_info->dwb_params.cnv_params.crop_width :
+ dc_wb_info->dwb_params.cnv_params.src_width;
+ wb_info->input_height = dc_wb_info->dwb_params.cnv_params.crop_en ?
+ dc_wb_info->dwb_params.cnv_params.crop_height :
+ dc_wb_info->dwb_params.cnv_params.src_height;
+ wb_info->output_width = dc_wb_info->dwb_params.dest_width;
+ wb_info->output_height = dc_wb_info->dwb_params.dest_height;
+ wb_info->v_taps = dc_wb_info->dwb_params.scaler_taps.v_taps > 0 ?
+ dc_wb_info->dwb_params.scaler_taps.v_taps : 1;
+ wb_info->h_taps = dc_wb_info->dwb_params.scaler_taps.h_taps > 0 ?
+ dc_wb_info->dwb_params.scaler_taps.h_taps : 1;
+ wb_info->v_taps_chroma = dc_wb_info->dwb_params.scaler_taps.v_taps_c > 0 ?
+ dc_wb_info->dwb_params.scaler_taps.v_taps_c : 1;
+ wb_info->h_taps_chroma = dc_wb_info->dwb_params.scaler_taps.h_taps_c > 0 ?
+ dc_wb_info->dwb_params.scaler_taps.h_taps_c : 1;
+ wb_info->h_ratio = dc_wb_info->dwb_params.cnv_params.crop_en ?
+ (double)dc_wb_info->dwb_params.cnv_params.crop_width /
+ (double)dc_wb_info->dwb_params.dest_width :
+ (double)dc_wb_info->dwb_params.cnv_params.src_width /
+ (double)dc_wb_info->dwb_params.dest_width;
+ wb_info->v_ratio = dc_wb_info->dwb_params.cnv_params.crop_en ?
+ (double)dc_wb_info->dwb_params.cnv_params.crop_height /
+ (double)dc_wb_info->dwb_params.dest_height :
+ (double)dc_wb_info->dwb_params.cnv_params.src_height /
+ (double)dc_wb_info->dwb_params.dest_height;
+ }
+ }
+}
+
static void populate_dml21_stream_overrides_from_stream_state(
struct dml2_stream_parameters *stream_desc,
struct dc_stream_state *stream,
@@ -826,6 +881,7 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s
ASSERT(disp_cfg_stream_location >= 0 && disp_cfg_stream_location < __DML2_WRAPPER_MAX_STREAMS_PLANES__);
populate_dml21_timing_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, context->streams[stream_index], otg_master_pipe, dml_ctx);
populate_dml21_output_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].output, context->streams[stream_index], otg_master_pipe);
+ populate_dml21_writeback_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].writeback, context->streams[stream_index]);
populate_dml21_stream_overrides_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location], context->streams[stream_index], &context->stream_status[stream_index]);
dml_dispcfg->stream_descriptors[disp_cfg_stream_location].overrides.hw.twait_budgeting.fclk_pstate = dml2_twait_budgeting_setting_if_needed;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c
index 835fece1d46a..16e1315da2fa 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.c
@@ -532,3 +532,20 @@ bool dml21_is_plane1_enabled(enum dml2_source_format_class source_format)
{
return source_format >= dml2_420_8 && source_format <= dml2_rgbe_alpha;
}
+
+void dml21_program_dc_mcif_arb_params(struct dml2_context *dml_ctx,
+ struct dc_state *context,
+ struct dml2_per_stream_programming *stream_prog,
+ unsigned int wb_index,
+ unsigned int dwb_inst)
+{
+ /* DC struct contains global reg for every WB instance */
+ memcpy(&context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_inst].dcn4x.global_regs,
+ &dml_ctx->v21.mode_programming.programming->mcif_global_regs,
+ sizeof(struct dml2_mcif_global_register_set));
+
+ /* copy per-DWB pipe registers */
+ memcpy(&context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_inst].dcn4x.inst_regs,
+ stream_prog->mcif_regs[wb_index],
+ sizeof(struct dml2_mcif_per_pipe_register_set));
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.h
index bff945a4ab3a..7312c33143c6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_utils.h
@@ -48,4 +48,9 @@ void dml21_build_fams2_programming(const struct dc *dc,
struct dc_state *context,
struct dml2_context *dml_ctx);
bool dml21_is_plane1_enabled(enum dml2_source_format_class source_format);
+void dml21_program_dc_mcif_arb_params(struct dml2_context *dml_ctx,
+ struct dc_state *context,
+ struct dml2_per_stream_programming *stream_prog,
+ unsigned int wb_index,
+ unsigned int dwb_inst);
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
index 11fc0b1cd152..a975d36ce15d 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
@@ -60,6 +60,7 @@ static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_sta
struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
int num_pipes;
unsigned int dml_phantom_prog_idx;
+ unsigned int stream_wb_idx;
context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
@@ -102,6 +103,15 @@ static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_sta
}
}
+ /* program WB */
+ for (stream_wb_idx = 0; stream_wb_idx < stream_prog->stream_descriptor->writeback.active_writebacks_per_stream; stream_wb_idx++) {
+ dml21_program_dc_mcif_arb_params(in_ctx,
+ context,
+ stream_prog,
+ stream_wb_idx,
+ dc_main_pipes[0]->stream->writeback_info[stream_wb_idx].dwb_pipe_inst);
+ }
+
/* copy per plane mcache allocation */
memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation));
if (pln_prog->phantom_plane.valid) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index bd0d7549d20f..f00ca2983ff5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -279,6 +279,8 @@ struct dml2_per_stream_programming {
enum dml2_pstate_method uclk_pstate_method;
+ struct dml2_mcif_per_pipe_register_set *mcif_regs[DML2_MAX_WRITEBACK];
+
struct {
bool enabled;
struct dml2_stream_parameters descriptor;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c
index c983869e0fa3..727b01ca18bf 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.c
@@ -368,9 +368,10 @@ static void expand_implict_subvp(const struct display_configuation_with_meta *di
static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance *core, const struct display_configuation_with_meta *display_cfg,
const struct dml2_display_cfg *svp_expanded_display_cfg, struct dml2_display_cfg_programming *programming, struct dml2_core_scratch *scratch)
{
- unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index, mcache_index;
+ unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index, mcache_index, dwb_index;
unsigned int total_main_mcaches_required = 0;
int total_pipe_regs_copied = 0;
+ int total_dwb_regs_copied = 0;
int dml_internal_pipe_index = 0;
const struct dml2_plane_parameters *main_plane;
const struct dml2_plane_parameters *phantom_plane;
@@ -386,6 +387,8 @@ static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_in
// display config
dml2_core_calcs_get_watermarks(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.wm_regs[0]);
+ dml2_core_calcs_get_mcif_arb_params(&core->clean_me_up.mode_lib, &programming->mcif_global_regs);
+
// Check if FAMS2 is required
if (display_cfg->stage3.performed && display_cfg->stage3.success) {
programming->fams2_required = display_cfg->stage3.fams2_required;
@@ -470,6 +473,19 @@ static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_in
programming->stream_programming[main_plane->stream_index].uclk_pstate_method,
plane_index);
+ /* populate DWB */
+ for (dwb_index = 0; dwb_index < svp_expanded_display_cfg->stream_descriptors[main_plane->stream_index].writeback.active_writebacks_per_stream; dwb_index++) {
+ programming->stream_programming[main_plane->stream_index].mcif_regs[dwb_index] = &programming->mcif_regs[total_dwb_regs_copied];
+ memset(programming->stream_programming[main_plane->stream_index].mcif_regs[dwb_index], 0, sizeof(struct dml2_mcif_per_pipe_register_set));
+ total_dwb_regs_copied++;
+
+ dml2_core_calcs_get_per_dwb_params(svp_expanded_display_cfg,
+ &core->clean_me_up.mode_lib,
+ programming->stream_programming[main_plane->stream_index].mcif_regs[dwb_index],
+ main_plane->stream_index,
+ dwb_index);
+ }
+
stream_already_populated_mask |= (0x1 << main_plane->stream_index);
}
dml_internal_pipe_index++;
@@ -661,10 +677,12 @@ bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out
unsigned int pipe_offset;
int dml_internal_pipe_index;
int total_pipe_regs_copied = 0;
+ int total_dwb_regs_copied = 0;
int stream_already_populated_mask = 0;
int main_stream_index;
unsigned int plane_index;
+ unsigned int dwb_index;
expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch);
@@ -688,6 +706,8 @@ bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out
dml2_core_calcs_get_arb_params(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.arb_regs);
dml2_core_calcs_get_watermarks(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.wm_regs[0]);
+ dml2_core_calcs_get_mcif_arb_params(&core->clean_me_up.mode_lib, &in_out->programming->mcif_global_regs);
+
dml_internal_pipe_index = 0;
for (plane_index = 0; plane_index < in_out->programming->display_config.num_planes; plane_index++) {
@@ -733,6 +753,18 @@ bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out
in_out->programming->stream_programming[main_stream_index].num_odms_required = in_out->cfg_support_info->stream_support_info[main_stream_index].odms_used;
dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &in_out->programming->stream_programming[main_stream_index], dml_internal_pipe_index);
+ for (dwb_index = 0; dwb_index < l->svp_expanded_display_cfg.stream_descriptors[main_stream_index].writeback.active_writebacks_per_stream; dwb_index++) {
+ in_out->programming->stream_programming[main_stream_index].mcif_regs[dwb_index] = &in_out->programming->mcif_regs[total_dwb_regs_copied];
+ memset(in_out->programming->stream_programming[main_stream_index].mcif_regs[dwb_index], 0, sizeof(struct dml2_mcif_per_pipe_register_set));
+ total_dwb_regs_copied++;
+
+ dml2_core_calcs_get_per_dwb_params(&l->svp_expanded_display_cfg,
+ &core->clean_me_up.mode_lib,
+ in_out->programming->stream_programming[main_stream_index].mcif_regs[dwb_index],
+ main_stream_index,
+ dwb_index);
+ }
+
stream_already_populated_mask |= (0x1 << main_stream_index);
}
dml_internal_pipe_index++;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
index b667fc9ad75f..fa78016b32fc 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
@@ -6741,6 +6741,25 @@ static void CalculateFlipSchedule(
#endif
}
+static double calculate_writeback_latency_hiding_us(
+ const struct dml2_display_cfg *display_cfg,
+ unsigned int writeback_buffer_size_bytes,
+ unsigned int stream_index,
+ unsigned int dwb_index)
+{
+ double line_time_us = (double)display_cfg->stream_descriptors[stream_index].timing.h_total /
+ (double)display_cfg->stream_descriptors[stream_index].timing.pixel_clock_khz / 1000.0;
+
+ double writeback_latency_hiding_us = (double)writeback_buffer_size_bytes /
+ ((double)display_cfg->stream_descriptors[stream_index].writeback.writeback_stream[dwb_index].output_height *
+ (double)display_cfg->stream_descriptors[stream_index].writeback.writeback_stream[dwb_index].output_width /
+ ((double)display_cfg->stream_descriptors[stream_index].writeback.writeback_stream[dwb_index].input_height *
+ line_time_us) * 4.0);
+
+ return display_cfg->stream_descriptors[stream_index].writeback.writeback_stream[dwb_index].pixel_format == dml2_444_64 ?
+ writeback_latency_hiding_us / 2 : writeback_latency_hiding_us;
+}
+
static void CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_params *p)
@@ -6905,13 +6924,10 @@ static void CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport(
p->VActiveLatencyHidingUs[k] = s->ActiveClockChangeLatencyHiding;
if (p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.active_writebacks_per_stream > 0) {
- s->WritebackLatencyHiding = (double)p->WritebackInterfaceBufferSize * 1024.0
- / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[0].output_height
- * (double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[0].output_width
- / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[0].input_height * (double)h_total / pixel_clock_mhz) * 4.0);
- if (p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[0].pixel_format == dml2_444_64) {
- s->WritebackLatencyHiding = s->WritebackLatencyHiding / 2;
- }
+ s->WritebackLatencyHiding = calculate_writeback_latency_hiding_us(p->display_cfg,
+ p->WritebackInterfaceBufferSize * 1024,
+ p->display_cfg->plane_descriptors[k].stream_index,
+ 0);
s->WritebackDRAMClockChangeLatencyMargin = s->WritebackLatencyHiding - p->Watermark->WritebackDRAMClockChangeWatermark;
s->WritebackFCLKChangeLatencyMargin = s->WritebackLatencyHiding - p->Watermark->WritebackFCLKChangeWatermark;
@@ -8693,6 +8709,7 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
s->TotalNumberOfActiveWriteback = 0;
memset(s->stream_visited, 0, DML2_MAX_PLANES * sizeof(bool));
+ mode_lib->ms.support.EnoughWritebackUnits = true;
for (k = 0; k < mode_lib->ms.num_active_planes; ++k) {
if (!dml_is_phantom_pipe(&display_cfg->plane_descriptors[k])) {
if (!s->stream_visited[display_cfg->plane_descriptors[k].stream_index]) {
@@ -8701,6 +8718,10 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
if (display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].writeback.active_writebacks_per_stream > 0)
s->TotalNumberOfActiveWriteback = s->TotalNumberOfActiveWriteback + 1;
+ /* >1 writeback per stream is currently not supported */
+ if (display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].writeback.active_writebacks_per_stream > 1)
+ mode_lib->ms.support.EnoughWritebackUnits = false;
+
s->TotalNumberOfActiveOTG = s->TotalNumberOfActiveOTG + 1;
if (display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].output.output_encoder == dml2_hdmifrl)
s->TotalNumberOfActiveHDMIFRL = s->TotalNumberOfActiveHDMIFRL + 1;
@@ -8716,10 +8737,10 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
}
/* Writeback Mode Support Check */
- mode_lib->ms.support.EnoughWritebackUnits = 1;
if (s->TotalNumberOfActiveWriteback > (unsigned int)mode_lib->ip.max_num_wb) {
mode_lib->ms.support.EnoughWritebackUnits = false;
}
+
mode_lib->ms.support.NumberOfOTGSupport = (s->TotalNumberOfActiveOTG <= (unsigned int)mode_lib->ip.max_num_otg);
mode_lib->ms.support.NumberOfHDMIFRLSupport = (s->TotalNumberOfActiveHDMIFRL <= (unsigned int)mode_lib->ip.max_num_hdmi_frl_outputs);
mode_lib->ms.support.NumberOfDP2p0Support = (s->TotalNumberOfActiveDP2p0 <= (unsigned int)mode_lib->ip.max_num_dp2p0_streams && s->TotalNumberOfActiveDP2p0Outputs <= (unsigned int)mode_lib->ip.max_num_dp2p0_outputs);
@@ -12831,6 +12852,14 @@ void dml2_core_calcs_get_arb_params(const struct dml2_display_cfg *display_cfg,
rq_dlg_get_arb_params(display_cfg, mode_lib, out);
}
+void dml2_core_calcs_get_mcif_arb_params(const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_mcif_global_register_set *out)
+{
+ out->wm_regs[0].fclk_pstate = (unsigned int)(mode_lib->mp.Watermark.WritebackFCLKChangeWatermark * 1000.0);
+ out->wm_regs[0].uclk_pstate = (unsigned int)(mode_lib->mp.Watermark.WritebackDRAMClockChangeWatermark * 1000.0);
+ out->wm_regs[0].urgent = (unsigned int)(mode_lib->mp.Watermark.WritebackUrgentWatermark * 1000.0);
+ out->wm_regs[0].temp_read_or_ppt = (unsigned int)(mode_lib->mp.Watermark.writeback_temp_read_or_ppt_watermark_us * 1000.0);
+}
+
void dml2_core_calcs_get_pipe_regs(const struct dml2_display_cfg *display_cfg,
struct dml2_core_internal_display_mode_lib *mode_lib,
struct dml2_dchub_per_pipe_register_set *out, int pipe_index)
@@ -12854,6 +12883,29 @@ void dml2_core_calcs_get_stream_programming(const struct dml2_core_internal_disp
dml2_core_calcs_get_global_sync_programming(mode_lib, &out->global_sync, pipe_index);
}
+void dml2_core_calcs_get_per_dwb_params(const struct dml2_display_cfg *display_cfg,
+ const struct dml2_core_internal_display_mode_lib *mode_lib,
+ struct dml2_mcif_per_pipe_register_set *out,
+ int stream_index,
+ int dwb_index)
+{
+ double writeback_latency_hiding_us = calculate_writeback_latency_hiding_us(display_cfg,
+ mode_lib->ip.writeback_interface_buffer_size_kbytes * 1024,
+ stream_index,
+ dwb_index);
+
+ out->max_scaled_time_ns = (unsigned int)math_max2(
+ (writeback_latency_hiding_us - mode_lib->mp.Watermark.WritebackUrgentWatermark) * 1000.0,
+ 0.0);
+
+ /* 1024ps units in U6.6 format */
+ out->time_per_pixel = (unsigned int)((1000000.0 * math_pow(2, 6)) /
+ (double)display_cfg->stream_descriptors[stream_index].timing.pixel_clock_khz);
+
+ out->slice_lines = 31;
+ out->arbitration_slice = 2;
+}
+
void dml2_core_calcs_get_global_fams2_programming(const struct dml2_core_internal_display_mode_lib *mode_lib,
const struct display_configuation_with_meta *display_cfg,
struct dmub_cmd_fams2_global_config *fams2_global_config)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.h
index 27ef0e096b25..3249f6bcf7bc 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.h
@@ -19,6 +19,7 @@ struct display_configuation_with_meta;
unsigned int dml2_core_calcs_mode_support_ex(struct dml2_core_calcs_mode_support_ex *in_out_params);
bool dml2_core_calcs_mode_programming_ex(struct dml2_core_calcs_mode_programming_ex *in_out_params);
void dml2_core_calcs_get_watermarks(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_dchub_watermark_regs *out);
+void dml2_core_calcs_get_mcif_arb_params(const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_mcif_global_register_set *out);
void dml2_core_calcs_get_arb_params(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_display_arb_regs *out);
void dml2_core_calcs_get_pipe_regs(const struct dml2_display_cfg *dml2_display_cfg, struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_dchub_per_pipe_register_set *out, int pipe_index);
void dml2_core_calcs_get_stream_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_per_stream_programming *out, int pipe_index);
@@ -30,6 +31,7 @@ void dml2_core_calcs_get_stream_support_info(const struct dml2_display_cfg *disp
void dml2_core_calcs_get_mall_allocation(struct dml2_core_internal_display_mode_lib *mode_lib, unsigned int *out, int pipe_index);
void dml2_core_calcs_get_stream_fams2_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, const struct display_configuation_with_meta *display_cfg, union dmub_cmd_fams2_config *fams2_base_programming, union dmub_cmd_fams2_config *fams2_sub_programming, enum dml2_pstate_method pstate_method, int plane_index);
void dml2_core_calcs_get_global_fams2_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, const struct display_configuation_with_meta *display_cfg, struct dmub_cmd_fams2_global_config *fams2_global_config);
+void dml2_core_calcs_get_per_dwb_params(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_mcif_per_pipe_register_set *out, int stream_index, int dwb_index);
void dml2_core_calcs_get_dpte_row_height(unsigned int *dpte_row_height, struct dml2_core_internal_display_mode_lib *mode_lib, bool is_plane1, enum dml2_source_format_class SourcePixelFormat, enum dml2_swizzle_mode SurfaceTiling, enum dml2_rotation_angle ScanDirection, unsigned int pitch, unsigned int GPUVMMinPageSizeKBytes);
void dml2_core_calcs_cursor_dlg_reg(struct dml2_cursor_dlg_regs *cursor_dlg_regs, const struct dml2_get_cursor_dlg_reg *p);
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
index 5ffe211a6643..c60a1faf2d5d 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
@@ -779,6 +779,25 @@ bool dpmm_dcn4_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_i
return result;
}
+static void dpmm_dcn4_map_mcif_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out)
+{
+ const struct dml2_core_internal_display_mode_lib *mode_lib = &in_out->core->clean_me_up.mode_lib;
+ struct dml2_mcif_global_register_set *mcif_regs = &in_out->programming->mcif_global_regs;
+
+ /* MCIF */
+ mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].urgent = (int unsigned)(mode_lib->mp.Watermark.WritebackUrgentWatermark * 1000.0);
+ mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.WritebackDRAMClockChangeWatermark * 1000.0);
+ mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.WritebackFCLKChangeWatermark * 1000.0);
+ mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.writeback_temp_read_or_ppt_watermark_us * 1000.0);
+
+ /* replicate sets A through D */
+ memcpy(&mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B], &mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A], sizeof(mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A]));
+ memcpy(&mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_C], &mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A], sizeof(mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A]));
+ memcpy(&mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_D], &mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A], sizeof(mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A]));
+
+ mcif_regs->num_watermark_sets = 4;
+}
+
bool dpmm_dcn4_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out)
{
const struct dml2_display_cfg *display_cfg = &in_out->display_cfg->display_config;
@@ -821,6 +840,8 @@ bool dpmm_dcn4_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_
dchubbub_regs->num_watermark_sets = 2;
+ dpmm_dcn4_map_mcif_watermarks(in_out);
+
return true;
}
bool dpmm_dcn42_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out)
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 24/70] drm/amd/display: Split DPMS ON into parts
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (22 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 23/70] drm/amd/display: Add DWB validation support to DML2.1 wrapper Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 25/70] drm/amd/display: Test color mod init and 3D LUT size Wayne Lin
` (45 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dominik Kaszewski, Alvin Lee
From: Dominik Kaszewski <dominik.kaszewski@amd.com>
[Why]
Ongoing optimization efforts require splitting DPMS ON around
enable_link, in order to enable running multiple sequences
in parallel.
[How]
* Split link_set_dpms_on across enable_link
* Add return value indicating whether the programming sequence
succeeded and/or run to the end.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/dc/inc/core_status.h | 10 +
.../gpu/drm/amd/display/dc/inc/link_service.h | 4 +-
.../gpu/drm/amd/display/dc/link/link_dpms.c | 184 ++++++++++++++----
.../gpu/drm/amd/display/dc/link/link_dpms.h | 4 +-
4 files changed, 156 insertions(+), 46 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
index 388f801f4582..1a17e727ed04 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
@@ -62,6 +62,16 @@ enum dc_status {
DC_FAIL_DP_LINK_BANDWIDTH = 28,
DC_FAIL_HW_CURSOR_SUPPORT = 29,
DC_FAIL_DP_TUNNEL_BW_VALIDATE = 30,
+
+ /// Link protocol handshake and DPMS hardware programming successful.
+ DC_DPMS_SUCCESS = DC_OK,
+ /// Handshake skipped by optimized path, programming successfully completed.
+ DC_DPMS_SKIPPED_HANDSHAKE = 31,
+ /// Handshake failed, programming successful, DCN in consistent state.
+ DC_DPMS_FAILED_HANDSHAKE = 32,
+ /// Handshake failed, programming aborted, DCN may be in inconsistent state.
+ DC_DPMS_FAILED_INCOMPLETE = 33,
+
DC_ERROR_UNEXPECTED = -1
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
index addeb3e3b25a..026d28046eea 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
@@ -155,8 +155,8 @@ struct link_service {
/*************************** DPMS *************************************/
- void (*set_dpms_on)(struct dc_state *state, struct pipe_ctx *pipe_ctx);
- void (*set_dpms_off)(struct pipe_ctx *pipe_ctx);
+ enum dc_status (*set_dpms_on)(struct dc_state *state, struct pipe_ctx *pipe_ctx);
+ enum dc_status (*set_dpms_off)(struct pipe_ctx *pipe_ctx);
void (*resume)(struct dc_link *link);
void (*blank_all_dp_displays)(struct dc *dc);
void (*blank_all_edp_displays)(struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index 335ae952ef60..949c669eb259 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -528,19 +528,27 @@ static bool write_i2c_redriver_setting(
return success;
}
+static struct link_encoder *get_link_encoder(struct pipe_ctx *pipe_ctx)
+{
+ struct link_encoder *link_enc
+ = pipe_ctx->stream->ctx->dc->config.unify_link_enc_assignment
+ ? pipe_ctx->link_res.dio_link_enc
+ : link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
+
+ ASSERT(link_enc);
+ return link_enc;
+}
+
static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
{
struct cp_psp *cp_psp = &pipe_ctx->stream->ctx->cp_psp;
- struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
+ struct link_encoder *link_enc = get_link_encoder(pipe_ctx);
struct cp_psp_stream_config config = {0};
enum dp_panel_mode panel_mode =
dp_get_panel_mode(pipe_ctx->stream->link);
if (cp_psp == NULL || cp_psp->funcs.update_stream_config == NULL)
return;
- if (!pipe_ctx->stream->ctx->dc->config.unify_link_enc_assignment)
- link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
- ASSERT(link_enc);
if (link_enc == NULL)
return;
@@ -2375,7 +2383,7 @@ static struct vpg *get_vpg(struct pipe_ctx *pipe_ctx)
return pipe_ctx->stream_res.stream_enc->vpg;
}
-void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
+enum dc_status link_set_dpms_off(struct pipe_ctx *pipe_ctx)
{
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
struct dc_stream_state *stream = pipe_ctx->stream;
@@ -2387,7 +2395,8 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
ASSERT(is_master_pipe_for_link(link, pipe_ctx));
if (dc_is_virtual_signal(stream->signal))
- return;
+ /* No real hardware to program for virtual signals. */
+ return DC_DPMS_SKIPPED_HANDSHAKE;
if (stream->sink) {
if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
@@ -2481,18 +2490,23 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
/* since current psp not loaded, we need to reset it to default */
link->panel_mode = panel_mode;
}
+
+ return DC_DPMS_SUCCESS;
}
-void link_set_dpms_on(
+static enum dc_status link_set_dpms_on_pre_enable_link(
struct dc_state *state,
- struct pipe_ctx *pipe_ctx)
+ struct pipe_ctx *pipe_ctx
+)
{
+ // Used conditionally in ifdef'ed diagnostic builds
+ (void) state;
+
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc *dc = stream->ctx->dc;
struct dc_link *link = stream->link;
- enum dc_status status;
- struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
+
enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
struct vpg *vpg = get_vpg(pipe_ctx);
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
@@ -2502,7 +2516,8 @@ void link_set_dpms_on(
ASSERT(is_master_pipe_for_link(link, pipe_ctx));
if (dc_is_virtual_signal(stream->signal))
- return;
+ /* No real hardware to program for virtual signals. */
+ return DC_DPMS_SKIPPED_HANDSHAKE;
if (stream->sink) {
if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
@@ -2516,13 +2531,12 @@ void link_set_dpms_on(
}
link_wait_for_unlocked(link);
- if (!dc->config.unify_link_enc_assignment)
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
if (!dc_is_virtual_signal(stream->signal)
&& !dc_is_hdmi_frl_signal(stream->signal)
&& !dp_is_128b_132b_signal(pipe_ctx)) {
+ struct link_encoder *link_enc = get_link_encoder(pipe_ctx);
+
if (link_enc)
link_enc->funcs->setup(
link_enc,
@@ -2569,7 +2583,9 @@ void link_set_dpms_on(
}
update_psp_stream_config(pipe_ctx, false);
- return;
+
+ /* Seamless boot: hardware already enabled by BIOS; skip link training. */
+ return DC_DPMS_SKIPPED_HANDSHAKE;
}
/* eDP lit up by bios already, no need to enable again. */
@@ -2587,11 +2603,16 @@ void link_set_dpms_on(
msleep(post_oui_delay);
}
- return;
+ /* eDP already lit by BIOS; skip standard enable steps. */
+ return DC_DPMS_SKIPPED_HANDSHAKE;
}
if (stream->dpms_off)
- return;
+ /*
+ * Stream is configured as DPMS-off; skip link enable.
+ * Hardware will NOT be in a fully enabled state after this early exit.
+ */
+ return DC_DPMS_FAILED_INCOMPLETE;
/* For Dp tunneling link, a pending HPD means that we have a race condition between processing
* current link and processing the pending HPD. If we enable the link now, we may end up with a
@@ -2599,7 +2620,11 @@ void link_set_dpms_on(
*/
if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->is_hpd_pending) {
DC_LOG_DEBUG("%s, Link%d HPD is pending, not enable it.\n", __func__, link->link_index);
- return;
+ /*
+ * Pending HPD on USB4 DPIA link: skip enable to avoid race condition.
+ * Hardware will NOT be in a fully enabled state after this early exit.
+ */
+ return DC_DPMS_FAILED_INCOMPLETE;
}
/* Have to setup DSC before DIG FE and BE are connected (which happens before the
@@ -2617,30 +2642,61 @@ void link_set_dpms_on(
if (link->replay_settings.config.replay_supported && !dc_is_embedded_signal(link->connector_signal))
dp_setup_replay(link, stream);
- // TODO: Split DPMS-on into 3 functions at this point
- status = enable_link(state, pipe_ctx);
+ return DC_DPMS_SUCCESS;
+}
+
+static enum dc_status link_set_dpms_on_enable_link(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx
+)
+{
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ const enum dc_status status = enable_link(state, pipe_ctx);
+
+ if (status == DC_OK)
+ return DC_DPMS_SUCCESS;
- if (status != DC_OK) {
- DC_LOG_WARNING("enabling link %u failed: %d\n",
- link->link_index,
- status);
+ DC_LOG_WARNING("enabling link %u failed: %d\n", link->link_index, status);
- /* Abort stream enable *unless* the failure was due to
- * DP link training - some DP monitors will recover and
- * show the stream anyway. But MST displays can't proceed
- * without link training.
- */
- if ((status != DC_FAIL_DP_LINK_TRAINING &&
- status != DC_FAIL_HDMI_FRL_LINK_TRAINING) ||
- stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
- if (false == link->link_status.link_active)
- disable_link(link, &pipe_ctx->link_res,
- stream->signal);
- BREAK_TO_DEBUGGER();
- return;
- }
+ /* Abort stream enable *unless* the failure was due to
+ * DP link training - some DP monitors will recover and
+ * show the stream anyway. But MST displays can't proceed
+ * without link training.
+ */
+ switch (status) {
+ case DC_FAIL_DP_LINK_TRAINING:
+ case DC_FAIL_HDMI_FRL_LINK_TRAINING:
+ if (stream->signal != SIGNAL_TYPE_DISPLAY_PORT_MST)
+ return DC_DPMS_SUCCESS;
+ break;
+
+ default:
+ break;
}
- // TODO: Split DPMS-on into 3 functions at this point
+
+ if (!link->link_status.link_active)
+ disable_link(link, &pipe_ctx->link_res, stream->signal);
+
+ /*
+ * Link enable failed; do NOT set skip_remaining so that post_enable_link
+ * still runs and leaves hardware in a consistent state.
+ */
+ return DC_DPMS_FAILED_HANDSHAKE;
+}
+
+static enum dc_status link_set_dpms_on_post_enable_link(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx
+)
+{
+ // Used conditionally in ifdef'ed diagnostic builds
+ (void) state;
+
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct hw_sequencer_funcs *hwss = &stream->ctx->dc->hwss;
if (stream->timing.flags.DSC && dc_is_hdmi_frl_signal(stream->signal))
//TODO: bring HDMI FRL in line with DP
@@ -2659,13 +2715,15 @@ void link_set_dpms_on(
if (!(dc_is_virtual_signal(stream->signal) ||
dc_is_hdmi_frl_signal(stream->signal) ||
dp_is_128b_132b_signal(pipe_ctx))) {
+ struct link_encoder *link_enc = get_link_encoder(pipe_ctx);
+
if (link_enc)
link_enc->funcs->setup(
link_enc,
stream->signal);
}
- dc->hwss.enable_stream(pipe_ctx);
+ hwss->enable_stream(pipe_ctx);
/* Set DPS PPS SDP (AKA "info frames") */
if (stream->timing.flags.DSC) {
@@ -2697,7 +2755,7 @@ void link_set_dpms_on(
link->is_display_mux_present)
msleep(20);
- dc->hwss.unblank_stream(pipe_ctx,
+ hwss->unblank_stream(pipe_ctx,
&link->cur_link_settings);
if (stream->sink_patches.delay_ignore_msa > 0)
@@ -2707,8 +2765,50 @@ void link_set_dpms_on(
enable_stream_features(pipe_ctx);
update_psp_stream_config(pipe_ctx, false);
- dc->hwss.enable_audio_stream(pipe_ctx);
+ hwss->enable_audio_stream(pipe_ctx);
if (dc_is_hdmi_signal(stream->signal))
set_avmute(pipe_ctx, false);
+
+ return DC_DPMS_SUCCESS;
+}
+
+enum dc_status link_set_dpms_on(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx
+)
+{
+ enum dc_status result = DC_DPMS_SUCCESS;
+
+ typedef enum dc_status (*step)(struct dc_state *, struct pipe_ctx *);
+ const step steps[] = {
+ link_set_dpms_on_pre_enable_link,
+ link_set_dpms_on_enable_link,
+ link_set_dpms_on_post_enable_link,
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(steps); i++) {
+ const enum dc_status step_result = steps[i](state, pipe_ctx);
+
+ switch (step_result) {
+ case DC_DPMS_SUCCESS:
+ case DC_DPMS_FAILED_HANDSHAKE:
+ // Enum is ordered from "best" to "worst" results
+ result = max(result, step_result);
+ break;
+
+ case DC_DPMS_SKIPPED_HANDSHAKE:
+ return step_result;
+
+ case DC_DPMS_FAILED_INCOMPLETE:
+ ASSERT(false);
+ return step_result;
+
+ default:
+ ASSERT(false);
+ return step_result;
+ }
+ }
+
+ return result;
}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.h b/drivers/gpu/drm/amd/display/dc/link/link_dpms.h
index e8662147dd8e..6559bc04d90e 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.h
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.h
@@ -27,10 +27,10 @@
#define __DC_LINK_DPMS_H__
#include "link_service.h"
-void link_set_dpms_on(
+enum dc_status link_set_dpms_on(
struct dc_state *state,
struct pipe_ctx *pipe_ctx);
-void link_set_dpms_off(struct pipe_ctx *pipe_ctx);
+enum dc_status link_set_dpms_off(struct pipe_ctx *pipe_ctx);
void link_resume(struct dc_link *link);
void link_blank_all_dp_displays(struct dc *dc);
void link_blank_all_edp_displays(struct dc *dc);
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 25/70] drm/amd/display: Test color mod init and 3D LUT size
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (23 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 24/70] drm/amd/display: Split DPMS ON into parts Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 26/70] drm/amd/display: Test plane colorop helper walkers Wayne Lin
` (44 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for amdgpu_dm_init_color_mod() and
amdgpu_dm_verify_lut3d_size().
init_color_mod is a smoke test that the x-points distribution is set up
without crashing. The verify_lut3d_size tests build adev/DC fixtures with
and without the 3D LUT capability and confirm that correct shaper and 3D
LUT blob sizes succeed while mismatched sizes return -EINVAL.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +
.../amdgpu_dm/tests/amdgpu_dm_color_test.c | 123 ++++++++++++++++++
2 files changed, 125 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index bcb2cee8c6e8..45d11990bc8e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -172,6 +172,7 @@ void amdgpu_dm_init_color_mod(void)
{
setup_x_points_distribution();
}
+EXPORT_IF_KUNIT(amdgpu_dm_init_color_mod);
STATIC_IFN_KUNIT INLINE_IFN_KUNIT
struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
@@ -1177,6 +1178,7 @@ int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_verify_lut3d_size);
/**
* amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported sizes
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index d64c7da20f2c..e46a8454425d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -7,14 +7,17 @@
#include <kunit/test.h>
#include <linux/types.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_colorop.h>
#include <drm/drm_property.h>
#include <uapi/drm/drm_mode.h>
#include "dc.h"
+#include "amdgpu.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_color.h"
+#include "amdgpu_dm_kunit_test_helpers.h"
/* ---- Tests for amdgpu_dm_fixpt_from_s3132 ---- */
@@ -1527,6 +1530,119 @@ static void dm_test_set_colorop_in_tf_1d_curve_bypass(struct kunit *test)
(int)TRANSFER_FUNCTION_LINEAR);
}
+/* ---- Tests for amdgpu_dm_init_color_mod ---- */
+
+/**
+ * dm_test_init_color_mod - Smoke test: must initialize x-points without crashing
+ * @test: KUnit test context
+ */
+static void dm_test_init_color_mod(struct kunit *test)
+{
+ amdgpu_dm_init_color_mod();
+ KUNIT_SUCCEED(test);
+}
+
+/* ---- Tests for amdgpu_dm_verify_lut3d_size ---- */
+
+/**
+ * dm_test_verify_lut3d_alloc_plane - Allocate a dm_plane_state for lut3d tests
+ * @test: KUnit test context
+ *
+ * Returns: a drm_plane_state pointer embedded in a zeroed dm_plane_state.
+ */
+static struct drm_plane_state *
+dm_test_verify_lut3d_alloc_plane(struct kunit *test)
+{
+ struct dm_plane_state *dm_plane_state;
+
+ dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_plane_state);
+
+ return &dm_plane_state->base;
+}
+
+/**
+ * dm_test_verify_lut3d_alloc_adev - Allocate adev with a DC and given 3D LUT cap
+ * @test: KUnit test context
+ * @has_3dlut: value to program into caps.color.dpp.hw_3d_lut
+ *
+ * Returns: an amdgpu_device with adev->dm.dc allocated.
+ */
+static struct amdgpu_device *
+dm_test_verify_lut3d_alloc_adev(struct kunit *test, bool has_3dlut)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+ adev->dm.dc = kunit_kzalloc(test, sizeof(*adev->dm.dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, adev->dm.dc);
+ adev->dm.dc->caps.color.dpp.hw_3d_lut = has_3dlut;
+
+ return adev;
+}
+
+/**
+ * dm_test_verify_lut3d_no_luts - No shaper/3D LUT blobs: must succeed
+ * @test: KUnit test context
+ */
+static void dm_test_verify_lut3d_no_luts(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_verify_lut3d_alloc_adev(test, false);
+ struct drm_plane_state *plane_state = dm_test_verify_lut3d_alloc_plane(test);
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut3d_size(adev, plane_state), 0);
+}
+
+/**
+ * dm_test_verify_lut3d_bad_shaper - Shaper LUT with wrong size: must return -EINVAL
+ * @test: KUnit test context
+ */
+static void dm_test_verify_lut3d_bad_shaper(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_verify_lut3d_alloc_adev(test, true);
+ struct drm_plane_state *plane_state = dm_test_verify_lut3d_alloc_plane(test);
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+
+ /* has_3dlut => expected shaper size is MAX_COLOR_LUT_ENTRIES */
+ dm_plane_state->shaper_lut = dm_test_make_lut_blob(test, 128);
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut3d_size(adev, plane_state), -EINVAL);
+}
+
+/**
+ * dm_test_verify_lut3d_bad_lut3d - 3D LUT with wrong size: must return -EINVAL
+ * @test: KUnit test context
+ */
+static void dm_test_verify_lut3d_bad_lut3d(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_verify_lut3d_alloc_adev(test, true);
+ struct drm_plane_state *plane_state = dm_test_verify_lut3d_alloc_plane(test);
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+
+ /* Valid shaper, but wrong 3D LUT size */
+ dm_plane_state->shaper_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
+ dm_plane_state->lut3d = dm_test_make_lut_blob(test, 128);
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut3d_size(adev, plane_state), -EINVAL);
+}
+
+/**
+ * dm_test_verify_lut3d_valid - Correct shaper and 3D LUT sizes: must succeed
+ * @test: KUnit test context
+ */
+static void dm_test_verify_lut3d_valid(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_test_verify_lut3d_alloc_adev(test, true);
+ struct drm_plane_state *plane_state = dm_test_verify_lut3d_alloc_plane(test);
+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+ const uint32_t lut3d_entries =
+ MAX_COLOR_3DLUT_SIZE * MAX_COLOR_3DLUT_SIZE * MAX_COLOR_3DLUT_SIZE;
+
+ dm_plane_state->shaper_lut = dm_test_make_lut_blob(test, MAX_COLOR_LUT_ENTRIES);
+ dm_plane_state->lut3d = dm_test_make_lut_blob(test, lut3d_entries);
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut3d_size(adev, plane_state), 0);
+}
+
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@@ -1624,6 +1740,13 @@ static struct kunit_case dm_color_test_cases[] = {
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_invalid_type),
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_unsupported_curve),
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_bypass),
+ /* amdgpu_dm_init_color_mod */
+ KUNIT_CASE(dm_test_init_color_mod),
+ /* amdgpu_dm_verify_lut3d_size */
+ KUNIT_CASE(dm_test_verify_lut3d_no_luts),
+ KUNIT_CASE(dm_test_verify_lut3d_bad_shaper),
+ KUNIT_CASE(dm_test_verify_lut3d_bad_lut3d),
+ KUNIT_CASE(dm_test_verify_lut3d_valid),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 26/70] drm/amd/display: Test plane colorop helper walkers
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (24 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 25/70] drm/amd/display: Test color mod init and 3D LUT size Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 27/70] drm/amd/display: Test CRTC color management update Wayne Lin
` (43 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for the per-colorop plane helpers
__set_dm_plane_colorop_multiplier(), __set_dm_plane_colorop_3x4_matrix()
and __set_dm_plane_colorop_degamma().
A single-colorop atomic-state fixture drives each helper: the multiplier
programs hdr_mult, the 3x4 matrix enables gamut remap (and rejects a
wrong blob length), and the degamma 1D curve maps to a predefined
transfer function (and rejects an unsupported curve).
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 9 +-
.../amd/display/amdgpu_dm/amdgpu_dm_color.h | 11 +
.../amdgpu_dm/tests/amdgpu_dm_color_test.c | 207 ++++++++++++++++++
3 files changed, 224 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 45d11990bc8e..2f46de79a47c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1547,7 +1547,7 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
}
EXPORT_IF_KUNIT(__set_colorop_in_tf_1d_curve);
-static int
+STATIC_IFN_KUNIT int
__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
struct dc_plane_state *dc_plane_state,
struct drm_colorop *colorop)
@@ -1573,8 +1573,9 @@ __set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
return __set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state);
}
+EXPORT_IF_KUNIT(__set_dm_plane_colorop_degamma);
-static int
+STATIC_IFN_KUNIT int
__set_dm_plane_colorop_3x4_matrix(struct drm_plane_state *plane_state,
struct dc_plane_state *dc_plane_state,
struct drm_colorop *colorop)
@@ -1614,8 +1615,9 @@ __set_dm_plane_colorop_3x4_matrix(struct drm_plane_state *plane_state,
return 0;
}
+EXPORT_IF_KUNIT(__set_dm_plane_colorop_3x4_matrix);
-static int
+STATIC_IFN_KUNIT int
__set_dm_plane_colorop_multiplier(struct drm_plane_state *plane_state,
struct dc_plane_state *dc_plane_state,
struct drm_colorop *colorop)
@@ -1643,6 +1645,7 @@ __set_dm_plane_colorop_multiplier(struct drm_plane_state *plane_state,
return 0;
}
+EXPORT_IF_KUNIT(__set_dm_plane_colorop_multiplier);
static int
__set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
index 8dbbcb3ab156..1a8b06bdaf44 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
@@ -113,6 +113,17 @@ int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
struct dc_plane_cm *cm);
int __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
struct drm_colorop_state *colorop_state);
+struct drm_plane_state;
+struct drm_colorop;
+int __set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
+ struct dc_plane_state *dc_plane_state,
+ struct drm_colorop *colorop);
+int __set_dm_plane_colorop_3x4_matrix(struct drm_plane_state *plane_state,
+ struct dc_plane_state *dc_plane_state,
+ struct drm_colorop *colorop);
+int __set_dm_plane_colorop_multiplier(struct drm_plane_state *plane_state,
+ struct dc_plane_state *dc_plane_state,
+ struct drm_colorop *colorop);
#endif
#endif /* __AMDGPU_DM_COLOR_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index e46a8454425d..a4253e44ca7b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -1643,6 +1643,204 @@ static void dm_test_verify_lut3d_valid(struct kunit *test)
KUNIT_EXPECT_EQ(test, amdgpu_dm_verify_lut3d_size(adev, plane_state), 0);
}
+/* ---- Tests for plane colorop helpers ---- */
+
+/**
+ * struct dm_test_colorop_fixture - shared state for plane colorop walk tests
+ * @adev: backing amdgpu device (provides a real DRM device)
+ * @state: fabricated atomic state with a single colorop slot
+ * @colorop: the colorop under test
+ * @colorop_state: the new state attached to @colorop
+ * @plane_state: plane state whose ->state points at @state
+ * @dc_plane_state: DC plane state written by the helpers
+ */
+struct dm_test_colorop_fixture {
+ struct amdgpu_device *adev;
+ struct drm_atomic_state *state;
+ struct drm_colorop *colorop;
+ struct drm_colorop_state *colorop_state;
+ struct drm_plane_state *plane_state;
+ struct dc_plane_state *dc_plane_state;
+};
+
+/**
+ * dm_test_colorop_setup - build a single-colorop atomic state fixture
+ * @test: KUnit test context
+ * @type: colorop type to assign
+ *
+ * Fabricates a minimal drm_atomic_state with one colorop slot so that
+ * for_each_new_colorop_in_state() finds exactly the colorop under test.
+ *
+ * Returns: a populated fixture (by value).
+ */
+static struct dm_test_colorop_fixture
+dm_test_colorop_setup(struct kunit *test, enum drm_colorop_type type)
+{
+ struct dm_test_colorop_fixture f = {0};
+ struct __drm_colorops_state *colorops;
+ struct dm_plane_state *dm_plane_state;
+
+ f.adev = dm_kunit_alloc_adev(test);
+ f.adev->ddev.mode_config.num_colorop = 1;
+
+ f.colorop = kunit_kzalloc(test, sizeof(*f.colorop), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.colorop);
+ f.colorop->dev = &f.adev->ddev;
+ f.colorop->type = type;
+
+ f.colorop_state = kunit_kzalloc(test, sizeof(*f.colorop_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.colorop_state);
+ f.colorop_state->colorop = f.colorop;
+
+ colorops = kunit_kcalloc(test, 1, sizeof(*colorops), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, colorops);
+ colorops[0].ptr = f.colorop;
+ colorops[0].new_state = f.colorop_state;
+
+ f.state = kunit_kzalloc(test, sizeof(*f.state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.state);
+ f.state->dev = &f.adev->ddev;
+ f.state->colorops = colorops;
+
+ dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_plane_state);
+ f.plane_state = &dm_plane_state->base;
+ f.plane_state->state = f.state;
+
+ f.dc_plane_state = kunit_kzalloc(test, sizeof(*f.dc_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.dc_plane_state);
+
+ return f;
+}
+
+/**
+ * dm_test_colorop_multiplier_applied - Multiplier colorop programs hdr_mult
+ * @test: KUnit test context
+ */
+static void dm_test_colorop_multiplier_applied(struct kunit *test)
+{
+ struct dm_test_colorop_fixture f =
+ dm_test_colorop_setup(test, DRM_COLOROP_MULTIPLIER);
+
+ /* 1.0 in S31.32 sign-magnitude */
+ f.colorop_state->multiplier = 1ULL << 32;
+
+ KUNIT_EXPECT_EQ(test,
+ __set_dm_plane_colorop_multiplier(f.plane_state, f.dc_plane_state, f.colorop),
+ 0);
+ KUNIT_EXPECT_EQ(test, f.dc_plane_state->hdr_mult.value, (long long)(1ULL << 32));
+}
+
+/**
+ * dm_test_colorop_multiplier_no_match - Non-multiplier colorop leaves hdr_mult untouched
+ * @test: KUnit test context
+ */
+static void dm_test_colorop_multiplier_no_match(struct kunit *test)
+{
+ struct dm_test_colorop_fixture f =
+ dm_test_colorop_setup(test, DRM_COLOROP_1D_CURVE);
+
+ f.colorop_state->multiplier = 1ULL << 32;
+
+ KUNIT_EXPECT_EQ(test,
+ __set_dm_plane_colorop_multiplier(f.plane_state, f.dc_plane_state, f.colorop),
+ 0);
+ KUNIT_EXPECT_EQ(test, f.dc_plane_state->hdr_mult.value, 0LL);
+}
+
+/**
+ * dm_test_colorop_3x4_matrix_applied - CTM 3x4 colorop enables gamut remap
+ * @test: KUnit test context
+ */
+static void dm_test_colorop_3x4_matrix_applied(struct kunit *test)
+{
+ struct dm_test_colorop_fixture f =
+ dm_test_colorop_setup(test, DRM_COLOROP_CTM_3X4);
+ struct drm_property_blob *blob;
+ struct drm_color_ctm_3x4 *ctm;
+
+ ctm = kunit_kzalloc(test, sizeof(*ctm), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctm);
+ ctm->matrix[0] = 1ULL << 32; /* identity diagonal */
+ ctm->matrix[5] = 1ULL << 32;
+ ctm->matrix[10] = 1ULL << 32;
+
+ blob = kunit_kzalloc(test, sizeof(*blob), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, blob);
+ blob->data = ctm;
+ blob->length = sizeof(struct drm_color_ctm_3x4);
+ f.colorop_state->data = blob;
+
+ KUNIT_EXPECT_EQ(test,
+ __set_dm_plane_colorop_3x4_matrix(f.plane_state, f.dc_plane_state, f.colorop),
+ 0);
+ KUNIT_EXPECT_TRUE(test, f.dc_plane_state->gamut_remap_matrix.enable_remap);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->input_csc_color_matrix.enable_adjustment);
+}
+
+/**
+ * dm_test_colorop_3x4_matrix_bad_length - Wrong blob length: must return -EINVAL
+ * @test: KUnit test context
+ */
+static void dm_test_colorop_3x4_matrix_bad_length(struct kunit *test)
+{
+ struct dm_test_colorop_fixture f =
+ dm_test_colorop_setup(test, DRM_COLOROP_CTM_3X4);
+ struct drm_property_blob *blob;
+
+ blob = kunit_kzalloc(test, sizeof(*blob), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, blob);
+ blob->data = kunit_kzalloc(test, 8, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, blob->data);
+ blob->length = 7; /* not sizeof(struct drm_color_ctm_3x4) */
+ f.colorop_state->data = blob;
+
+ KUNIT_EXPECT_EQ(test,
+ __set_dm_plane_colorop_3x4_matrix(f.plane_state, f.dc_plane_state, f.colorop),
+ -EINVAL);
+}
+
+/**
+ * dm_test_colorop_degamma_predefined - Degamma 1D curve programs predefined TF
+ * @test: KUnit test context
+ */
+static void dm_test_colorop_degamma_predefined(struct kunit *test)
+{
+ struct dm_test_colorop_fixture f =
+ dm_test_colorop_setup(test, DRM_COLOROP_1D_CURVE);
+
+ /* SRGB_EOTF is part of amdgpu_dm_supported_degam_tfs */
+ f.colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_SRGB_EOTF;
+ f.colorop_state->bypass = false;
+
+ KUNIT_EXPECT_EQ(test,
+ __set_dm_plane_colorop_degamma(f.plane_state, f.dc_plane_state, f.colorop),
+ 0);
+ KUNIT_EXPECT_EQ(test,
+ (int)f.dc_plane_state->in_transfer_func.type,
+ (int)TF_TYPE_PREDEFINED);
+ KUNIT_EXPECT_EQ(test,
+ (int)f.dc_plane_state->in_transfer_func.tf,
+ (int)TRANSFER_FUNCTION_SRGB);
+}
+
+/**
+ * dm_test_colorop_degamma_no_match - Unsupported degamma curve: must return -EINVAL
+ * @test: KUnit test context
+ */
+static void dm_test_colorop_degamma_no_match(struct kunit *test)
+{
+ struct dm_test_colorop_fixture f =
+ dm_test_colorop_setup(test, DRM_COLOROP_1D_CURVE);
+
+ /* SRGB_INV_EOTF is a shaper TF, not in amdgpu_dm_supported_degam_tfs */
+ f.colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF;
+
+ KUNIT_EXPECT_EQ(test,
+ __set_dm_plane_colorop_degamma(f.plane_state, f.dc_plane_state, f.colorop),
+ -EINVAL);
+}
+
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@@ -1747,6 +1945,15 @@ static struct kunit_case dm_color_test_cases[] = {
KUNIT_CASE(dm_test_verify_lut3d_bad_shaper),
KUNIT_CASE(dm_test_verify_lut3d_bad_lut3d),
KUNIT_CASE(dm_test_verify_lut3d_valid),
+ /* __set_dm_plane_colorop_multiplier */
+ KUNIT_CASE(dm_test_colorop_multiplier_applied),
+ KUNIT_CASE(dm_test_colorop_multiplier_no_match),
+ /* __set_dm_plane_colorop_3x4_matrix */
+ KUNIT_CASE(dm_test_colorop_3x4_matrix_applied),
+ KUNIT_CASE(dm_test_colorop_3x4_matrix_bad_length),
+ /* __set_dm_plane_colorop_degamma */
+ KUNIT_CASE(dm_test_colorop_degamma_predefined),
+ KUNIT_CASE(dm_test_colorop_degamma_no_match),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 27/70] drm/amd/display: Test CRTC color management update
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (25 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 26/70] drm/amd/display: Test plane colorop helper walkers Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 28/70] drm/amd/display: Test plane " Wayne Lin
` (42 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for amdgpu_dm_check_crtc_color_mgmt() and
amdgpu_dm_update_crtc_color_mgmt().
A shared color-update fixture (adev/DC, atomic state, CRTC/stream and
plane state) backs the tests: the check path succeeds with no CRTC LUTs,
and the update path leaves the stream gamut remap bypassed without a CTM
and enables it when a CRTC CTM is present.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +
.../amdgpu_dm/tests/amdgpu_dm_color_test.c | 142 ++++++++++++++++++
2 files changed, 144 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 2f46de79a47c..36aa4af581dd 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1323,6 +1323,7 @@ int amdgpu_dm_check_crtc_color_mgmt(struct dm_crtc_state *crtc,
return r;
}
+EXPORT_IF_KUNIT(amdgpu_dm_check_crtc_color_mgmt);
/**
* amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream.
@@ -1381,6 +1382,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_update_crtc_color_mgmt);
static int
map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index a4253e44ca7b..2e7a6b2a6d91 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -1841,6 +1841,144 @@ static void dm_test_colorop_degamma_no_match(struct kunit *test)
-EINVAL);
}
+/* ---- Tests for CRTC and plane color management update paths ---- */
+
+/**
+ * struct dm_test_color_update_fixture - minimal color update fixture
+ * @adev: backing amdgpu device
+ * @state: DRM atomic state with @adev's DRM device
+ * @crtc_state: DM CRTC state under test
+ * @stream: DC stream referenced by @crtc_state
+ * @dm_plane_state: DM plane state under test
+ * @plane: DRM plane referenced by @dm_plane_state
+ * @dc_plane_state: DC plane state under test
+ */
+struct dm_test_color_update_fixture {
+ struct amdgpu_device *adev;
+ struct drm_atomic_state *state;
+ struct dm_crtc_state *crtc_state;
+ struct dc_stream_state *stream;
+ struct dm_plane_state *dm_plane_state;
+ struct drm_plane *plane;
+ struct dc_plane_state *dc_plane_state;
+};
+
+/**
+ * dm_test_color_update_setup - allocate a minimal color update fixture
+ * @test: KUnit test context
+ *
+ * Returns: a populated fixture with all large DC/DRM state heap-allocated.
+ */
+static struct dm_test_color_update_fixture
+dm_test_color_update_setup(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = {0};
+
+ f.adev = dm_kunit_alloc_adev(test);
+ f.adev->dm.dc = kunit_kzalloc(test, sizeof(*f.adev->dm.dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.adev->dm.dc);
+
+ f.state = kunit_kzalloc(test, sizeof(*f.state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.state);
+ f.state->dev = &f.adev->ddev;
+
+ f.stream = kunit_kzalloc(test, sizeof(*f.stream), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.stream);
+
+ f.crtc_state = kunit_kzalloc(test, sizeof(*f.crtc_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.crtc_state);
+ f.crtc_state->base.state = f.state;
+ f.crtc_state->stream = f.stream;
+
+ f.plane = kunit_kzalloc(test, sizeof(*f.plane), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.plane);
+ f.plane->dev = &f.adev->ddev;
+
+ f.dm_plane_state = kunit_kzalloc(test, sizeof(*f.dm_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.dm_plane_state);
+ f.dm_plane_state->base.state = f.state;
+ f.dm_plane_state->base.plane = f.plane;
+
+ f.dc_plane_state = kunit_kzalloc(test, sizeof(*f.dc_plane_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f.dc_plane_state);
+
+ return f;
+}
+
+/**
+ * dm_test_make_ctm_blob - Allocate a fake drm_property_blob for CTM data
+ * @test: KUnit test context
+ * @data: CTM data pointer
+ * @size: CTM data size in bytes
+ *
+ * Returns: a fake property blob pointing at @data.
+ */
+static struct drm_property_blob *
+dm_test_make_ctm_blob(struct kunit *test, void *data, size_t size)
+{
+ struct drm_property_blob *blob;
+
+ blob = kunit_kzalloc(test, sizeof(*blob), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, blob);
+ blob->data = data;
+ blob->length = size;
+
+ return blob;
+}
+
+/**
+ * dm_test_check_crtc_color_mgmt_no_luts - No CRTC LUTs check succeeds
+ * @test: KUnit test context
+ */
+static void dm_test_check_crtc_color_mgmt_no_luts(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.crtc_state->cm_has_degamma = true;
+ f.crtc_state->cm_is_degamma_srgb = true;
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_check_crtc_color_mgmt(f.crtc_state, true), 0);
+ KUNIT_EXPECT_FALSE(test, f.crtc_state->cm_has_degamma);
+ KUNIT_EXPECT_FALSE(test, f.crtc_state->cm_is_degamma_srgb);
+}
+
+/**
+ * dm_test_update_crtc_color_mgmt_no_ctm - No CRTC CTM leaves remap bypassed
+ * @test: KUnit test context
+ */
+static void dm_test_update_crtc_color_mgmt_no_ctm(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.stream->gamut_remap_matrix.enable_remap = true;
+ f.stream->csc_color_matrix.enable_adjustment = true;
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_update_crtc_color_mgmt(f.crtc_state), 0);
+ KUNIT_EXPECT_FALSE(test, f.stream->gamut_remap_matrix.enable_remap);
+ KUNIT_EXPECT_FALSE(test, f.stream->csc_color_matrix.enable_adjustment);
+}
+
+/**
+ * dm_test_update_crtc_color_mgmt_ctm - CRTC CTM enables stream gamut remap
+ * @test: KUnit test context
+ */
+static void dm_test_update_crtc_color_mgmt_ctm(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+ struct drm_color_ctm *ctm;
+
+ ctm = kunit_kzalloc(test, sizeof(*ctm), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctm);
+ ctm->matrix[0] = 1ULL << 32;
+ ctm->matrix[4] = 1ULL << 32;
+ ctm->matrix[8] = 1ULL << 32;
+ f.crtc_state->base.ctm = dm_test_make_ctm_blob(test, ctm, sizeof(*ctm));
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_update_crtc_color_mgmt(f.crtc_state), 0);
+ KUNIT_EXPECT_TRUE(test, f.stream->gamut_remap_matrix.enable_remap);
+ KUNIT_EXPECT_FALSE(test, f.stream->csc_color_matrix.enable_adjustment);
+}
+
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@@ -1954,6 +2092,10 @@ static struct kunit_case dm_color_test_cases[] = {
/* __set_dm_plane_colorop_degamma */
KUNIT_CASE(dm_test_colorop_degamma_predefined),
KUNIT_CASE(dm_test_colorop_degamma_no_match),
+ /* CRTC and plane color management update paths */
+ KUNIT_CASE(dm_test_check_crtc_color_mgmt_no_luts),
+ KUNIT_CASE(dm_test_update_crtc_color_mgmt_no_ctm),
+ KUNIT_CASE(dm_test_update_crtc_color_mgmt_ctm),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 28/70] drm/amd/display: Test plane color management update
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (26 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 27/70] drm/amd/display: Test CRTC color management update Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 29/70] drm/amd/display: Test plane colorop pipeline update Wayne Lin
` (41 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for the legacy paths of
amdgpu_dm_update_plane_color_mgmt().
Using the shared color-update fixture, the tests cover the bad 3D LUT
size early failure, the default fallback path, implicit CRTC degamma
mapping, color caps taken from the DC context, and a plane CTM mapping to
the DPP gamut remap matrix.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_color_test.c | 108 ++++++++++++++++++
2 files changed, 109 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 36aa4af581dd..dc1ad4325739 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -2132,3 +2132,4 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
return amdgpu_dm_plane_set_color_properties(plane_state, dc_plane_state);
}
+EXPORT_IF_KUNIT(amdgpu_dm_update_plane_color_mgmt);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index 2e7a6b2a6d91..6bca2b2f62a8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -1979,6 +1979,109 @@ static void dm_test_update_crtc_color_mgmt_ctm(struct kunit *test)
KUNIT_EXPECT_FALSE(test, f.stream->csc_color_matrix.enable_adjustment);
}
+/**
+ * dm_test_update_plane_color_mgmt_bad_lut3d - Bad 3D LUT size fails early
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_bad_lut3d(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.adev->dm.dc->caps.color.dpp.hw_3d_lut = true;
+ f.dm_plane_state->lut3d = dm_test_make_lut_blob(test, 128);
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base,
+ f.dc_plane_state),
+ -EINVAL);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_fallback_defaults - Legacy fallback default path
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_fallback_defaults(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_EQ(test, f.dc_plane_state->hdr_mult.value, 0LL);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.shaper_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.blend_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.lut3d_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->gamut_remap_matrix.enable_remap);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_maps_crtc_degamma - CRTC implicit degamma path
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_maps_crtc_degamma(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.crtc_state->cm_is_degamma_srgb = true;
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_EQ(test,
+ (int)f.dc_plane_state->in_transfer_func.type,
+ (int)TF_TYPE_PREDEFINED);
+ KUNIT_EXPECT_EQ(test,
+ (int)f.dc_plane_state->in_transfer_func.tf,
+ (int)TRANSFER_FUNCTION_SRGB);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_uses_color_caps - DC context provides color caps
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_uses_color_caps(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+ struct dc_context *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+ ctx->dc = f.adev->dm.dc;
+ f.dc_plane_state->ctx = ctx;
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_plane_ctm - Plane CTM maps to gamut remap
+ * @test: KUnit test context
+ *
+ * When the plane has a CTM blob, the update path programs the DPP gamut
+ * remap matrix and enables remapping (and disables the input CSC).
+ */
+static void dm_test_update_plane_color_mgmt_plane_ctm(struct kunit *test)
+{
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+ struct drm_color_ctm_3x4 *ctm;
+
+ ctm = kunit_kzalloc(test, sizeof(*ctm), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctm);
+ /* Identity-ish entries; values are irrelevant to the branch taken. */
+ ctm->matrix[0] = 0x100000000ULL;
+ ctm->matrix[5] = 0x100000000ULL;
+ ctm->matrix[10] = 0x100000000ULL;
+
+ f.dm_plane_state->ctm = dm_test_make_ctm_blob(test, ctm, sizeof(*ctm));
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_TRUE(test, f.dc_plane_state->gamut_remap_matrix.enable_remap);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->input_csc_color_matrix.enable_adjustment);
+}
+
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@@ -2096,6 +2199,11 @@ static struct kunit_case dm_color_test_cases[] = {
KUNIT_CASE(dm_test_check_crtc_color_mgmt_no_luts),
KUNIT_CASE(dm_test_update_crtc_color_mgmt_no_ctm),
KUNIT_CASE(dm_test_update_crtc_color_mgmt_ctm),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_bad_lut3d),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_fallback_defaults),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_maps_crtc_degamma),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_uses_color_caps),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_plane_ctm),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 29/70] drm/amd/display: Test plane colorop pipeline update
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (27 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 28/70] drm/amd/display: Test plane " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 30/70] drm/amd/display: add KUnit tests for DM IP-block callbacks Wayne Lin
` (40 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for the colorop-pipeline path of
amdgpu_dm_update_plane_color_mgmt().
Test-local helpers fabricate a linked colorop pipeline so the update path
can be exercised end to end: a fully bypassed pipeline succeeds, a
pipeline missing the multiplier or the 3x4 op falls back to defaults, and
a pipeline with no 3D LUT hardware skips the 3D ops.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_color_test.c | 219 ++++++++++++++++++
1 file changed, 219 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index 6bca2b2f62a8..641126d03c65 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -2082,6 +2082,221 @@ static void dm_test_update_plane_color_mgmt_plane_ctm(struct kunit *test)
KUNIT_EXPECT_FALSE(test, f.dc_plane_state->input_csc_color_matrix.enable_adjustment);
}
+/**
+ * dm_test_colorop_pipeline_add - append one colorop to a fabricated pipeline
+ * @test: KUnit test context
+ * @f: color update fixture that owns the atomic state
+ * @index: colorop array index to populate
+ * @type: colorop type
+ * @curve_1d_type: 1D curve type for DRM_COLOROP_1D_CURVE states
+ * @bypass: bypass flag for the new colorop state
+ *
+ * Returns: the newly allocated colorop.
+ */
+static struct drm_colorop *
+dm_test_colorop_pipeline_add(struct kunit *test,
+ struct dm_test_color_update_fixture *f,
+ int index, enum drm_colorop_type type,
+ enum drm_colorop_curve_1d_type curve_1d_type,
+ bool bypass)
+{
+ struct drm_colorop_state *colorop_state;
+ struct drm_colorop *colorop;
+
+ colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, colorop);
+ colorop->dev = &f->adev->ddev;
+ colorop->type = type;
+ colorop->size = MAX_COLOR_LUT_ENTRIES;
+
+ colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, colorop_state);
+ colorop_state->colorop = colorop;
+ colorop_state->curve_1d_type = curve_1d_type;
+ colorop_state->bypass = bypass;
+
+ f->state->colorops[index].ptr = colorop;
+ f->state->colorops[index].new_state = colorop_state;
+
+ return colorop;
+}
+
+/**
+ * dm_test_colorop_pipeline_setup - build a linked colorop pipeline prefix
+ * @test: KUnit test context
+ * @f: color update fixture that owns the atomic state
+ * @types: colorop types to create
+ * @curves: curve type for each colorop state
+ * @bypass: bypass flag for each colorop state
+ * @count: number of colorops to create
+ *
+ * Returns: the first colorop in the linked pipeline.
+ */
+static struct drm_colorop *
+dm_test_colorop_pipeline_setup(struct kunit *test,
+ struct dm_test_color_update_fixture *f,
+ const enum drm_colorop_type *types,
+ const enum drm_colorop_curve_1d_type *curves,
+ const bool *bypass,
+ int count)
+{
+ struct drm_colorop **colorops;
+ int i;
+
+ f->state->colorops = kunit_kcalloc(test, count, sizeof(*f->state->colorops),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f->state->colorops);
+ f->adev->ddev.mode_config.num_colorop = count;
+
+ colorops = kunit_kcalloc(test, count, sizeof(*colorops), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, colorops);
+
+ for (i = 0; i < count; i++)
+ colorops[i] = dm_test_colorop_pipeline_add(test, f, i, types[i], curves[i], bypass[i]);
+
+ for (i = 0; i < count - 1; i++)
+ colorops[i]->next = colorops[i + 1];
+
+ return colorops[0];
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_colorop_bypass_pipeline - bypassed pipeline succeeds
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_colorop_bypass_pipeline(struct kunit *test)
+{
+ static const enum drm_colorop_type types[] = {
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_MULTIPLIER,
+ DRM_COLOROP_CTM_3X4,
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_1D_LUT,
+ DRM_COLOROP_3D_LUT,
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_1D_LUT,
+ };
+ static const enum drm_colorop_curve_1d_type curves[] = {
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ };
+ static const bool bypass[] = {
+ true, true, true, true, true, true, true, true,
+ };
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.adev->dm.dc->caps.color.dpp.hw_3d_lut = true;
+ f.dm_plane_state->base.color_pipeline =
+ dm_test_colorop_pipeline_setup(test, &f, types, curves, bypass, ARRAY_SIZE(types));
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.shaper_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.lut3d_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.blend_enable);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_colorop_missing_multiplier - missing second op falls back
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_colorop_missing_multiplier(struct kunit *test)
+{
+ static const enum drm_colorop_type types[] = { DRM_COLOROP_1D_CURVE };
+ static const enum drm_colorop_curve_1d_type curves[] = {
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ };
+ static const bool bypass[] = { true };
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.dm_plane_state->base.color_pipeline =
+ dm_test_colorop_pipeline_setup(test, &f, types, curves, bypass, ARRAY_SIZE(types));
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.shaper_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.blend_enable);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_colorop_missing_3x4 - missing third op falls back
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_colorop_missing_3x4(struct kunit *test)
+{
+ static const enum drm_colorop_type types[] = {
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_MULTIPLIER,
+ };
+ static const enum drm_colorop_curve_1d_type curves[] = {
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ };
+ static const bool bypass[] = { true, true };
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.dm_plane_state->base.color_pipeline =
+ dm_test_colorop_pipeline_setup(test, &f, types, curves, bypass, ARRAY_SIZE(types));
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base, f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.shaper_enable);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.blend_enable);
+}
+
+/**
+ * dm_test_update_plane_color_mgmt_colorop_no_3dlut_hw - no 3D LUT skips 3D ops
+ * @test: KUnit test context
+ */
+static void dm_test_update_plane_color_mgmt_colorop_no_3dlut_hw(struct kunit *test)
+{
+ static const enum drm_colorop_type types[] = {
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_MULTIPLIER,
+ DRM_COLOROP_CTM_3X4,
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_1D_LUT,
+ DRM_COLOROP_3D_LUT,
+ DRM_COLOROP_1D_CURVE,
+ DRM_COLOROP_1D_LUT,
+ };
+ static const enum drm_colorop_curve_1d_type curves[] = {
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ DRM_COLOROP_1D_CURVE_SRGB_EOTF,
+ };
+ static const bool bypass[] = {
+ true, true, true, true, true, false, true, true,
+ };
+ struct dm_test_color_update_fixture f = dm_test_color_update_setup(test);
+
+ f.adev->dm.dc->caps.color.dpp.hw_3d_lut = true;
+ f.dm_plane_state->base.color_pipeline =
+ dm_test_colorop_pipeline_setup(test, &f, types, curves, bypass,
+ ARRAY_SIZE(types));
+ f.adev->dm.dc->caps.color.dpp.hw_3d_lut = false;
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_update_plane_color_mgmt(f.crtc_state, &f.dm_plane_state->base,
+ f.dc_plane_state),
+ 0);
+ KUNIT_EXPECT_FALSE(test, f.dc_plane_state->cm.flags.bits.lut3d_enable);
+}
+
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@@ -2204,6 +2419,10 @@ static struct kunit_case dm_color_test_cases[] = {
KUNIT_CASE(dm_test_update_plane_color_mgmt_maps_crtc_degamma),
KUNIT_CASE(dm_test_update_plane_color_mgmt_uses_color_caps),
KUNIT_CASE(dm_test_update_plane_color_mgmt_plane_ctm),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_colorop_bypass_pipeline),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_colorop_missing_multiplier),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_colorop_missing_3x4),
+ KUNIT_CASE(dm_test_update_plane_color_mgmt_colorop_no_3dlut_hw),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 30/70] drm/amd/display: add KUnit tests for DM IP-block callbacks
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (28 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 29/70] drm/amd/display: Test plane colorop pipeline update Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 31/70] drm/amd/display: add KUnit tests for DM CRTC vblank/scanout Wayne Lin
` (39 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit coverage for the simple amdgpu_dm IP-block callbacks
(is_idle, wait_for_idle, soft_reset, set_clockgating_state,
set_powergating_state and the bandwidth_update display hook) by
asserting their placeholder return values. Also add the shared test
include block used by the amdgpu_dm test suite.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 22 ++++--
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 9 +++
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 73 +++++++++++++++++++
3 files changed, 96 insertions(+), 8 deletions(-)
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 cb10c5fa374e..80778d7e7337 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -224,23 +224,26 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
return 0;
}
-static bool dm_is_idle(struct amdgpu_ip_block *ip_block)
+STATIC_IFN_KUNIT bool dm_is_idle(struct amdgpu_ip_block *ip_block)
{
/* XXX todo */
return true;
}
+EXPORT_IF_KUNIT(dm_is_idle);
-static int dm_wait_for_idle(struct amdgpu_ip_block *ip_block)
+STATIC_IFN_KUNIT int dm_wait_for_idle(struct amdgpu_ip_block *ip_block)
{
/* XXX todo */
return 0;
}
+EXPORT_IF_KUNIT(dm_wait_for_idle);
-static int dm_soft_reset(struct amdgpu_ip_block *ip_block)
+STATIC_IFN_KUNIT int dm_soft_reset(struct amdgpu_ip_block *ip_block)
{
/* XXX todo */
return 0;
}
+EXPORT_IF_KUNIT(dm_soft_reset);
STATIC_IFN_KUNIT bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state)
@@ -310,17 +313,19 @@ static inline bool update_planes_and_stream_adapter(struct dc *dc,
stream_update);
}
-static int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
- enum amd_clockgating_state state)
+STATIC_IFN_KUNIT int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
+ enum amd_clockgating_state state)
{
return 0;
}
+EXPORT_IF_KUNIT(dm_set_clockgating_state);
-static int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
- enum amd_powergating_state state)
+STATIC_IFN_KUNIT int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
+ enum amd_powergating_state state)
{
return 0;
}
+EXPORT_IF_KUNIT(dm_set_powergating_state);
/* Prototypes of private functions */
static int dm_early_init(struct amdgpu_ip_block *ip_block);
@@ -2795,10 +2800,11 @@ static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm)
*
* Calculate and program the display watermarks and line buffer allocation.
*/
-static void dm_bandwidth_update(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT void dm_bandwidth_update(struct amdgpu_device *adev)
{
/* TODO: implement later */
}
+EXPORT_IF_KUNIT(dm_bandwidth_update);
static const struct amdgpu_display_funcs dm_display_funcs = {
.bandwidth_update = dm_bandwidth_update, /* called unconditionally */
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 f753e90bdeda..7bb552d1ddba 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1140,6 +1140,15 @@ void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
struct dc_sink *sink);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+struct amdgpu_ip_block;
+bool dm_is_idle(struct amdgpu_ip_block *ip_block);
+int dm_wait_for_idle(struct amdgpu_ip_block *ip_block);
+int dm_soft_reset(struct amdgpu_ip_block *ip_block);
+int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
+ enum amd_clockgating_state state);
+int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
+ enum amd_powergating_state state);
+void dm_bandwidth_update(struct amdgpu_device *adev);
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,
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 0b29bf0a7d04..d4e37580316f 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
@@ -6,10 +6,76 @@
*/
#include <kunit/test.h>
+#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_writeback.h>
#include "dc.h"
+#include "inc/core_types.h"
+#include "amd_shared.h"
+#include "amdgpu.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
+#include "amdgpu_dm_kunit_test_helpers.h"
+
+/* Tests for simple DM callbacks */
+
+/**
+ * dm_test_is_idle - Test placeholder idle callback returns true
+ * @test: The KUnit test context
+ */
+static void dm_test_is_idle(struct kunit *test)
+{
+ KUNIT_EXPECT_TRUE(test, dm_is_idle(NULL));
+}
+
+/**
+ * dm_test_wait_for_idle - Test placeholder wait-for-idle callback returns success
+ * @test: The KUnit test context
+ */
+static void dm_test_wait_for_idle(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test, dm_wait_for_idle(NULL), 0);
+}
+
+/**
+ * dm_test_soft_reset - Test placeholder soft-reset callback returns success
+ * @test: The KUnit test context
+ */
+static void dm_test_soft_reset(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test, dm_soft_reset(NULL), 0);
+}
+
+/**
+ * dm_test_set_clockgating_state - Test placeholder clockgating callback returns success
+ * @test: The KUnit test context
+ */
+static void dm_test_set_clockgating_state(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test, dm_set_clockgating_state(NULL, AMD_CG_STATE_GATE), 0);
+}
+
+/**
+ * dm_test_set_powergating_state - Test placeholder powergating callback returns success
+ * @test: The KUnit test context
+ */
+static void dm_test_set_powergating_state(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test, dm_set_powergating_state(NULL, AMD_PG_STATE_GATE), 0);
+}
+
+/**
+ * dm_test_bandwidth_update - Test placeholder bandwidth update is callable
+ * @test: The KUnit test context
+ */
+static void dm_test_bandwidth_update(struct kunit *test)
+{
+ dm_bandwidth_update(NULL);
+}
/* Tests for dm_plane_layer_index_cmp() */
@@ -884,6 +950,13 @@ static void dm_test_master_stream_defaults_to_first(struct kunit *test)
}
static struct kunit_case amdgpu_dm_tests[] = {
+ /* Simple DM callbacks */
+ KUNIT_CASE(dm_test_is_idle),
+ KUNIT_CASE(dm_test_wait_for_idle),
+ KUNIT_CASE(dm_test_soft_reset),
+ KUNIT_CASE(dm_test_set_clockgating_state),
+ KUNIT_CASE(dm_test_set_powergating_state),
+ KUNIT_CASE(dm_test_bandwidth_update),
/* dm_plane_layer_index_cmp */
KUNIT_CASE(dm_test_plane_layer_index_cmp_equal),
KUNIT_CASE(dm_test_plane_layer_index_cmp_descending),
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 31/70] drm/amd/display: add KUnit tests for DM CRTC vblank/scanout
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (29 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 30/70] drm/amd/display: add KUnit tests for DM IP-block callbacks Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 32/70] drm/amd/display: add KUnit tests for DM atomic state helpers Wayne Lin
` (38 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for the DM CRTC helpers: the no-writeback and
non-pending writeback paths of amdgpu_dm_crtc_complete_writeback, the
out-of-range and no-stream paths of dm_vblank_get_counter, and the
invalid-CRTC and no-stream paths of dm_crtc_get_scanoutpos.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 112 ++++++++++++++++++
3 files changed, 121 insertions(+), 3 deletions(-)
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 80778d7e7337..4b60d7343dec 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -169,7 +169,7 @@ static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
* @return
* Counter for vertical blanks
*/
-static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+STATIC_IFN_KUNIT u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
{
struct amdgpu_crtc *acrtc = NULL;
@@ -186,9 +186,10 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
return dc_stream_get_vblank_counter(acrtc->dm_irq_params.stream);
}
+EXPORT_IF_KUNIT(dm_vblank_get_counter);
-static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
- u32 *vbl, u32 *position)
+STATIC_IFN_KUNIT int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+ u32 *vbl, u32 *position)
{
u32 v_blank_start = 0, v_blank_end = 0, h_position = 0, v_position = 0;
struct amdgpu_crtc *acrtc = NULL;
@@ -223,6 +224,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
return 0;
}
+EXPORT_IF_KUNIT(dm_crtc_get_scanoutpos);
STATIC_IFN_KUNIT bool dm_is_idle(struct amdgpu_ip_block *ip_block)
{
@@ -4686,6 +4688,7 @@ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc)
return true;
}
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_complete_writeback);
static void dm_clear_writeback(struct amdgpu_display_manager *dm,
struct amdgpu_crtc *acrtc,
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 7bb552d1ddba..cbe95fb3c0d6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1149,6 +1149,9 @@ int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
enum amd_powergating_state state);
void dm_bandwidth_update(struct amdgpu_device *adev);
+u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc);
+int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+ u32 *vbl, u32 *position);
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,
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 d4e37580316f..7b92078d95bc 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
@@ -77,6 +77,112 @@ static void dm_test_bandwidth_update(struct kunit *test)
dm_bandwidth_update(NULL);
}
+/**
+ * dm_test_crtc_complete_writeback_no_connector - Test no writeback connector returns false
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_complete_writeback_no_connector(struct kunit *test)
+{
+ struct amdgpu_crtc *acrtc;
+
+ acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+ KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_complete_writeback(acrtc));
+}
+
+/**
+ * dm_test_crtc_complete_writeback_not_pending - Test non-pending writeback returns false
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_complete_writeback_not_pending(struct kunit *test)
+{
+ struct amdgpu_crtc *acrtc;
+ struct drm_writeback_connector *wb_conn;
+
+ acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
+ wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, wb_conn);
+
+ spin_lock_init(&wb_conn->job_lock);
+ acrtc->wb_conn = wb_conn;
+ acrtc->wb_pending = false;
+
+ KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_complete_writeback(acrtc));
+}
+
+/**
+ * dm_test_vblank_get_counter_out_of_range - Test out-of-range CRTC returns zero
+ * @test: The KUnit test context
+ */
+static void dm_test_vblank_get_counter_out_of_range(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+ adev->mode_info.num_crtc = 1;
+
+ KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 1), 0U);
+}
+
+/**
+ * dm_test_vblank_get_counter_no_stream - Test missing stream returns zero
+ * @test: The KUnit test context
+ */
+static void dm_test_vblank_get_counter_no_stream(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc;
+
+ acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+ adev->mode_info.num_crtc = 1;
+ adev->mode_info.crtcs[0] = acrtc;
+
+ KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 0), 0U);
+}
+
+/**
+ * dm_test_crtc_get_scanoutpos_invalid_crtc - Test invalid CRTC returns -EINVAL
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_get_scanoutpos_invalid_crtc(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ u32 vbl = 0;
+ u32 position = 0;
+
+ adev->mode_info.num_crtc = 1;
+
+ KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, -1, &vbl, &position),
+ -EINVAL);
+ KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 1, &vbl, &position),
+ -EINVAL);
+}
+
+/**
+ * dm_test_crtc_get_scanoutpos_no_stream - Test missing stream returns zero
+ * @test: The KUnit test context
+ */
+static void dm_test_crtc_get_scanoutpos_no_stream(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc;
+ u32 vbl = 0;
+ u32 position = 0;
+
+ acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+ adev->mode_info.num_crtc = 1;
+ adev->mode_info.crtcs[0] = acrtc;
+
+ KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 0, &vbl, &position), 0);
+ KUNIT_EXPECT_EQ(test, vbl, 0U);
+ KUNIT_EXPECT_EQ(test, position, 0U);
+}
+
/* Tests for dm_plane_layer_index_cmp() */
/**
@@ -957,6 +1063,12 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_set_clockgating_state),
KUNIT_CASE(dm_test_set_powergating_state),
KUNIT_CASE(dm_test_bandwidth_update),
+ KUNIT_CASE(dm_test_crtc_complete_writeback_no_connector),
+ KUNIT_CASE(dm_test_crtc_complete_writeback_not_pending),
+ KUNIT_CASE(dm_test_vblank_get_counter_out_of_range),
+ KUNIT_CASE(dm_test_vblank_get_counter_no_stream),
+ KUNIT_CASE(dm_test_crtc_get_scanoutpos_invalid_crtc),
+ KUNIT_CASE(dm_test_crtc_get_scanoutpos_no_stream),
/* dm_plane_layer_index_cmp */
KUNIT_CASE(dm_test_plane_layer_index_cmp_equal),
KUNIT_CASE(dm_test_plane_layer_index_cmp_descending),
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 32/70] drm/amd/display: add KUnit tests for DM atomic state helpers
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (30 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 31/70] drm/amd/display: add KUnit tests for DM CRTC vblank/scanout Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 33/70] drm/amd/display: add KUnit tests for DM stream scaling Wayne Lin
` (37 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for the DM atomic private-state accessors
(dm_atomic_get_new_state, dm_atomic_destroy_state), the native
cursor-mode selector (dm_should_update_native_cursor) and
amdgpu_dm_smu_write_watermarks_table. Cover the empty and matching
private-object lookups, the NULL-context destroy path, the NULL,
native and overlay cursor-mode paths, and the non-Navi1x watermark
table early return.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 20 ++-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 8 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 155 ++++++++++++++++++
3 files changed, 175 insertions(+), 8 deletions(-)
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 4b60d7343dec..7806b3405c3d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1404,7 +1404,7 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
drm_connector_list_iter_end(&iter);
}
-static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
{
int ret = 0;
@@ -1454,6 +1454,7 @@ static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_smu_write_watermarks_table);
static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
{
@@ -2285,7 +2286,7 @@ int dm_atomic_get_state(struct drm_atomic_state *state,
return 0;
}
-static struct dm_atomic_state *
+STATIC_IFN_KUNIT struct dm_atomic_state *
dm_atomic_get_new_state(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
@@ -2302,6 +2303,7 @@ dm_atomic_get_new_state(struct drm_atomic_state *state)
return NULL;
}
+EXPORT_IF_KUNIT(dm_atomic_get_new_state);
static struct drm_private_state *
dm_atomic_duplicate_state(struct drm_private_obj *obj)
@@ -2327,8 +2329,8 @@ dm_atomic_duplicate_state(struct drm_private_obj *obj)
return &new_state->base;
}
-static void dm_atomic_destroy_state(struct drm_private_obj *obj,
- struct drm_private_state *state)
+STATIC_IFN_KUNIT void dm_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
{
struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
@@ -2337,6 +2339,7 @@ static void dm_atomic_destroy_state(struct drm_private_obj *obj,
kfree(dm_state);
}
+EXPORT_IF_KUNIT(dm_atomic_destroy_state);
static struct drm_private_state_funcs dm_atomic_state_funcs = {
.atomic_duplicate_state = dm_atomic_duplicate_state,
@@ -6360,10 +6363,10 @@ static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc,
return 0;
}
-static bool dm_should_update_native_cursor(struct drm_atomic_state *state,
- struct drm_crtc *old_plane_crtc,
- struct drm_crtc *new_plane_crtc,
- bool enable)
+STATIC_IFN_KUNIT bool dm_should_update_native_cursor(struct drm_atomic_state *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;
@@ -6388,6 +6391,7 @@ static bool dm_should_update_native_cursor(struct drm_atomic_state *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_state *state,
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 cbe95fb3c0d6..bef9663caf6e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1152,6 +1152,14 @@ void dm_bandwidth_update(struct amdgpu_device *adev);
u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc);
int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
u32 *vbl, u32 *position);
+struct dm_atomic_state *dm_atomic_get_new_state(struct drm_atomic_state *state);
+void dm_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state);
+int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev);
+bool dm_should_update_native_cursor(struct drm_atomic_state *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,
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 7b92078d95bc..92056f4147d3 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
@@ -183,6 +183,154 @@ static void dm_test_crtc_get_scanoutpos_no_stream(struct kunit *test)
KUNIT_EXPECT_EQ(test, position, 0U);
}
+/**
+ * dm_test_atomic_get_new_state_empty - Test empty atomic state has no DM state
+ * @test: The KUnit test context
+ */
+static void dm_test_atomic_get_new_state_empty(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct drm_atomic_state *state;
+
+ state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, state);
+ state->dev = &adev->ddev;
+
+ KUNIT_EXPECT_NULL(test, dm_atomic_get_new_state(state));
+}
+
+/**
+ * dm_test_atomic_get_new_state_match - Test atomic state returns matching DM private state
+ * @test: The KUnit test context
+ */
+static void dm_test_atomic_get_new_state_match(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dm_atomic_state *dm_state;
+ struct drm_atomic_state *state;
+
+ state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, state);
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ state->private_objs = kunit_kzalloc(test, sizeof(*state->private_objs),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, state->private_objs);
+
+ state->dev = &adev->ddev;
+ state->num_private_objs = 1;
+ state->private_objs[0].ptr = &adev->dm.atomic_obj;
+ state->private_objs[0].new_state = &dm_state->base;
+
+ 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_state *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_state *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
+ */
+static void dm_test_atomic_destroy_state_no_context(struct kunit *test)
+{
+ struct dm_atomic_state *dm_state;
+
+ /*
+ * Use kzalloc(), not kunit_kzalloc(): dm_atomic_destroy_state() frees
+ * the state itself, so KUnit-managed memory would be double-freed.
+ */
+ dm_state = kzalloc(sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ /* context == NULL: dc_state_release() is skipped and the state is freed. */
+ dm_atomic_destroy_state(NULL, &dm_state->base);
+}
+
+/**
+ * dm_test_smu_write_watermarks_table_default - Test watermarks table skips non-Navi1x IP versions
+ * @test: The KUnit test context
+ */
+static void dm_test_smu_write_watermarks_table_default(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+ /*
+ * A zeroed adev reports DCE IP version 0, which is not one of the
+ * Navi1x versions handled by the switch, so the function returns early.
+ */
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_smu_write_watermarks_table(adev), 0);
+}
+
/* Tests for dm_plane_layer_index_cmp() */
/**
@@ -1069,6 +1217,13 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_vblank_get_counter_no_stream),
KUNIT_CASE(dm_test_crtc_get_scanoutpos_invalid_crtc),
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),
+ KUNIT_CASE(dm_test_smu_write_watermarks_table_default),
/* dm_plane_layer_index_cmp */
KUNIT_CASE(dm_test_plane_layer_index_cmp_equal),
KUNIT_CASE(dm_test_plane_layer_index_cmp_descending),
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 33/70] drm/amd/display: add KUnit tests for DM stream scaling
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (31 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 32/70] drm/amd/display: add KUnit tests for DM atomic state helpers Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 34/70] drm/amd/display: add KUnit tests for HDCP state diffing Wayne Lin
` (36 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for the stream scaling path: a disable-underscan case
for is_scaling_state_different, and coverage of
amdgpu_dm_update_stream_scaling_settings across the full-screen
default, RMX_FULL, RMX_ASPECT pillarbox/letterbox, RMX_CENTER and
underscan paths.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 231 ++++++++++++++++++
2 files changed, 232 insertions(+)
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 7806b3405c3d..fc1a73435203 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3456,6 +3456,7 @@ void amdgpu_dm_update_stream_scaling_settings(struct drm_device *dev,
dst.x, dst.y, dst.width, dst.height);
}
+EXPORT_IF_KUNIT(amdgpu_dm_update_stream_scaling_settings);
static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
struct dc_state *dc_state,
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 92056f4147d3..724d03db2736 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
@@ -830,6 +830,28 @@ static void dm_test_scaling_state_underscan_enabled(struct kunit *test)
KUNIT_EXPECT_TRUE(test, is_scaling_state_different(new_state, old_state));
}
+/**
+ * dm_test_scaling_state_underscan_disabled - Test disabling underscan with borders differs
+ * @test: The KUnit test context
+ */
+static void dm_test_scaling_state_underscan_disabled(struct kunit *test)
+{
+ struct dm_connector_state *old_state;
+ struct dm_connector_state *new_state;
+
+ old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
+ new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state);
+ KUNIT_ASSERT_NOT_NULL(test, new_state);
+
+ old_state->underscan_enable = true;
+ old_state->underscan_hborder = 16;
+ old_state->underscan_vborder = 16;
+ new_state->underscan_enable = false;
+
+ KUNIT_EXPECT_TRUE(test, is_scaling_state_different(new_state, old_state));
+}
+
/**
* dm_test_scaling_state_underscan_border_changed - Test changed underscan borders differ
* @test: The KUnit test context
@@ -1203,6 +1225,206 @@ static void dm_test_master_stream_defaults_to_first(struct kunit *test)
stream0);
}
+/* Tests for amdgpu_dm_update_stream_scaling_settings() */
+
+/**
+ * dm_test_update_scaling_null_mode - Test NULL mode leaves the stream rects untouched
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_null_mode(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+
+ stream->timing.h_addressable = 1920;
+ stream->timing.v_addressable = 1080;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, NULL, NULL, stream);
+
+ /* NULL mode: early return before touching src/dst */
+ KUNIT_EXPECT_EQ(test, stream->src.width, 0);
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 0);
+}
+
+/**
+ * dm_test_update_scaling_fullscreen_default - Test full-screen default with no dm_state
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_fullscreen_default(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+ struct drm_display_mode mode = { 0 };
+
+ mode.hdisplay = 1920;
+ mode.vdisplay = 1080;
+ stream->timing.h_addressable = 2560;
+ stream->timing.v_addressable = 1440;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, &mode, NULL, stream);
+
+ /* src = mode, dst = timing addressable, no centering without dm_state */
+ KUNIT_EXPECT_EQ(test, stream->src.width, 1920);
+ KUNIT_EXPECT_EQ(test, stream->src.height, 1080);
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 2560);
+ KUNIT_EXPECT_EQ(test, stream->dst.height, 1440);
+ KUNIT_EXPECT_EQ(test, stream->dst.x, 0);
+ KUNIT_EXPECT_EQ(test, stream->dst.y, 0);
+}
+
+/**
+ * dm_test_update_scaling_rmx_full - Test RMX_FULL keeps a full-size, centered dst
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_rmx_full(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+ struct dm_connector_state *dm_state;
+ struct drm_display_mode mode = { 0 };
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ mode.hdisplay = 1280;
+ mode.vdisplay = 720;
+ stream->timing.h_addressable = 1920;
+ stream->timing.v_addressable = 1080;
+ dm_state->scaling = RMX_FULL;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, &mode, dm_state, stream);
+
+ /* RMX_FULL: dst stays full addressable, offset 0 */
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 1920);
+ KUNIT_EXPECT_EQ(test, stream->dst.height, 1080);
+ KUNIT_EXPECT_EQ(test, stream->dst.x, 0);
+ KUNIT_EXPECT_EQ(test, stream->dst.y, 0);
+}
+
+/**
+ * dm_test_update_scaling_rmx_aspect_pillarbox - Test RMX_ASPECT preserves aspect ratio
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_rmx_aspect_pillarbox(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+ struct dm_connector_state *dm_state;
+ struct drm_display_mode mode = { 0 };
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ /* 4:3 source on a 16:9 panel -> pillarboxed */
+ mode.hdisplay = 1024;
+ mode.vdisplay = 768;
+ stream->timing.h_addressable = 1920;
+ stream->timing.v_addressable = 1080;
+ dm_state->scaling = RMX_ASPECT;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, &mode, dm_state, stream);
+
+ /*
+ * src.width*dst.height (1024*1080) < src.height*dst.width (768*1920):
+ * width scaled to src.width*dst.height/src.height = 1440, height stays
+ * 1080, centered horizontally at (1920-1440)/2 = 240.
+ */
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 1440);
+ KUNIT_EXPECT_EQ(test, stream->dst.height, 1080);
+ KUNIT_EXPECT_EQ(test, stream->dst.x, 240);
+ KUNIT_EXPECT_EQ(test, stream->dst.y, 0);
+}
+
+/**
+ * dm_test_update_scaling_rmx_aspect_letterbox - Test RMX_ASPECT letterboxes wide sources
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_rmx_aspect_letterbox(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+ struct dm_connector_state *dm_state;
+ struct drm_display_mode mode = { 0 };
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ /* 16:9 source on a 4:3 panel -> letterboxed */
+ mode.hdisplay = 1920;
+ mode.vdisplay = 1080;
+ stream->timing.h_addressable = 1024;
+ stream->timing.v_addressable = 768;
+ dm_state->scaling = RMX_ASPECT;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, &mode, dm_state, stream);
+
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 1024);
+ KUNIT_EXPECT_EQ(test, stream->dst.height, 576);
+ KUNIT_EXPECT_EQ(test, stream->dst.x, 0);
+ KUNIT_EXPECT_EQ(test, stream->dst.y, 96);
+}
+
+/**
+ * dm_test_update_scaling_rmx_center - Test RMX_CENTER centers a 1:1 dst
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_rmx_center(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+ struct dm_connector_state *dm_state;
+ struct drm_display_mode mode = { 0 };
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ mode.hdisplay = 1280;
+ mode.vdisplay = 720;
+ stream->timing.h_addressable = 1920;
+ stream->timing.v_addressable = 1080;
+ dm_state->scaling = RMX_CENTER;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, &mode, dm_state, stream);
+
+ /* RMX_CENTER: dst = src, centered on the addressable area */
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 1280);
+ KUNIT_EXPECT_EQ(test, stream->dst.height, 720);
+ KUNIT_EXPECT_EQ(test, stream->dst.x, 320);
+ KUNIT_EXPECT_EQ(test, stream->dst.y, 180);
+}
+
+/**
+ * dm_test_update_scaling_underscan - Test underscan borders shrink and offset dst
+ * @test: The KUnit test context
+ */
+static void dm_test_update_scaling_underscan(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL);
+ struct dm_connector_state *dm_state;
+ struct drm_display_mode mode = { 0 };
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ mode.hdisplay = 1920;
+ mode.vdisplay = 1080;
+ stream->timing.h_addressable = 1920;
+ stream->timing.v_addressable = 1080;
+ dm_state->scaling = RMX_FULL;
+ dm_state->underscan_enable = true;
+ dm_state->underscan_hborder = 64;
+ dm_state->underscan_vborder = 32;
+
+ amdgpu_dm_update_stream_scaling_settings(&adev->ddev, &mode, dm_state, stream);
+
+ /* Full dst, then underscan: x/y += border/2, width/height -= border */
+ KUNIT_EXPECT_EQ(test, stream->dst.x, 32);
+ KUNIT_EXPECT_EQ(test, stream->dst.y, 16);
+ KUNIT_EXPECT_EQ(test, stream->dst.width, 1856);
+ KUNIT_EXPECT_EQ(test, stream->dst.height, 1048);
+}
+
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_is_idle),
@@ -1254,6 +1476,7 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_scaling_state_same),
KUNIT_CASE(dm_test_scaling_state_scaling_changed),
KUNIT_CASE(dm_test_scaling_state_underscan_enabled),
+ KUNIT_CASE(dm_test_scaling_state_underscan_disabled),
KUNIT_CASE(dm_test_scaling_state_underscan_border_changed),
/* is_timing_unchanged_for_freesync */
KUNIT_CASE(dm_test_timing_unchanged_null_args),
@@ -1274,6 +1497,14 @@ static struct kunit_case amdgpu_dm_tests[] = {
/* set_master_stream */
KUNIT_CASE(dm_test_master_stream_highest_refresh),
KUNIT_CASE(dm_test_master_stream_defaults_to_first),
+ /* amdgpu_dm_update_stream_scaling_settings */
+ KUNIT_CASE(dm_test_update_scaling_null_mode),
+ KUNIT_CASE(dm_test_update_scaling_fullscreen_default),
+ KUNIT_CASE(dm_test_update_scaling_rmx_full),
+ KUNIT_CASE(dm_test_update_scaling_rmx_aspect_pillarbox),
+ KUNIT_CASE(dm_test_update_scaling_rmx_aspect_letterbox),
+ KUNIT_CASE(dm_test_update_scaling_rmx_center),
+ KUNIT_CASE(dm_test_update_scaling_underscan),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 34/70] drm/amd/display: add KUnit tests for HDCP state diffing
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (32 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 33/70] drm/amd/display: add KUnit tests for DM stream scaling Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 35/70] drm/amd/display: add KUnit tests for freesync config Wayne Lin
` (35 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for is_content_protection_different using a shared
connector/crtc fixture. Cover the content-type change, ENABLED->DESIRED
re-enable (with and without modeset), UNDESIRED and DESIRED steady
states, the update_hdcp hot-plug and stream re-enable paths, and the
S3/DESIRED/UNDESIRED enable transitions.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 237 ++++++++++++++++++
3 files changed, 252 insertions(+), 6 deletions(-)
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 fc1a73435203..03b9079ce818 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3653,12 +3653,13 @@ is_scaling_state_different(const struct dm_connector_state *dm_state,
}
EXPORT_IF_KUNIT(is_scaling_state_different);
-static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
- struct drm_crtc_state *old_crtc_state,
- struct drm_connector_state *new_conn_state,
- struct drm_connector_state *old_conn_state,
- const struct drm_connector *connector,
- struct hdcp_workqueue *hdcp_w)
+STATIC_IFN_KUNIT bool
+is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+ struct drm_crtc_state *old_crtc_state,
+ struct drm_connector_state *new_conn_state,
+ struct drm_connector_state *old_conn_state,
+ const struct drm_connector *connector,
+ struct hdcp_workqueue *hdcp_w)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
@@ -3772,6 +3773,7 @@ static bool is_content_protection_different(struct drm_crtc_state *new_crtc_stat
pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__);
return false;
}
+EXPORT_IF_KUNIT(is_content_protection_different);
static void remove_stream(struct amdgpu_device *adev,
struct amdgpu_crtc *acrtc,
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 bef9663caf6e..c508f0be1b55 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1178,6 +1178,13 @@ bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state);
void set_multisync_trigger_params(struct dc_stream_state *stream);
void set_master_stream(struct dc_stream_state *stream_set[], int stream_count);
+struct hdcp_workqueue;
+bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+ struct drm_crtc_state *old_crtc_state,
+ struct drm_connector_state *new_conn_state,
+ struct drm_connector_state *old_conn_state,
+ const struct drm_connector *connector,
+ struct hdcp_workqueue *hdcp_w);
#endif
#endif /* __AMDGPU_DM_H__ */
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 724d03db2736..1caacad43106 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
@@ -1425,6 +1425,231 @@ static void dm_test_update_scaling_underscan(struct kunit *test)
KUNIT_EXPECT_EQ(test, stream->dst.height, 1048);
}
+/* Tests for is_content_protection_different() */
+
+struct dm_test_cp_ctx {
+ struct amdgpu_dm_connector *aconnector;
+ struct dm_connector_state *new_dm; /* also connector->state */
+ struct dm_connector_state *old_dm;
+ struct drm_crtc_state *new_crtc;
+ struct drm_crtc_state *old_crtc;
+};
+
+static struct dm_test_cp_ctx *dm_test_cp_ctx_alloc(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ ctx->new_dm = kunit_kzalloc(test, sizeof(*ctx->new_dm), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->new_dm);
+ ctx->old_dm = kunit_kzalloc(test, sizeof(*ctx->old_dm), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->old_dm);
+ ctx->new_crtc = kunit_kzalloc(test, sizeof(*ctx->new_crtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->new_crtc);
+ ctx->old_crtc = kunit_kzalloc(test, sizeof(*ctx->old_crtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->old_crtc);
+
+ /* connector->state must be the new dm connector state */
+ ctx->aconnector->base.state = &ctx->new_dm->base;
+ ctx->aconnector->base.dpms = DRM_MODE_DPMS_ON;
+
+ return ctx;
+}
+
+static bool dm_test_cp_diff(struct dm_test_cp_ctx *ctx)
+{
+ return is_content_protection_different(ctx->new_crtc, ctx->old_crtc,
+ &ctx->new_dm->base,
+ &ctx->old_dm->base,
+ &ctx->aconnector->base, NULL);
+}
+
+/**
+ * dm_test_cp_diff_hdcp_type_change - Test an HDCP content-type change forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_hdcp_type_change(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.hdcp_content_type = 0;
+ ctx->new_dm->base.hdcp_content_type = 1;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+ KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+ (int)DRM_MODE_CONTENT_PROTECTION_DESIRED);
+}
+
+/**
+ * dm_test_cp_diff_reenable_mode_changed - Test ENABLED->DESIRED with modeset forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_reenable_mode_changed(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_crtc->mode_changed = true;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+ KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+ (int)DRM_MODE_CONTENT_PROTECTION_DESIRED);
+}
+
+/**
+ * dm_test_cp_diff_reenable_no_change - Test ENABLED->DESIRED without modeset restores ENABLED
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_reenable_no_change(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_crtc->mode_changed = false;
+
+ KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+ KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+ (int)DRM_MODE_CONTENT_PROTECTION_ENABLED);
+}
+
+/**
+ * dm_test_cp_diff_undesired - Test UNDESIRED->UNDESIRED needs no update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_undesired(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+
+ KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_desired_mode_changed - Test DESIRED->DESIRED with modeset forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_mode_changed(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_crtc->mode_changed = true;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_desired_no_change - Test steady DESIRED->DESIRED needs no update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_no_change(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_crtc->mode_changed = false;
+
+ KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_update_hdcp_hotplug - Test the update_hdcp hot-plug path forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_update_hdcp_hotplug(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+ struct dc_sink *sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->update_hdcp = true;
+ ctx->aconnector->base.dpms = DRM_MODE_DPMS_ON;
+ ctx->aconnector->dc_sink = sink;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+ KUNIT_EXPECT_FALSE(test, ctx->new_dm->update_hdcp);
+}
+
+/**
+ * dm_test_cp_diff_stream_reenabled - Test the stream removed-and-re-enabled path forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_stream_reenabled(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+ struct drm_crtc *crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
+ crtc->enabled = true;
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->update_hdcp = true;
+ ctx->old_dm->base.crtc = NULL;
+ ctx->new_dm->base.crtc = crtc;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+ KUNIT_EXPECT_FALSE(test, ctx->new_dm->update_hdcp);
+}
+
+/**
+ * dm_test_cp_diff_s3_undesired_to_enabled - Test the S3 UNDESIRED->ENABLED path forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_s3_undesired_to_enabled(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+ KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+ (int)DRM_MODE_CONTENT_PROTECTION_DESIRED);
+}
+
+/**
+ * dm_test_cp_diff_desired_to_enabled - Test DESIRED->ENABLED needs no update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_to_enabled(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+ KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_desired_to_undesired - Test DESIRED->UNDESIRED forces update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_to_undesired(struct kunit *test)
+{
+ struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+ ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+
+ KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+}
+
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_is_idle),
@@ -1505,6 +1730,18 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_update_scaling_rmx_aspect_letterbox),
KUNIT_CASE(dm_test_update_scaling_rmx_center),
KUNIT_CASE(dm_test_update_scaling_underscan),
+ /* is_content_protection_different */
+ KUNIT_CASE(dm_test_cp_diff_hdcp_type_change),
+ KUNIT_CASE(dm_test_cp_diff_reenable_mode_changed),
+ KUNIT_CASE(dm_test_cp_diff_reenable_no_change),
+ KUNIT_CASE(dm_test_cp_diff_undesired),
+ KUNIT_CASE(dm_test_cp_diff_desired_mode_changed),
+ KUNIT_CASE(dm_test_cp_diff_desired_no_change),
+ KUNIT_CASE(dm_test_cp_diff_update_hdcp_hotplug),
+ KUNIT_CASE(dm_test_cp_diff_stream_reenabled),
+ KUNIT_CASE(dm_test_cp_diff_s3_undesired_to_enabled),
+ KUNIT_CASE(dm_test_cp_diff_desired_to_enabled),
+ KUNIT_CASE(dm_test_cp_diff_desired_to_undesired),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 35/70] drm/amd/display: add KUnit tests for freesync config
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (33 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 34/70] drm/amd/display: add KUnit tests for HDCP state diffing Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 36/70] drm/amd/display: add KUnit tests for per-frame master sync Wayne Lin
` (34 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for get_freesync_config_for_crtc and
reset_freesync_config_for_crtc using a shared connector/crtc/stream
fixture. Cover the writeback early return, the not-capable and
out-of-range unsupported paths, the active-variable, inactive and
active-fixed states, and the config reset.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 197 ++++++++++++++++++
3 files changed, 205 insertions(+), 3 deletions(-)
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 03b9079ce818..fa0add5bcabf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -126,7 +126,7 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
/* basic init/fini API */
static int amdgpu_dm_init(struct amdgpu_device *adev);
static void amdgpu_dm_fini(struct amdgpu_device *adev);
-static void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
+STATIC_IFN_KUNIT void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
/*
* initializes drm_device display related structures, based on the information
@@ -5733,7 +5733,7 @@ static int do_aquire_global_lock(struct drm_device *dev,
return ret < 0 ? ret : 0;
}
-static void get_freesync_config_for_crtc(
+STATIC_IFN_KUNIT void get_freesync_config_for_crtc(
struct dm_crtc_state *new_crtc_state,
struct dm_connector_state *new_con_state)
{
@@ -5776,8 +5776,9 @@ static void get_freesync_config_for_crtc(
out:
new_crtc_state->freesync_config = config;
}
+EXPORT_IF_KUNIT(get_freesync_config_for_crtc);
-static void reset_freesync_config_for_crtc(
+STATIC_IFN_KUNIT void reset_freesync_config_for_crtc(
struct dm_crtc_state *new_crtc_state)
{
new_crtc_state->vrr_supported = false;
@@ -5785,6 +5786,7 @@ static void reset_freesync_config_for_crtc(
memset(&new_crtc_state->vrr_infopacket, 0,
sizeof(new_crtc_state->vrr_infopacket));
}
+EXPORT_IF_KUNIT(reset_freesync_config_for_crtc);
STATIC_IFN_KUNIT bool
is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
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 c508f0be1b55..29cefa4d8468 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1178,6 +1178,9 @@ bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state);
void set_multisync_trigger_params(struct dc_stream_state *stream);
void set_master_stream(struct dc_stream_state *stream_set[], int stream_count);
+void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
+void get_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state,
+ struct dm_connector_state *new_con_state);
struct hdcp_workqueue;
bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
struct drm_crtc_state *old_crtc_state,
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 1caacad43106..1464eeda704b 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
@@ -1650,6 +1650,194 @@ static void dm_test_cp_diff_desired_to_undesired(struct kunit *test)
KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
}
+/* Tests for get_freesync_config_for_crtc() */
+
+struct dm_test_freesync_ctx {
+ struct amdgpu_dm_connector *aconnector;
+ struct dm_crtc_state *crtc_state;
+ struct dm_connector_state *conn_state;
+ struct dc_stream_state *stream;
+};
+
+static struct dm_test_freesync_ctx *dm_test_freesync_ctx_alloc(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+ ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
+ ctx->stream = dm_kunit_alloc_stream(test, NULL);
+
+ ctx->conn_state->base.connector = &ctx->aconnector->base;
+ ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_DisplayPort;
+ ctx->crtc_state->stream = ctx->stream;
+
+ /* 1080p60 timing so drm_mode_vrefresh() == 60 */
+ ctx->crtc_state->base.mode.clock = 148500;
+ ctx->crtc_state->base.mode.htotal = 2200;
+ ctx->crtc_state->base.mode.vtotal = 1125;
+
+ return ctx;
+}
+
+/**
+ * dm_test_freesync_config_writeback - Test writeback connector is left untouched
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_writeback(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+ ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_WRITEBACK;
+ ctx->conn_state->freesync_capable = true;
+ ctx->aconnector->min_vfreq = 48;
+ ctx->aconnector->max_vfreq = 120;
+ ctx->crtc_state->vrr_supported = true; /* sentinel: must stay set */
+
+ get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+ /* Writeback: early return leaves vrr_supported sentinel untouched */
+ KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+}
+
+/**
+ * dm_test_freesync_config_not_capable - Test a non-freesync sink reports UNSUPPORTED
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_not_capable(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+ ctx->conn_state->freesync_capable = false;
+ ctx->aconnector->min_vfreq = 48;
+ ctx->aconnector->max_vfreq = 120;
+
+ get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+ KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
+ KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+ (int)VRR_STATE_UNSUPPORTED);
+}
+
+/**
+ * dm_test_freesync_config_out_of_range - Test a refresh outside the range is UNSUPPORTED
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_out_of_range(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+ ctx->conn_state->freesync_capable = true;
+ ctx->aconnector->min_vfreq = 90; /* 60 < 90 -> out of range */
+ ctx->aconnector->max_vfreq = 120;
+
+ get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+ KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
+ KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+ (int)VRR_STATE_UNSUPPORTED);
+}
+
+/**
+ * dm_test_freesync_config_active_variable - Test vrr_enabled yields ACTIVE_VARIABLE
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_active_variable(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+ ctx->conn_state->freesync_capable = true;
+ ctx->aconnector->min_vfreq = 48;
+ ctx->aconnector->max_vfreq = 120;
+ ctx->crtc_state->base.vrr_enabled = true;
+
+ get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+ KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+ KUNIT_EXPECT_TRUE(test, ctx->stream->ignore_msa_timing_param);
+ KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+ (int)VRR_STATE_ACTIVE_VARIABLE);
+ KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.min_refresh_in_uhz,
+ 48000000U);
+ KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.max_refresh_in_uhz,
+ 120000000U);
+ KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.vsif_supported);
+ KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.btr);
+}
+
+/**
+ * dm_test_freesync_config_inactive - Test supported-but-off yields INACTIVE
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_inactive(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+ ctx->conn_state->freesync_capable = true;
+ ctx->aconnector->min_vfreq = 48;
+ ctx->aconnector->max_vfreq = 120;
+ ctx->crtc_state->base.vrr_enabled = false;
+
+ get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+ KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+ KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+ (int)VRR_STATE_INACTIVE);
+}
+
+/**
+ * dm_test_freesync_config_active_fixed - Test freesync-video mode yields ACTIVE_FIXED
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_active_fixed(struct kunit *test)
+{
+ struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+ ctx->conn_state->freesync_capable = true;
+ ctx->aconnector->min_vfreq = 48;
+ ctx->aconnector->max_vfreq = 120;
+ /* Pre-set fixed state selects the freesync-video (fixed) path */
+ ctx->crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
+ ctx->crtc_state->freesync_config.fixed_refresh_in_uhz = 60000000;
+ ctx->crtc_state->base.vrr_enabled = true; /* ignored on the fixed path */
+
+ get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+ KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+ KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+ (int)VRR_STATE_ACTIVE_FIXED);
+ KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.fixed_refresh_in_uhz,
+ 60000000U);
+}
+
+/* Tests for reset_freesync_config_for_crtc() */
+
+/**
+ * dm_test_reset_freesync_config - Test reset clears vrr support and info packet
+ * @test: The KUnit test context
+ */
+static void dm_test_reset_freesync_config(struct kunit *test)
+{
+ struct dm_crtc_state *crtc_state;
+
+ crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, crtc_state);
+
+ crtc_state->vrr_supported = true;
+ crtc_state->vrr_infopacket.valid = true;
+
+ reset_freesync_config_for_crtc(crtc_state);
+
+ KUNIT_EXPECT_FALSE(test, crtc_state->vrr_supported);
+ KUNIT_EXPECT_FALSE(test, crtc_state->vrr_infopacket.valid);
+}
+
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_is_idle),
@@ -1742,6 +1930,15 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_cp_diff_s3_undesired_to_enabled),
KUNIT_CASE(dm_test_cp_diff_desired_to_enabled),
KUNIT_CASE(dm_test_cp_diff_desired_to_undesired),
+ /* get_freesync_config_for_crtc */
+ KUNIT_CASE(dm_test_freesync_config_writeback),
+ KUNIT_CASE(dm_test_freesync_config_not_capable),
+ KUNIT_CASE(dm_test_freesync_config_out_of_range),
+ KUNIT_CASE(dm_test_freesync_config_active_variable),
+ KUNIT_CASE(dm_test_freesync_config_inactive),
+ KUNIT_CASE(dm_test_freesync_config_active_fixed),
+ /* reset_freesync_config_for_crtc */
+ KUNIT_CASE(dm_test_reset_freesync_config),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 36/70] drm/amd/display: add KUnit tests for per-frame master sync
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (34 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 35/70] drm/amd/display: add KUnit tests for freesync config Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 37/70] drm/amd/display: add KUnit tests for stutter quirk Wayne Lin
` (33 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for dm_enable_per_frame_crtc_master_sync covering the
single-stream no-op, the two-stream master selection with trigger
parameters, and the NULL-stream skip path.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 103 ++++++++++++++++++
3 files changed, 107 insertions(+), 2 deletions(-)
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 fa0add5bcabf..8fe7e125e14a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -141,7 +141,7 @@ static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm);
static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_state *state);
static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
-static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
+STATIC_IFN_KUNIT void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state);
@@ -5342,7 +5342,7 @@ STATIC_IFN_KUNIT void set_master_stream(struct dc_stream_state *stream_set[],
}
EXPORT_IF_KUNIT(set_master_stream);
-static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
+STATIC_IFN_KUNIT void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
{
int i = 0;
struct dc_stream_state *stream;
@@ -5370,6 +5370,7 @@ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
set_multisync_trigger_params(stream);
}
}
+EXPORT_IF_KUNIT(dm_enable_per_frame_crtc_master_sync);
/**
* amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
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 29cefa4d8468..897434504459 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1181,6 +1181,7 @@ void set_master_stream(struct dc_stream_state *stream_set[], int stream_count);
void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
void get_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state,
struct dm_connector_state *new_con_state);
+void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
struct hdcp_workqueue;
bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
struct drm_crtc_state *old_crtc_state,
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 1464eeda704b..b988198418c6 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
@@ -1838,6 +1838,105 @@ static void dm_test_reset_freesync_config(struct kunit *test)
KUNIT_EXPECT_FALSE(test, crtc_state->vrr_infopacket.valid);
}
+/* Tests for dm_enable_per_frame_crtc_master_sync() */
+
+/**
+ * dm_test_per_frame_master_sync_single_stream - Test fewer than two streams is a no-op
+ * @test: The KUnit test context
+ */
+static void dm_test_per_frame_master_sync_single_stream(struct kunit *test)
+{
+ struct dc_state *context;
+ struct dc_stream_state *stream;
+
+ context = kunit_kzalloc(test, sizeof(*context), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, context);
+ stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+
+ stream->triggered_crtc_reset.enabled = true;
+ context->streams[0] = stream;
+ context->stream_count = 1;
+
+ dm_enable_per_frame_crtc_master_sync(context);
+
+ /* < 2 streams: early return, event_source stays NULL */
+ KUNIT_EXPECT_NULL(test, stream->triggered_crtc_reset.event_source);
+}
+
+/**
+ * dm_test_per_frame_master_sync_two_streams - Test the master is picked and applied
+ * @test: The KUnit test context
+ */
+static void dm_test_per_frame_master_sync_two_streams(struct kunit *test)
+{
+ struct dc_state *context;
+ struct dc_stream_state *stream0, *stream1;
+
+ context = kunit_kzalloc(test, sizeof(*context), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, context);
+ stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, stream0);
+ stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, stream1);
+
+ /* stream0 60Hz, stream1 120Hz, both trigger-reset enabled */
+ stream0->triggered_crtc_reset.enabled = true;
+ stream0->timing.pix_clk_100hz = 1485000;
+ stream0->timing.h_total = 2200;
+ stream0->timing.v_total = 1125;
+ stream1->triggered_crtc_reset.enabled = true;
+ stream1->timing.pix_clk_100hz = 2970000;
+ stream1->timing.h_total = 2200;
+ stream1->timing.v_total = 1125;
+ stream1->timing.flags.VSYNC_POSITIVE_POLARITY = 1;
+
+ context->streams[0] = stream0;
+ context->streams[1] = stream1;
+ context->stream_count = 2;
+
+ dm_enable_per_frame_crtc_master_sync(context);
+
+ /* set_master_stream picks the highest refresh (stream1) as event source */
+ KUNIT_EXPECT_PTR_EQ(test, stream0->triggered_crtc_reset.event_source,
+ stream1);
+ KUNIT_EXPECT_PTR_EQ(test, stream1->triggered_crtc_reset.event_source,
+ stream1);
+ /* set_multisync_trigger_params applied to enabled streams */
+ KUNIT_EXPECT_EQ(test, (int)stream0->triggered_crtc_reset.event,
+ (int)CRTC_EVENT_VSYNC_RISING);
+ KUNIT_EXPECT_EQ(test, (int)stream0->triggered_crtc_reset.delay,
+ (int)TRIGGER_DELAY_NEXT_PIXEL);
+}
+
+/**
+ * dm_test_per_frame_master_sync_skips_null_stream - Test NULL stream entries are skipped
+ * @test: The KUnit test context
+ */
+static void dm_test_per_frame_master_sync_skips_null_stream(struct kunit *test)
+{
+ struct dc_state *context;
+ struct dc_stream_state *stream;
+
+ context = kunit_kzalloc(test, sizeof(*context), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, context);
+ stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+
+ stream->triggered_crtc_reset.enabled = true;
+ stream->timing.pix_clk_100hz = 1485000;
+ stream->timing.h_total = 2200;
+ stream->timing.v_total = 1125;
+ context->streams[0] = stream;
+ context->streams[1] = NULL;
+ context->stream_count = 2;
+
+ dm_enable_per_frame_crtc_master_sync(context);
+
+ KUNIT_EXPECT_PTR_EQ(test, stream->triggered_crtc_reset.event_source,
+ stream);
+}
+
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_is_idle),
@@ -1939,6 +2038,10 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_freesync_config_active_fixed),
/* reset_freesync_config_for_crtc */
KUNIT_CASE(dm_test_reset_freesync_config),
+ /* dm_enable_per_frame_crtc_master_sync */
+ KUNIT_CASE(dm_test_per_frame_master_sync_single_stream),
+ KUNIT_CASE(dm_test_per_frame_master_sync_two_streams),
+ KUNIT_CASE(dm_test_per_frame_master_sync_skips_null_stream),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 37/70] drm/amd/display: add KUnit tests for stutter quirk
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (35 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 36/70] drm/amd/display: add KUnit tests for per-frame master sync Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 38/70] drm/amd/display: add KUnit tests for DPCD poweroff delay Wayne Lin
` (32 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for dm_should_disable_stutter covering a full quirk
match, a non-matching device, and a partial match that differs only in
the PCI revision.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 64 +++++++++++++++++++
3 files changed, 68 insertions(+), 1 deletion(-)
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 8fe7e125e14a..8195ca386419 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -424,7 +424,7 @@ static const struct amdgpu_stutter_quirk amdgpu_stutter_quirk_list[] = {
{ 0, 0, 0, 0, 0 },
};
-static bool dm_should_disable_stutter(struct pci_dev *pdev)
+STATIC_IFN_KUNIT bool dm_should_disable_stutter(struct pci_dev *pdev)
{
const struct amdgpu_stutter_quirk *p = amdgpu_stutter_quirk_list;
@@ -440,6 +440,7 @@ static bool dm_should_disable_stutter(struct pci_dev *pdev)
}
return false;
}
+EXPORT_IF_KUNIT(dm_should_disable_stutter);
void*
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 897434504459..84c0bcfc093f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1178,6 +1178,8 @@ bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
struct dm_crtc_state *new_state);
void set_multisync_trigger_params(struct dc_stream_state *stream);
void set_master_stream(struct dc_stream_state *stream_set[], int stream_count);
+struct pci_dev;
+bool dm_should_disable_stutter(struct pci_dev *pdev);
void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
void get_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state,
struct dm_connector_state *new_con_state);
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 b988198418c6..dfdef08343a4 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
@@ -1937,6 +1937,66 @@ static void dm_test_per_frame_master_sync_skips_null_stream(struct kunit *test)
stream);
}
+/* Tests for dm_should_disable_stutter() */
+
+/**
+ * dm_test_should_disable_stutter_match - Test the quirk device matches
+ * @test: The KUnit test context
+ */
+static void dm_test_should_disable_stutter_match(struct kunit *test)
+{
+ struct pci_dev *pdev;
+
+ pdev = kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, pdev);
+
+ pdev->vendor = 0x1002;
+ pdev->device = 0x15dd;
+ pdev->subsystem_vendor = 0x1002;
+ pdev->subsystem_device = 0x15dd;
+ pdev->revision = 0xc8;
+
+ KUNIT_EXPECT_TRUE(test, dm_should_disable_stutter(pdev));
+}
+
+/**
+ * dm_test_should_disable_stutter_no_match - Test a non-quirk device does not match
+ * @test: The KUnit test context
+ */
+static void dm_test_should_disable_stutter_no_match(struct kunit *test)
+{
+ struct pci_dev *pdev;
+
+ pdev = kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, pdev);
+
+ pdev->vendor = 0x1002;
+ pdev->device = 0x1234;
+
+ KUNIT_EXPECT_FALSE(test, dm_should_disable_stutter(pdev));
+}
+
+/**
+ * dm_test_should_disable_stutter_revision_differs - Test a partial match (revision) fails
+ * @test: The KUnit test context
+ */
+static void dm_test_should_disable_stutter_revision_differs(struct kunit *test)
+{
+ struct pci_dev *pdev;
+
+ pdev = kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, pdev);
+
+ /* Everything matches the quirk except the revision */
+ pdev->vendor = 0x1002;
+ pdev->device = 0x15dd;
+ pdev->subsystem_vendor = 0x1002;
+ pdev->subsystem_device = 0x15dd;
+ pdev->revision = 0x00;
+
+ KUNIT_EXPECT_FALSE(test, dm_should_disable_stutter(pdev));
+}
+
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_is_idle),
@@ -2042,6 +2102,10 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_per_frame_master_sync_single_stream),
KUNIT_CASE(dm_test_per_frame_master_sync_two_streams),
KUNIT_CASE(dm_test_per_frame_master_sync_skips_null_stream),
+ /* dm_should_disable_stutter */
+ KUNIT_CASE(dm_test_should_disable_stutter_match),
+ KUNIT_CASE(dm_test_should_disable_stutter_no_match),
+ KUNIT_CASE(dm_test_should_disable_stutter_revision_differs),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 38/70] drm/amd/display: add KUnit tests for DPCD poweroff delay
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (36 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 37/70] drm/amd/display: add KUnit tests for stutter quirk Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 39/70] drm/amd/display: add CRC source list KUnit coverage Wayne Lin
` (31 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for amdgpu_dm_apply_delay_after_dpcd_poweroff covering
the NULL-sink early return, the zero-wait skip path, and the non-zero
wait interval.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 +
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 48 +++++++++++++++++++
2 files changed, 49 insertions(+)
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 8195ca386419..9a3f78c17a5a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1919,6 +1919,7 @@ void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
ppatch->wait_after_dpcd_poweroff_ms / 1000);
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_apply_delay_after_dpcd_poweroff);
/**
* amdgpu_dm_dump_links_and_sinks - Debug dump of all DC links and their sinks
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 dfdef08343a4..c1a00e0e94a1 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
@@ -1997,6 +1997,50 @@ static void dm_test_should_disable_stutter_revision_differs(struct kunit *test)
KUNIT_EXPECT_FALSE(test, dm_should_disable_stutter(pdev));
}
+/* Tests for amdgpu_dm_apply_delay_after_dpcd_poweroff() */
+
+/**
+ * dm_test_apply_delay_null_sink - Test a NULL sink returns without delay
+ * @test: The KUnit test context
+ */
+static void dm_test_apply_delay_null_sink(struct kunit *test)
+{
+ /* NULL sink: early return, no delay, no dereference */
+ amdgpu_dm_apply_delay_after_dpcd_poweroff(NULL, NULL);
+}
+
+/**
+ * dm_test_apply_delay_zero_wait - Test a zero wait interval skips the delay
+ * @test: The KUnit test context
+ */
+static void dm_test_apply_delay_zero_wait(struct kunit *test)
+{
+ struct dc_sink *sink;
+
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+
+ /* wait == 0: no msleep, adev is unused so NULL is safe */
+ sink->edid_caps.panel_patch.wait_after_dpcd_poweroff_ms = 0;
+ amdgpu_dm_apply_delay_after_dpcd_poweroff(NULL, sink);
+}
+
+/**
+ * dm_test_apply_delay_nonzero_wait - Test a non-zero wait interval executes delay path
+ * @test: The KUnit test context
+ */
+static void dm_test_apply_delay_nonzero_wait(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct dc_sink *sink;
+
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+
+ sink->edid_caps.panel_patch.wait_after_dpcd_poweroff_ms = 1;
+ amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, sink);
+}
+
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_is_idle),
@@ -2106,6 +2150,10 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_should_disable_stutter_match),
KUNIT_CASE(dm_test_should_disable_stutter_no_match),
KUNIT_CASE(dm_test_should_disable_stutter_revision_differs),
+ /* amdgpu_dm_apply_delay_after_dpcd_poweroff */
+ KUNIT_CASE(dm_test_apply_delay_null_sink),
+ KUNIT_CASE(dm_test_apply_delay_zero_wait),
+ KUNIT_CASE(dm_test_apply_delay_nonzero_wait),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 39/70] drm/amd/display: add CRC source list KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (37 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 38/70] drm/amd/display: add KUnit tests for DPCD poweroff delay Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 40/70] drm/amd/display: add CRC source verify " Wayne Lin
` (30 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Expose amdgpu_dm_crtc_get_crc_sources() for KUnit and add a test that
verifies the returned static source-name list and its count. This is the
accessor used by the debugfs CRC control interface.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_crc_test.c | 26 +++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 1f9528364e53..630dea3487b3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -152,6 +152,7 @@ const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc,
*count = ARRAY_SIZE(pipe_crc_sources);
return pipe_crc_sources;
}
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_get_crc_sources);
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
static void update_phy_id_mapping(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
index a6fd3a6fd803..88f7a15853e8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
@@ -95,6 +95,30 @@ static void dm_test_is_valid_crc_source(struct kunit *test)
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
}
+/**
+ * dm_test_crtc_get_crc_sources() - Test available CRC source strings.
+ * @test: KUnit test context.
+ *
+ * Verifies that amdgpu_dm_crtc_get_crc_sources() returns the static source
+ * list and reports all debugfs source names.
+ */
+static void dm_test_crtc_get_crc_sources(struct kunit *test)
+{
+ const char *const *sources;
+ size_t count = 0;
+
+ sources = amdgpu_dm_crtc_get_crc_sources(NULL, &count);
+
+ KUNIT_ASSERT_NOT_NULL(test, sources);
+ KUNIT_EXPECT_EQ(test, count, 6);
+ KUNIT_EXPECT_STREQ(test, sources[0], "none");
+ KUNIT_EXPECT_STREQ(test, sources[1], "crtc");
+ KUNIT_EXPECT_STREQ(test, sources[2], "crtc dither");
+ KUNIT_EXPECT_STREQ(test, sources[3], "dprx");
+ KUNIT_EXPECT_STREQ(test, sources[4], "dprx dither");
+ KUNIT_EXPECT_STREQ(test, sources[5], "auto");
+}
+
/**
* dm_test_need_dp_aux() - Test dm_need_dp_aux().
* @test: KUnit test context.
@@ -222,6 +246,8 @@ static struct kunit_case dm_crc_test_cases[] = {
KUNIT_CASE(dm_test_need_crc_dither),
/* amdgpu_dm_is_valid_crc_source() */
KUNIT_CASE(dm_test_is_valid_crc_source),
+ /* amdgpu_dm_crtc_get_crc_sources() */
+ KUNIT_CASE(dm_test_crtc_get_crc_sources),
/* dm_need_dp_aux() */
KUNIT_CASE(dm_test_need_dp_aux),
/* dm_crc_source_should_start_dprx() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 40/70] drm/amd/display: add CRC source verify KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (38 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 39/70] drm/amd/display: add CRC source list KUnit coverage Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 41/70] drm/amd/display: add CRC configure " Wayne Lin
` (29 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Expose amdgpu_dm_crtc_verify_crc_source() for KUnit and add tests for the
valid and invalid source-name paths. Introduce the shared CRTC test
scaffolding (dm_test_alloc_crc_crtc() plus the DM device test includes)
used by the remaining CRTC CRC tests.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_crc_test.c | 66 +++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 630dea3487b3..6600cc6ecf8e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -565,6 +565,7 @@ amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
*values_cnt = 3;
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_verify_crc_source);
int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
struct dm_crtc_state *dm_crtc_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
index 88f7a15853e8..4fa0bd9669c4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
@@ -7,7 +7,30 @@
#include <kunit/test.h>
+#include <drm/drm_modeset_lock.h>
+
+#include "dc.h"
+#include "amdgpu.h"
+#include "amdgpu_mode.h"
+#include "amdgpu_dm.h"
#include "amdgpu_dm_crc.h"
+#include "amdgpu_dm_kunit_test_helpers.h"
+
+static struct amdgpu_crtc *dm_test_alloc_crc_crtc(struct kunit *test,
+ struct amdgpu_device *adev)
+{
+ struct amdgpu_crtc *acrtc;
+
+ acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+ acrtc->base.dev = &adev->ddev;
+ drm_modeset_lock_init(&acrtc->base.mutex);
+ spin_lock_init(&acrtc->base.commit_lock);
+ INIT_LIST_HEAD(&acrtc->base.commit_list);
+
+ return acrtc;
+}
static void dm_test_parse_crc_source_none(struct kunit *test)
{
@@ -119,6 +142,46 @@ static void dm_test_crtc_get_crc_sources(struct kunit *test)
KUNIT_EXPECT_STREQ(test, sources[5], "auto");
}
+/**
+ * dm_test_crtc_verify_crc_source_valid() - Test valid CRC source verification.
+ * @test: KUnit test context.
+ *
+ * Verifies that valid source strings return success and request three CRC
+ * values.
+ */
+static void dm_test_crtc_verify_crc_source_valid(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ size_t values_cnt = 0;
+ int ret;
+
+ ret = amdgpu_dm_crtc_verify_crc_source(&acrtc->base, "crtc", &values_cnt);
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, values_cnt, 3);
+}
+
+/**
+ * dm_test_crtc_verify_crc_source_invalid() - Test invalid CRC source verification.
+ * @test: KUnit test context.
+ *
+ * Verifies that invalid source strings are rejected without changing the
+ * caller-provided values count.
+ */
+static void dm_test_crtc_verify_crc_source_invalid(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ size_t values_cnt = 7;
+ int ret;
+
+ ret = amdgpu_dm_crtc_verify_crc_source(&acrtc->base, "bad", &values_cnt);
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+ KUNIT_EXPECT_EQ(test, values_cnt, 7);
+}
+
/**
* dm_test_need_dp_aux() - Test dm_need_dp_aux().
* @test: KUnit test context.
@@ -248,6 +311,9 @@ static struct kunit_case dm_crc_test_cases[] = {
KUNIT_CASE(dm_test_is_valid_crc_source),
/* amdgpu_dm_crtc_get_crc_sources() */
KUNIT_CASE(dm_test_crtc_get_crc_sources),
+ /* amdgpu_dm_crtc_verify_crc_source() */
+ KUNIT_CASE(dm_test_crtc_verify_crc_source_valid),
+ KUNIT_CASE(dm_test_crtc_verify_crc_source_invalid),
/* dm_need_dp_aux() */
KUNIT_CASE(dm_test_need_dp_aux),
/* dm_crc_source_should_start_dprx() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 41/70] drm/amd/display: add CRC configure KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (39 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 40/70] drm/amd/display: add CRC source verify " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 42/70] drm/amd/display: add CRC set-source " Wayne Lin
` (28 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Expose amdgpu_dm_crtc_configure_crc_source() for KUnit and add tests for
the CRTC-enable, disable (NONE), DPRX, DPRX-dither, DCN3.6 polynomial
select, and DC-configure-failure paths.
Introduce a small fake DC fixture (timing-generator and OPP callbacks
over an empty resource context) so the configure path can be exercised
without real hardware. The fixture is shared with the CRC IRQ tests.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_crc_test.c | 343 ++++++++++++++++++
2 files changed, 344 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 6600cc6ecf8e..47beee584dbf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -638,6 +638,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
return ret;
}
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_configure_crc_source);
int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
index 4fa0bd9669c4..383646ad7005 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
@@ -10,12 +10,150 @@
#include <drm/drm_modeset_lock.h>
#include "dc.h"
+#include "core_types.h"
+#include "logger_types.h"
+#include "opp.h"
+#include "timing_generator.h"
#include "amdgpu.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_crc.h"
#include "amdgpu_dm_kunit_test_helpers.h"
+struct dm_test_crc_dc_fixture {
+ struct dc *dc;
+ struct dc_context *dc_ctx;
+ struct dc_state *dc_state;
+ struct dc_stream_state *stream;
+ struct dc_link *link;
+ struct timing_generator *tg;
+ struct output_pixel_processor *opp;
+ struct dal_logger *logger;
+ struct dm_crtc_state *dm_state;
+ struct crc_params crc_params;
+ enum dc_dynamic_expansion dyn_expansion;
+ enum dc_dither_option dither_option;
+ uint32_t crc_r;
+ uint32_t crc_g;
+ uint32_t crc_b;
+ bool configure_crc_called;
+ bool dyn_expansion_called;
+ bool bit_depth_reduction_called;
+ bool configure_crc_return;
+ bool get_crc_called;
+ bool get_crc_return;
+};
+
+static struct dm_test_crc_dc_fixture *dm_test_crc_dc_ctx;
+
+static bool dm_test_configure_crc(struct timing_generator *tg,
+ const struct crc_params *params)
+{
+ if (!dm_test_crc_dc_ctx)
+ return false;
+
+ dm_test_crc_dc_ctx->configure_crc_called = true;
+ dm_test_crc_dc_ctx->crc_params = *params;
+
+ return dm_test_crc_dc_ctx->configure_crc_return;
+}
+
+static bool dm_test_get_crc(struct timing_generator *tg, uint8_t idx,
+ uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
+{
+ if (!dm_test_crc_dc_ctx)
+ return false;
+
+ dm_test_crc_dc_ctx->get_crc_called = true;
+ *r_cr = dm_test_crc_dc_ctx->crc_r;
+ *g_y = dm_test_crc_dc_ctx->crc_g;
+ *b_cb = dm_test_crc_dc_ctx->crc_b;
+
+ return dm_test_crc_dc_ctx->get_crc_return;
+}
+
+static void dm_test_opp_set_dyn_expansion(struct output_pixel_processor *opp,
+ enum dc_color_space color_sp,
+ enum dc_color_depth color_dpth,
+ enum signal_type signal)
+{
+ if (!dm_test_crc_dc_ctx)
+ return;
+
+ dm_test_crc_dc_ctx->dyn_expansion_called = true;
+ dm_test_crc_dc_ctx->dyn_expansion = opp->dyn_expansion;
+}
+
+static void dm_test_opp_program_bit_depth_reduction(struct output_pixel_processor *opp,
+ const struct bit_depth_reduction_params *params)
+{
+ if (!dm_test_crc_dc_ctx)
+ return;
+
+ dm_test_crc_dc_ctx->bit_depth_reduction_called = true;
+}
+
+static const struct timing_generator_funcs dm_test_tg_funcs = {
+ .configure_crc = dm_test_configure_crc,
+ .get_crc = dm_test_get_crc,
+};
+
+static const struct opp_funcs dm_test_opp_funcs = {
+ .opp_set_dyn_expansion = dm_test_opp_set_dyn_expansion,
+ .opp_program_bit_depth_reduction = dm_test_opp_program_bit_depth_reduction,
+};
+
+static struct dm_test_crc_dc_fixture *dm_test_alloc_crc_dc_fixture(struct kunit *test,
+ struct amdgpu_device *adev)
+{
+ struct dm_test_crc_dc_fixture *fixture;
+ struct pipe_ctx *pipe;
+
+ fixture = kunit_kzalloc(test, sizeof(*fixture), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture);
+
+ fixture->dm_state = kunit_kzalloc(test, sizeof(*fixture->dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->dm_state);
+ fixture->dc = kunit_kzalloc(test, sizeof(*fixture->dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->dc);
+ fixture->dc_ctx = kunit_kzalloc(test, sizeof(*fixture->dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->dc_ctx);
+ fixture->dc_state = kunit_kzalloc(test, sizeof(*fixture->dc_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->dc_state);
+ fixture->tg = kunit_kzalloc(test, sizeof(*fixture->tg), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->tg);
+ fixture->opp = kunit_kzalloc(test, sizeof(*fixture->opp), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->opp);
+ fixture->logger = kunit_kzalloc(test, sizeof(*fixture->logger), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fixture->logger);
+ fixture->link = dm_kunit_alloc_link(test);
+ fixture->stream = dm_kunit_alloc_stream(test, fixture->link);
+
+ mutex_init(&adev->dm.dc_lock);
+ adev->dm.dc = fixture->dc;
+ fixture->dc->ctx = fixture->dc_ctx;
+ fixture->dc->current_state = fixture->dc_state;
+ fixture->dc_ctx->dc = fixture->dc;
+ fixture->dc_ctx->logger = fixture->logger;
+ fixture->link->dc = fixture->dc;
+ fixture->stream->ctx = fixture->dc_ctx;
+ fixture->stream->link = fixture->link;
+ fixture->stream->timing.h_addressable = 1920;
+ fixture->stream->timing.v_addressable = 1080;
+ fixture->configure_crc_return = true;
+ fixture->tg->funcs = &dm_test_tg_funcs;
+ fixture->opp->funcs = &dm_test_opp_funcs;
+ fixture->dm_state->stream = fixture->stream;
+
+ pipe = &fixture->dc_state->res_ctx.pipe_ctx[0];
+ pipe->stream = fixture->stream;
+ pipe->pipe_idx = 0;
+ pipe->stream_res.tg = fixture->tg;
+ pipe->stream_res.opp = fixture->opp;
+
+ return fixture;
+}
+
static struct amdgpu_crtc *dm_test_alloc_crc_crtc(struct kunit *test,
struct amdgpu_device *adev)
{
@@ -182,6 +320,203 @@ static void dm_test_crtc_verify_crc_source_invalid(struct kunit *test)
KUNIT_EXPECT_EQ(test, values_cnt, 7);
}
+/**
+ * dm_test_crtc_configure_crc_source_no_stream() - Test missing stream handling.
+ * @test: KUnit test context.
+ *
+ * Verifies that configuration is deferred/rejected before any DC access when
+ * the CRTC state does not have a stream.
+ */
+static void dm_test_crtc_configure_crc_source_no_stream(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_crtc_state *dm_state;
+ int ret;
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_CRTC);
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+}
+
+/**
+ * dm_test_crtc_configure_crc_source_dprx() - Test DPRX configure path.
+ * @test: KUnit test context.
+ *
+ * Verifies that a DPRX source can be configured with an empty DC resource
+ * state, covering the non-CRTC path that only updates dither/dynamic expansion.
+ */
+static void dm_test_crtc_configure_crc_source_dprx(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+ int ret;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ dm_test_crc_dc_ctx = fixture;
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, fixture->dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_DPRX);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_FALSE(test, fixture->configure_crc_called);
+ KUNIT_EXPECT_TRUE(test, fixture->dyn_expansion_called);
+ KUNIT_EXPECT_EQ(test, fixture->dyn_expansion, DYN_EXPANSION_DISABLE);
+ KUNIT_EXPECT_TRUE(test, fixture->bit_depth_reduction_called);
+}
+
+/**
+ * dm_test_crtc_configure_crc_source_dprx_dither() - Test DPRX dither path.
+ * @test: KUnit test context.
+ *
+ * Verifies that a DPRX dither source reaches the default dither/dynamic
+ * expansion path without requiring timing-generator callbacks.
+ */
+static void dm_test_crtc_configure_crc_source_dprx_dither(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+ int ret;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ dm_test_crc_dc_ctx = fixture;
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, fixture->dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_FALSE(test, fixture->configure_crc_called);
+ KUNIT_EXPECT_TRUE(test, fixture->dyn_expansion_called);
+ KUNIT_EXPECT_EQ(test, fixture->dyn_expansion, DYN_EXPANSION_AUTO);
+ KUNIT_EXPECT_TRUE(test, fixture->bit_depth_reduction_called);
+}
+
+/**
+ * dm_test_crtc_configure_crc_source_crtc() - Test CRTC enable path.
+ * @test: KUnit test context.
+ *
+ * Verifies that a CRTC source enables DC CRC capture and disables dither.
+ */
+static void dm_test_crtc_configure_crc_source_crtc(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+ int ret;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ dm_test_crc_dc_ctx = fixture;
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, fixture->dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_CRTC);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_TRUE(test, fixture->configure_crc_called);
+ KUNIT_EXPECT_TRUE(test, fixture->crc_params.enable);
+ KUNIT_EXPECT_TRUE(test, fixture->crc_params.continuous_mode);
+ KUNIT_EXPECT_TRUE(test, fixture->crc_params.reset);
+ KUNIT_EXPECT_EQ(test, fixture->crc_params.windowa_x_end, 1920);
+ KUNIT_EXPECT_EQ(test, fixture->crc_params.windowa_y_end, 1080);
+ KUNIT_EXPECT_TRUE(test, fixture->dyn_expansion_called);
+ KUNIT_EXPECT_EQ(test, fixture->dyn_expansion, DYN_EXPANSION_DISABLE);
+ KUNIT_EXPECT_TRUE(test, fixture->bit_depth_reduction_called);
+}
+
+/**
+ * dm_test_crtc_configure_crc_source_crtc_dcn36_poly() - Test CRC poly select.
+ * @test: KUnit test context.
+ *
+ * Verifies that DCN3.6+ configurations use the CRTC-selected CRC polynomial.
+ */
+static void dm_test_crtc_configure_crc_source_crtc_dcn36_poly(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+ int ret;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 6, 0);
+ acrtc->dm_irq_params.crc_poly_mode = CRC_POLY_MODE_32;
+ dm_test_crc_dc_ctx = fixture;
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, fixture->dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_CRTC);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_TRUE(test, fixture->configure_crc_called);
+ KUNIT_EXPECT_EQ(test, fixture->crc_params.crc_poly_mode, CRC_POLY_MODE_32);
+}
+
+/**
+ * dm_test_crtc_configure_crc_source_crtc_configure_fails() - Test failure path.
+ * @test: KUnit test context.
+ *
+ * Verifies that a DC CRC configuration failure is reported as -EINVAL and
+ * stops before dither/dynamic expansion programming.
+ */
+static void dm_test_crtc_configure_crc_source_crtc_configure_fails(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+ int ret;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ fixture->configure_crc_return = false;
+ dm_test_crc_dc_ctx = fixture;
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, fixture->dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_CRTC);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+ KUNIT_EXPECT_TRUE(test, fixture->configure_crc_called);
+ KUNIT_EXPECT_FALSE(test, fixture->dyn_expansion_called);
+ KUNIT_EXPECT_FALSE(test, fixture->bit_depth_reduction_called);
+}
+
+/**
+ * dm_test_crtc_configure_crc_source_none() - Test CRC disable path.
+ * @test: KUnit test context.
+ *
+ * Verifies that source NONE disables DC CRC capture and restores default
+ * dither/dynamic expansion.
+ */
+static void dm_test_crtc_configure_crc_source_none(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+ int ret;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ dm_test_crc_dc_ctx = fixture;
+
+ ret = amdgpu_dm_crtc_configure_crc_source(&acrtc->base, fixture->dm_state,
+ AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_TRUE(test, fixture->configure_crc_called);
+ KUNIT_EXPECT_FALSE(test, fixture->crc_params.enable);
+ KUNIT_EXPECT_FALSE(test, fixture->crc_params.continuous_mode);
+ KUNIT_EXPECT_TRUE(test, fixture->crc_params.reset);
+ KUNIT_EXPECT_TRUE(test, fixture->dyn_expansion_called);
+ KUNIT_EXPECT_EQ(test, fixture->dyn_expansion, DYN_EXPANSION_AUTO);
+ KUNIT_EXPECT_TRUE(test, fixture->bit_depth_reduction_called);
+}
+
/**
* dm_test_need_dp_aux() - Test dm_need_dp_aux().
* @test: KUnit test context.
@@ -314,6 +649,14 @@ static struct kunit_case dm_crc_test_cases[] = {
/* amdgpu_dm_crtc_verify_crc_source() */
KUNIT_CASE(dm_test_crtc_verify_crc_source_valid),
KUNIT_CASE(dm_test_crtc_verify_crc_source_invalid),
+ /* amdgpu_dm_crtc_configure_crc_source() */
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_no_stream),
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_dprx),
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_dprx_dither),
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_crtc),
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_crtc_dcn36_poly),
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_crtc_configure_fails),
+ KUNIT_CASE(dm_test_crtc_configure_crc_source_none),
/* dm_need_dp_aux() */
KUNIT_CASE(dm_test_need_dp_aux),
/* dm_crc_source_should_start_dprx() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 42/70] drm/amd/display: add CRC set-source KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (40 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 41/70] drm/amd/display: add CRC configure " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 43/70] drm/amd/display: add CRC IRQ handler " Wayne Lin
` (27 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Expose amdgpu_dm_crtc_set_crc_source() for KUnit and add tests for the
invalid-source guard, the valid NONE no-stream exit, the pending-commit
wait/put path, and the DPRX connector-walk that returns -EINVAL when no
matching DP connector is attached.
Add connector test helpers (drm_connector_funcs plus a cleanup action)
to back the DPRX connector-walk test.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_crc_test.c | 161 ++++++++++++++++++
2 files changed, 162 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 47beee584dbf..0e896aab098a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -816,6 +816,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
return ret;
}
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_set_crc_source);
/**
* amdgpu_dm_crtc_handle_crc_irq: Report to DRM the CRC on given CRTC.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
index 383646ad7005..96bdb83317ec 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
@@ -7,7 +7,11 @@
#include <kunit/test.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_connector.h>
#include <drm/drm_modeset_lock.h>
+#include <drm/drm_probe_helper.h>
#include "dc.h"
#include "core_types.h"
@@ -170,6 +174,19 @@ static struct amdgpu_crtc *dm_test_alloc_crc_crtc(struct kunit *test,
return acrtc;
}
+static const struct drm_connector_funcs dm_test_crc_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+};
+
+static void dm_test_crc_connector_cleanup(void *data)
+{
+ drm_connector_cleanup(data);
+}
+
static void dm_test_parse_crc_source_none(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_NONE, dm_parse_crc_source("none"));
@@ -517,6 +534,145 @@ static void dm_test_crtc_configure_crc_source_none(struct kunit *test)
KUNIT_EXPECT_TRUE(test, fixture->bit_depth_reduction_called);
}
+/**
+ * dm_test_crtc_set_crc_source_invalid() - Test invalid source guard.
+ * @test: KUnit test context.
+ *
+ * Verifies that amdgpu_dm_crtc_set_crc_source() rejects invalid source names
+ * before taking modeset locks, vblank references, or touching DC state.
+ */
+static void dm_test_crtc_set_crc_source_invalid(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ int ret;
+
+ ret = amdgpu_dm_crtc_set_crc_source(&acrtc->base, "invalid");
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+}
+
+/**
+ * dm_test_crtc_set_crc_source_none_no_stream() - Test valid source no-stream exit.
+ * @test: KUnit test context.
+ *
+ * Verifies that a valid NONE request enters the set-source body, reads the
+ * current CRC state, and exits cleanly when configuration is deferred because
+ * no stream is attached.
+ */
+static void dm_test_crtc_set_crc_source_none_no_stream(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_crtc_state *dm_state;
+ int ret;
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+ acrtc->base.state = &dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
+
+ ret = amdgpu_dm_crtc_set_crc_source(&acrtc->base, "none");
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+ KUNIT_EXPECT_EQ(test, acrtc->dm_irq_params.crc_src,
+ AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
+ KUNIT_EXPECT_EQ(test, dm_state->crc_skip_count, 0);
+}
+
+/**
+ * dm_test_crtc_set_crc_source_none_commit() - Test set-source with pending commit.
+ * @test: KUnit test context.
+ *
+ * Verifies that a pending CRTC commit is acquired and waited on (already
+ * completed here so the wait returns immediately), then released during
+ * cleanup. Configuration is still deferred because no stream is attached.
+ */
+static void dm_test_crtc_set_crc_source_none_commit(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_crtc_state *dm_state;
+ struct drm_crtc_commit *commit;
+ int ret;
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+ acrtc->base.state = &dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
+
+ commit = kunit_kzalloc(test, sizeof(*commit), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, commit);
+ kref_init(&commit->ref);
+ init_completion(&commit->hw_done);
+ /* Mark the commit finished so the wait returns immediately. */
+ complete_all(&commit->hw_done);
+ list_add_tail(&commit->commit_entry, &acrtc->base.commit_list);
+
+ ret = amdgpu_dm_crtc_set_crc_source(&acrtc->base, "none");
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+ KUNIT_EXPECT_EQ(test, dm_state->crc_skip_count, 0);
+}
+
+/**
+ * dm_test_crtc_set_crc_source_dprx_no_connector() - Test DPRX with no match.
+ * @test: KUnit test context.
+ *
+ * Verifies that requesting a DPRX source walks the connector list and returns
+ * -EINVAL when no matching DP connector is attached to the CRTC. A stateless
+ * connector and a writeback connector exercise both connector filter branches.
+ */
+static void dm_test_crtc_set_crc_source_dprx_no_connector(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct drm_connector *dp_conn;
+ struct drm_connector *wb_conn;
+ struct dm_crtc_state *dm_state;
+ int ret;
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+ acrtc->base.state = &dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
+
+ /* Stateless DP connector: skipped by the !state filter. */
+ dp_conn = kunit_kzalloc(test, sizeof(*dp_conn), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dp_conn);
+ KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, dp_conn,
+ &dm_test_crc_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort), 0);
+ KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test,
+ dm_test_crc_connector_cleanup, dp_conn), 0);
+
+ /* Writeback connector bound to this CRTC: skipped by the WB filter. */
+ wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, wb_conn);
+ KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wb_conn,
+ &dm_test_crc_connector_funcs,
+ DRM_MODE_CONNECTOR_WRITEBACK), 0);
+ KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test,
+ dm_test_crc_connector_cleanup, wb_conn), 0);
+ drm_atomic_helper_connector_reset(wb_conn);
+ KUNIT_ASSERT_NOT_NULL(test, wb_conn->state);
+ wb_conn->state->crtc = &acrtc->base;
+ /*
+ * __drm_atomic_helper_connector_destroy_state() drops a connector
+ * reference when state->crtc is set. Balance it here since the CRTC is
+ * assigned directly rather than via drm_atomic_set_crtc_for_connector(),
+ * otherwise cleanup would drop the connector to zero and schedule an
+ * async free on the system workqueue.
+ */
+ drm_connector_get(wb_conn);
+
+ ret = amdgpu_dm_crtc_set_crc_source(&acrtc->base, "dprx");
+
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+ KUNIT_EXPECT_EQ(test, acrtc->dm_irq_params.crc_src,
+ AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
+}
+
/**
* dm_test_need_dp_aux() - Test dm_need_dp_aux().
* @test: KUnit test context.
@@ -657,6 +813,11 @@ static struct kunit_case dm_crc_test_cases[] = {
KUNIT_CASE(dm_test_crtc_configure_crc_source_crtc_dcn36_poly),
KUNIT_CASE(dm_test_crtc_configure_crc_source_crtc_configure_fails),
KUNIT_CASE(dm_test_crtc_configure_crc_source_none),
+ /* amdgpu_dm_crtc_set_crc_source() */
+ KUNIT_CASE(dm_test_crtc_set_crc_source_invalid),
+ KUNIT_CASE(dm_test_crtc_set_crc_source_none_no_stream),
+ KUNIT_CASE(dm_test_crtc_set_crc_source_none_commit),
+ KUNIT_CASE(dm_test_crtc_set_crc_source_dprx_no_connector),
/* dm_need_dp_aux() */
KUNIT_CASE(dm_test_need_dp_aux),
/* dm_crc_source_should_start_dprx() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 43/70] drm/amd/display: add CRC IRQ handler KUnit coverage
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (41 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 42/70] drm/amd/display: add CRC set-source " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 44/70] drm/amd/display: Adjust the structure dml2_dchub_watermark_regs Wayne Lin
` (26 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Expose amdgpu_dm_crtc_handle_crc_irq() for KUnit and add tests for the
incomplete-CRTC early returns, the disabled-source exit, the initial
two-frame skip window, the DPRX post-skip exit, and the failed
dc_stream_get_crc() path that stops before delivering a DRM CRC entry.
These tests reuse the fake DC fixture introduced with the CRC configure
coverage.
Assisted-by: Copilot:Claude-Opus-4.8 GPT-5.5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_crc_test.c | 132 ++++++++++++++++++
2 files changed, 133 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 0e896aab098a..078d2b589ec4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -874,6 +874,7 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
drm_crtc_accurate_vblank_count(crtc), crcs);
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_crtc_handle_crc_irq);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
index 96bdb83317ec..29a513dab9cd 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
@@ -673,6 +673,132 @@ static void dm_test_crtc_set_crc_source_dprx_no_connector(struct kunit *test)
AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
}
+/**
+ * dm_test_crtc_handle_crc_irq_early_returns() - Test null/missing state exits.
+ * @test: KUnit test context.
+ *
+ * Verifies that the CRC IRQ handler safely ignores incomplete CRTC objects.
+ */
+static void dm_test_crtc_handle_crc_irq_early_returns(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_crtc_state *dm_state;
+
+ amdgpu_dm_crtc_handle_crc_irq(NULL);
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+ acrtc->base.state = &dm_state->base;
+
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+ KUNIT_EXPECT_EQ(test, dm_state->crc_skip_count, 0);
+}
+
+/**
+ * dm_test_crtc_handle_crc_irq_disabled_source() - Test disabled source exit.
+ * @test: KUnit test context.
+ *
+ * Verifies that a present stream does not advance the skip counter when CRC
+ * capture is disabled.
+ */
+static void dm_test_crtc_handle_crc_irq_disabled_source(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_crtc_state *dm_state;
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+ dm_state->stream = dm_kunit_alloc_stream(test, NULL);
+ acrtc->base.state = &dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
+
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+
+ KUNIT_EXPECT_EQ(test, dm_state->crc_skip_count, 0);
+}
+
+/**
+ * dm_test_crtc_handle_crc_irq_skips_initial_frames() - Test initial skip logic.
+ * @test: KUnit test context.
+ *
+ * Verifies that the first two enabled CRC IRQs only increment crc_skip_count,
+ * avoiding the later DC CRC read path.
+ */
+static void dm_test_crtc_handle_crc_irq_skips_initial_frames(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_crtc_state *dm_state;
+
+ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dm_state);
+ dm_state->stream = dm_kunit_alloc_stream(test, NULL);
+ acrtc->base.state = &dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_CRTC;
+
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+ KUNIT_EXPECT_EQ(test, dm_state->crc_skip_count, 1);
+
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+ KUNIT_EXPECT_EQ(test, dm_state->crc_skip_count, 2);
+}
+
+/**
+ * dm_test_crtc_handle_crc_irq_dprx_after_skip() - Test DPRX post-skip exit.
+ * @test: KUnit test context.
+ *
+ * Verifies that enabled non-CRTC CRC sources do not call into DC CRC reads
+ * after the initial skip window.
+ */
+static void dm_test_crtc_handle_crc_irq_dprx_after_skip(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ fixture->dm_state->crc_skip_count = 2;
+ acrtc->base.state = &fixture->dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_DPRX;
+ dm_test_crc_dc_ctx = fixture;
+
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_FALSE(test, fixture->get_crc_called);
+ KUNIT_EXPECT_EQ(test, fixture->dm_state->crc_skip_count, 2);
+}
+
+/**
+ * dm_test_crtc_handle_crc_irq_get_crc_fails() - Test failed DC CRC read.
+ * @test: KUnit test context.
+ *
+ * Verifies that the IRQ handler exits after dc_stream_get_crc() returns false,
+ * before attempting to deliver a DRM CRC entry.
+ */
+static void dm_test_crtc_handle_crc_irq_get_crc_fails(struct kunit *test)
+{
+ struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+ struct amdgpu_crtc *acrtc = dm_test_alloc_crc_crtc(test, adev);
+ struct dm_test_crc_dc_fixture *fixture;
+
+ fixture = dm_test_alloc_crc_dc_fixture(test, adev);
+ fixture->dm_state->crc_skip_count = 2;
+ fixture->get_crc_return = false;
+ acrtc->base.state = &fixture->dm_state->base;
+ acrtc->dm_irq_params.crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_CRTC;
+ dm_test_crc_dc_ctx = fixture;
+
+ amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
+ dm_test_crc_dc_ctx = NULL;
+
+ KUNIT_EXPECT_TRUE(test, fixture->get_crc_called);
+ KUNIT_EXPECT_EQ(test, fixture->dm_state->crc_skip_count, 2);
+}
+
/**
* dm_test_need_dp_aux() - Test dm_need_dp_aux().
* @test: KUnit test context.
@@ -818,6 +944,12 @@ static struct kunit_case dm_crc_test_cases[] = {
KUNIT_CASE(dm_test_crtc_set_crc_source_none_no_stream),
KUNIT_CASE(dm_test_crtc_set_crc_source_none_commit),
KUNIT_CASE(dm_test_crtc_set_crc_source_dprx_no_connector),
+ /* amdgpu_dm_crtc_handle_crc_irq() */
+ KUNIT_CASE(dm_test_crtc_handle_crc_irq_early_returns),
+ KUNIT_CASE(dm_test_crtc_handle_crc_irq_disabled_source),
+ KUNIT_CASE(dm_test_crtc_handle_crc_irq_skips_initial_frames),
+ KUNIT_CASE(dm_test_crtc_handle_crc_irq_dprx_after_skip),
+ KUNIT_CASE(dm_test_crtc_handle_crc_irq_get_crc_fails),
/* dm_need_dp_aux() */
KUNIT_CASE(dm_test_need_dp_aux),
/* dm_crc_source_should_start_dprx() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 44/70] drm/amd/display: Adjust the structure dml2_dchub_watermark_regs
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (42 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 43/70] drm/amd/display: add CRC IRQ handler " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 45/70] drm/amd/display: Add mode helper tests for connector Wayne Lin
` (25 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Austin Zheng
From: Aurabindo Pillai <aurabindo.pillai@amd.com>
Adjust the structure dml2_dchub_watermark_regs for future usage
Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
index 5669be0a7340..799e72243418 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
@@ -171,8 +171,15 @@ struct dml2_dchub_watermark_regs {
uint32_t sr_exit_low_power;
uint32_t uclk_pstate;
uint32_t fclk_pstate;
+ union {
uint32_t temp_read_or_ppt;
+ uint32_t temp_read;
+ };
+ uint32_t ppt;
+ union {
uint32_t usr;
+ uint32_t buffer_fullness;
+ };
/* qos */
uint32_t refcyc_per_trip_to_mem;
uint32_t refcyc_per_meta_trip_to_mem;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 45/70] drm/amd/display: Add mode helper tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (43 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 44/70] drm/amd/display: Adjust the structure dml2_dchub_watermark_regs Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 46/70] drm/amd/display: Add i2c and EDID parsing " Wayne Lin
` (24 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for the connector mode helpers:
amdgpu_dm_connector_funcs_force(), dm_validate_stream_and_context(),
amdgpu_dm_connector_to_encoder(), amdgpu_dm_get_native_mode(),
amdgpu_dm_create_common_mode(), amdgpu_dm_connector_add_common_modes(),
amdgpu_dm_connector_ddc_get_modes(), add_fs_modes() and
amdgpu_dm_connector_add_freesync_modes().
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 27 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 15 +
.../tests/amdgpu_dm_connector_test.c | 309 ++++++++++++++++++
3 files changed, 342 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 6d358cb84961..557cc6492529 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1914,7 +1914,7 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
}
EXPORT_IF_KUNIT(amdgpu_dm_connector_late_register);
-static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
+STATIC_IFN_KUNIT void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dc_link *dc_link = aconnector->dc_link;
@@ -1950,6 +1950,7 @@ static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
&dc_em_sink->edid_caps);
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_funcs_force);
static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
.reset = amdgpu_dm_connector_funcs_reset,
@@ -2034,7 +2035,7 @@ STATIC_IFN_KUNIT void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
}
EXPORT_IF_KUNIT(handle_edid_mgmt);
-static enum dc_status dm_validate_stream_and_context(struct dc *dc,
+STATIC_IFN_KUNIT enum dc_status dm_validate_stream_and_context(struct dc *dc,
struct dc_stream_state *stream)
{
enum dc_status dc_result = DC_ERROR_UNEXPECTED;
@@ -2096,6 +2097,7 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc,
return dc_result;
}
+EXPORT_IF_KUNIT(dm_validate_stream_and_context);
struct dc_stream_state *
amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
@@ -2460,7 +2462,7 @@ STATIC_IFN_KUNIT int to_drm_connector_type(enum signal_type st, uint32_t connect
}
EXPORT_IF_KUNIT(to_drm_connector_type);
-static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
+STATIC_IFN_KUNIT struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
{
struct drm_encoder *encoder;
@@ -2470,8 +2472,9 @@ static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *
return NULL;
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_to_encoder);
-static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
+STATIC_IFN_KUNIT void amdgpu_dm_get_native_mode(struct drm_connector *connector)
{
struct drm_encoder *encoder;
struct amdgpu_encoder *amdgpu_encoder;
@@ -2499,8 +2502,9 @@ static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_get_native_mode);
-static struct drm_display_mode *
+STATIC_IFN_KUNIT struct drm_display_mode *
amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
const char *name,
int hdisplay, int vdisplay)
@@ -2523,6 +2527,7 @@ amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
return mode;
}
+EXPORT_IF_KUNIT(amdgpu_dm_create_common_mode);
static const struct amdgpu_dm_mode_size {
char name[DRM_DISPLAY_MODE_LEN];
@@ -2542,7 +2547,7 @@ static const struct amdgpu_dm_mode_size {
{"1920x1200", 1920, 1200}
};
-static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
+STATIC_IFN_KUNIT void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
@@ -2590,6 +2595,7 @@ static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
amdgpu_dm_connector->num_modes++;
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_add_common_modes);
void amdgpu_set_panel_orientation(struct drm_connector *connector)
{
@@ -2621,7 +2627,7 @@ void amdgpu_set_panel_orientation(struct drm_connector *connector)
native_mode->vdisplay);
}
-static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
+STATIC_IFN_KUNIT void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
const struct drm_edid *drm_edid)
{
struct amdgpu_dm_connector *amdgpu_dm_connector =
@@ -2653,6 +2659,7 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
amdgpu_dm_connector->num_modes = 0;
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_ddc_get_modes);
STATIC_IFN_KUNIT bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector,
struct drm_display_mode *mode)
@@ -2668,7 +2675,7 @@ STATIC_IFN_KUNIT bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector,
}
EXPORT_IF_KUNIT(is_duplicate_mode);
-static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
+STATIC_IFN_KUNIT uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
{
const struct drm_display_mode *m;
struct drm_display_mode *new_mode;
@@ -2743,8 +2750,9 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
out:
return new_modes_count;
}
+EXPORT_IF_KUNIT(add_fs_modes);
-static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
+STATIC_IFN_KUNIT void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
const struct drm_edid *drm_edid)
{
struct amdgpu_dm_connector *amdgpu_dm_connector =
@@ -2767,6 +2775,7 @@ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connect
amdgpu_dm_connector->num_modes +=
add_fs_modes(amdgpu_dm_connector);
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_add_freesync_modes);
static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index f7ec4b906e13..b237e8f864db 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -146,6 +146,21 @@ int amdgpu_dm_encoder_init(struct drm_device *dev,
uint32_t link_index);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+void amdgpu_dm_connector_funcs_force(struct drm_connector *connector);
+enum dc_status dm_validate_stream_and_context(struct dc *dc,
+ struct dc_stream_state *stream);
+struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector);
+void amdgpu_dm_get_native_mode(struct drm_connector *connector);
+struct drm_display_mode *amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
+ const char *name,
+ int hdisplay, int vdisplay);
+void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector);
+void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
+ const struct drm_edid *drm_edid);
+uint add_fs_modes(struct amdgpu_dm_connector *aconnector);
+void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
+ const struct drm_edid *drm_edid);
void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector);
void create_eml_sink(struct amdgpu_dm_connector *aconnector);
void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 59f2f8235486..459f0eda9a69 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -11,8 +11,10 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_encoder.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_mode_object.h>
+#include <drm/drm_modes.h>
#include <drm/drm_property.h>
#include <linux/hdmi.h>
@@ -4379,6 +4381,291 @@ static void dm_test_handle_edid_mgmt_non_dp_leaves_caps(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)ctx->link->verified_link_cap.link_rate, 0);
}
+/*
+ * Context for the connector funcs / modes tests: a managed DRM device with a
+ * registered connector and a managed encoder attached to it, so helpers that
+ * walk connector->encoder relationships resolve correctly.
+ */
+struct dm_test_modes_ctx {
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_encoder *aenc;
+};
+
+static struct dm_test_modes_ctx *
+dm_test_modes_ctx_alloc(struct kunit *test, int connector_type)
+{
+ struct dm_test_modes_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->drm = dm_test_alloc_drm(test);
+ ctx->aconnector = dm_test_add_connector(test, ctx->drm, connector_type);
+
+ ctx->aenc = kunit_kzalloc(test, sizeof(*ctx->aenc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aenc);
+ KUNIT_ASSERT_EQ(test,
+ drmm_encoder_init(ctx->drm, &ctx->aenc->base, NULL,
+ DRM_MODE_ENCODER_TMDS, NULL), 0);
+ KUNIT_ASSERT_EQ(test,
+ drm_connector_attach_encoder(&ctx->aconnector->base,
+ &ctx->aenc->base), 0);
+
+ return ctx;
+}
+
+/**
+ * dm_test_funcs_force_no_edid - Test force() leaves drm_edid NULL when no EDID
+ * @test: The KUnit test context
+ *
+ * A headless force-on DisplayPort connector reads no EDID, so the cached
+ * drm_edid pointer must stay NULL after the force callback runs.
+ */
+static void dm_test_funcs_force_no_edid(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+
+ amdgpu_dm_connector_funcs_force(&ctx->aconnector->base);
+
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->drm_edid);
+}
+
+/**
+ * dm_test_validate_stream_null_stream - Test NULL stream returns unexpected
+ * @test: The KUnit test context
+ *
+ * With a NULL stream the validation jumps straight to cleanup without ever
+ * dereferencing the dc handle and reports DC_ERROR_UNEXPECTED.
+ */
+static void dm_test_validate_stream_null_stream(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test,
+ (int)dm_validate_stream_and_context(NULL, NULL),
+ (int)DC_ERROR_UNEXPECTED);
+}
+
+/**
+ * dm_test_to_encoder_no_encoder - Test connector with no encoder returns NULL
+ * @test: The KUnit test context
+ */
+static void dm_test_to_encoder_no_encoder(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+ struct amdgpu_dm_connector *aconnector =
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+
+ KUNIT_EXPECT_NULL(test,
+ amdgpu_dm_connector_to_encoder(&aconnector->base));
+}
+
+/**
+ * dm_test_to_encoder_returns_attached - Test the attached encoder is returned
+ * @test: The KUnit test context
+ */
+static void dm_test_to_encoder_returns_attached(struct kunit *test)
+{
+ struct dm_test_modes_ctx *ctx =
+ dm_test_modes_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ KUNIT_EXPECT_PTR_EQ(test,
+ amdgpu_dm_connector_to_encoder(&ctx->aconnector->base),
+ &ctx->aenc->base);
+}
+
+/**
+ * dm_test_native_mode_no_encoder - Test native mode resolution is a no-op
+ * @test: The KUnit test context
+ *
+ * Without an encoder there is nothing to copy into, so the call must return
+ * cleanly without dereferencing a NULL encoder.
+ */
+static void dm_test_native_mode_no_encoder(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+ struct amdgpu_dm_connector *aconnector =
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+
+ amdgpu_dm_get_native_mode(&aconnector->base);
+}
+
+/**
+ * dm_test_native_mode_empty_probed_zeroes_clock - Test empty probed list clears mode
+ * @test: The KUnit test context
+ *
+ * With no probed modes there is no preferred mode to copy, so the encoder's
+ * native mode is memset to zero (clock becomes 0).
+ */
+static void dm_test_native_mode_empty_probed_zeroes_clock(struct kunit *test)
+{
+ struct dm_test_modes_ctx *ctx =
+ dm_test_modes_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+
+ ctx->aenc->native_mode.clock = 148500;
+
+ amdgpu_dm_get_native_mode(&ctx->aconnector->base);
+
+ KUNIT_EXPECT_EQ(test, ctx->aenc->native_mode.clock, 0);
+}
+
+/**
+ * dm_test_native_mode_copies_preferred - Test the preferred mode is copied
+ * @test: The KUnit test context
+ *
+ * The preferred probed mode is duplicated into the encoder's native mode.
+ */
+static void dm_test_native_mode_copies_preferred(struct kunit *test)
+{
+ struct dm_test_modes_ctx *ctx =
+ dm_test_modes_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_create(ctx->drm);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+ mode->type = DRM_MODE_TYPE_PREFERRED;
+ mode->clock = 148500;
+ mode->hdisplay = 1920;
+ mode->vdisplay = 1080;
+ drm_mode_probed_add(&ctx->aconnector->base, mode);
+
+ amdgpu_dm_get_native_mode(&ctx->aconnector->base);
+
+ KUNIT_EXPECT_EQ(test, ctx->aenc->native_mode.hdisplay, 1920);
+ KUNIT_EXPECT_EQ(test, ctx->aenc->native_mode.vdisplay, 1080);
+ KUNIT_EXPECT_EQ(test, ctx->aenc->native_mode.clock, 148500);
+}
+
+/**
+ * dm_test_create_common_mode_overrides - Test common mode inherits native timing
+ * @test: The KUnit test context
+ *
+ * A new common mode takes its pixel clock and porches from the encoder's
+ * native mode but overrides the visible resolution and clears PREFERRED.
+ */
+static void dm_test_create_common_mode_overrides(struct kunit *test)
+{
+ struct dm_test_modes_ctx *ctx =
+ dm_test_modes_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+ struct drm_display_mode *mode;
+
+ ctx->aenc->native_mode.clock = 148500;
+ ctx->aenc->native_mode.htotal = 2200;
+ ctx->aenc->native_mode.type = DRM_MODE_TYPE_PREFERRED;
+
+ mode = amdgpu_dm_create_common_mode(&ctx->aenc->base, "800x600",
+ 800, 600);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ KUNIT_EXPECT_EQ(test, mode->hdisplay, 800);
+ KUNIT_EXPECT_EQ(test, mode->vdisplay, 600);
+ KUNIT_EXPECT_EQ(test, mode->clock, 148500);
+ KUNIT_EXPECT_EQ(test, mode->htotal, 2200);
+ KUNIT_EXPECT_FALSE(test, mode->type & DRM_MODE_TYPE_PREFERRED);
+ KUNIT_EXPECT_STREQ(test, mode->name, "800x600");
+
+ drm_mode_destroy(ctx->drm, mode);
+}
+
+/**
+ * dm_test_add_common_modes_non_edp_noop - Test non-eDP/LVDS adds no modes
+ * @test: The KUnit test context
+ *
+ * Common scaled modes are only added for eDP/LVDS panels; an HDMI connector
+ * is left untouched.
+ */
+static void dm_test_add_common_modes_non_edp_noop(struct kunit *test)
+{
+ struct dm_test_modes_ctx *ctx =
+ dm_test_modes_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ ctx->aenc->native_mode.hdisplay = 1920;
+ ctx->aenc->native_mode.vdisplay = 1200;
+
+ amdgpu_dm_connector_add_common_modes(&ctx->aenc->base,
+ &ctx->aconnector->base);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 0);
+}
+
+/**
+ * dm_test_add_common_modes_edp_adds - Test eDP adds the smaller common modes
+ * @test: The KUnit test context
+ *
+ * For an eDP panel with a 1920x1200 native mode every common mode strictly
+ * smaller than the native one is added (10 of the 11 entries).
+ */
+static void dm_test_add_common_modes_edp_adds(struct kunit *test)
+{
+ struct dm_test_modes_ctx *ctx =
+ dm_test_modes_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+
+ ctx->aenc->native_mode.hdisplay = 1920;
+ ctx->aenc->native_mode.vdisplay = 1200;
+
+ amdgpu_dm_connector_add_common_modes(&ctx->aenc->base,
+ &ctx->aconnector->base);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 10);
+}
+
+/**
+ * dm_test_ddc_get_modes_null_edid - Test a NULL EDID resets the mode count
+ * @test: The KUnit test context
+ */
+static void dm_test_ddc_get_modes_null_edid(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+ struct amdgpu_dm_connector *aconnector =
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+
+ aconnector->num_modes = 5;
+
+ amdgpu_dm_connector_ddc_get_modes(&aconnector->base, NULL);
+
+ KUNIT_EXPECT_EQ(test, aconnector->num_modes, 0);
+}
+
+/**
+ * dm_test_add_fs_modes_no_preferred_mode - Test no preferred mode yields no modes
+ * @test: The KUnit test context
+ *
+ * A writeback connector has no highest-refresh-rate mode, so add_fs_modes()
+ * cannot build any FreeSync video modes and returns 0.
+ */
+static void dm_test_add_fs_modes_no_preferred_mode(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ aconnector->base.connector_type = DRM_MODE_CONNECTOR_WRITEBACK;
+
+ KUNIT_EXPECT_EQ(test, (int)add_fs_modes(aconnector), 0);
+}
+
+/**
+ * dm_test_add_freesync_modes_null_edid_noop - Test NULL EDID adds no modes
+ * @test: The KUnit test context
+ *
+ * Without an EDID the FreeSync video modes cannot be derived, so the mode
+ * count is left unchanged.
+ */
+static void dm_test_add_freesync_modes_null_edid_noop(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ aconnector->num_modes = 7;
+
+ amdgpu_dm_connector_add_freesync_modes(&aconnector->base, NULL);
+
+ KUNIT_EXPECT_EQ(test, aconnector->num_modes, 7);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -4608,6 +4895,28 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
/* handle_edid_mgmt */
KUNIT_CASE(dm_test_handle_edid_mgmt_dp_sets_link_caps),
KUNIT_CASE(dm_test_handle_edid_mgmt_non_dp_leaves_caps),
+ /* amdgpu_dm_connector_funcs_force */
+ KUNIT_CASE(dm_test_funcs_force_no_edid),
+ /* dm_validate_stream_and_context */
+ KUNIT_CASE(dm_test_validate_stream_null_stream),
+ /* amdgpu_dm_connector_to_encoder */
+ KUNIT_CASE(dm_test_to_encoder_no_encoder),
+ KUNIT_CASE(dm_test_to_encoder_returns_attached),
+ /* amdgpu_dm_get_native_mode */
+ KUNIT_CASE(dm_test_native_mode_no_encoder),
+ KUNIT_CASE(dm_test_native_mode_empty_probed_zeroes_clock),
+ KUNIT_CASE(dm_test_native_mode_copies_preferred),
+ /* amdgpu_dm_create_common_mode */
+ KUNIT_CASE(dm_test_create_common_mode_overrides),
+ /* amdgpu_dm_connector_add_common_modes */
+ KUNIT_CASE(dm_test_add_common_modes_non_edp_noop),
+ KUNIT_CASE(dm_test_add_common_modes_edp_adds),
+ /* amdgpu_dm_connector_ddc_get_modes */
+ KUNIT_CASE(dm_test_ddc_get_modes_null_edid),
+ /* add_fs_modes */
+ KUNIT_CASE(dm_test_add_fs_modes_no_preferred_mode),
+ /* amdgpu_dm_connector_add_freesync_modes */
+ KUNIT_CASE(dm_test_add_freesync_modes_null_edid_noop),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 46/70] drm/amd/display: Add i2c and EDID parsing tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (44 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 45/70] drm/amd/display: Add mode helper tests for connector Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 47/70] drm/amd/display: Add mode validation and CEC " Wayne Lin
` (23 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for the i2c and EDID parsing helpers:
amdgpu_dm_i2c_func(), amdgpu_dm_i2c_xfer(), get_amd_vsdb(),
parse_hdmi_amd_vsdb() and parse_edid_displayid_vrr().
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 15 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 10 +
.../tests/amdgpu_dm_connector_test.c | 249 ++++++++++++++++++
3 files changed, 269 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 557cc6492529..72c12484d218 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -2999,7 +2999,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
}
}
-static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
+STATIC_IFN_KUNIT int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num)
{
struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
@@ -3043,11 +3043,13 @@ static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
kfree(cmd.payloads);
return result;
}
+EXPORT_IF_KUNIT(amdgpu_dm_i2c_xfer);
-static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap)
+STATIC_IFN_KUNIT u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
+EXPORT_IF_KUNIT(amdgpu_dm_i2c_func);
static const struct i2c_algorithm amdgpu_dm_i2c_algo = {
.master_xfer = amdgpu_dm_i2c_xfer,
@@ -3409,7 +3411,7 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
return ret;
}
-static void parse_edid_displayid_vrr(struct drm_connector *connector,
+STATIC_IFN_KUNIT void parse_edid_displayid_vrr(struct drm_connector *connector,
const struct edid *edid)
{
u8 *edid_ext = NULL;
@@ -3451,8 +3453,9 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
j++;
}
}
+EXPORT_IF_KUNIT(parse_edid_displayid_vrr);
-static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+STATIC_IFN_KUNIT int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
struct drm_connector *connector = &aconnector->base;
@@ -3462,8 +3465,9 @@ static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
return connector->display_info.amd_vsdb.version != 0;
}
+EXPORT_IF_KUNIT(get_amd_vsdb);
-static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+STATIC_IFN_KUNIT int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
const struct edid *edid,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
@@ -3494,6 +3498,7 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
return valid_vsdb_found ? i : -ENODEV;
}
+EXPORT_IF_KUNIT(parse_hdmi_amd_vsdb);
/**
* amdgpu_dm_update_freesync_caps - Update Freesync capabilities
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index b237e8f864db..b64c81477a60 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -146,6 +146,16 @@ int amdgpu_dm_encoder_init(struct drm_device *dev,
uint32_t link_index);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num);
+u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap);
+void parse_edid_displayid_vrr(struct drm_connector *connector,
+ const struct edid *edid);
+int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info);
+int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+ const struct edid *edid,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info);
void amdgpu_dm_connector_funcs_force(struct drm_connector *connector);
enum dc_status dm_validate_stream_and_context(struct dc *dc,
struct dc_stream_state *stream);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 459f0eda9a69..f60ce381683e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -17,6 +17,7 @@
#include <drm/drm_modes.h>
#include <drm/drm_property.h>
#include <linux/hdmi.h>
+#include <linux/i2c.h>
#include "dc.h"
#include "amdgpu.h"
@@ -4666,6 +4667,239 @@ static void dm_test_add_freesync_modes_null_edid_noop(struct kunit *test)
KUNIT_EXPECT_EQ(test, aconnector->num_modes, 7);
}
+/* EDID extension block tag values (avoids pulling in private drm headers). */
+#define DM_TEST_CEA_EXT 0x02
+#define DM_TEST_DISPLAYID_EXT 0x70
+
+/**
+ * dm_test_i2c_func_returns_flags - Test the i2c functionality flags
+ * @test: The KUnit test context
+ *
+ * The algorithm advertises plain I2C plus emulated SMBUS regardless of the
+ * adapter argument, which it never dereferences.
+ */
+static void dm_test_i2c_func_returns_flags(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_i2c_func(NULL),
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL);
+}
+
+/**
+ * dm_test_i2c_xfer_no_ddc_pin - Test transfers without a DDC pin are rejected
+ * @test: The KUnit test context
+ *
+ * When the backing ddc_service has no ddc_pin the transfer bails out early
+ * with -EIO before touching the message buffers or the dc handle.
+ */
+static void dm_test_i2c_xfer_no_ddc_pin(struct kunit *test)
+{
+ struct amdgpu_i2c_adapter *i2c;
+ struct ddc_service *ddc;
+
+ i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, i2c);
+ ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ddc);
+
+ i2c->ddc_service = ddc;
+ i2c_set_adapdata(&i2c->base, i2c);
+
+ /* ddc->ddc_pin is NULL -> transfer is rejected with -EIO. */
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_i2c_xfer(&i2c->base, NULL, 0), -EIO);
+}
+
+/**
+ * dm_test_get_amd_vsdb_unsupported - Test a zero VSDB version reports no support
+ * @test: The KUnit test context
+ */
+static void dm_test_get_amd_vsdb_unsupported(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ aconnector->base.display_info.amd_vsdb.version = 0;
+ aconnector->base.display_info.amd_vsdb.replay_mode = false;
+
+ KUNIT_EXPECT_EQ(test, get_amd_vsdb(aconnector, &vsdb_info), 0);
+ KUNIT_EXPECT_EQ(test, vsdb_info.amd_vsdb_version, 0);
+}
+
+/**
+ * dm_test_get_amd_vsdb_supported - Test a non-zero VSDB version is reported
+ * @test: The KUnit test context
+ *
+ * The display info's VSDB version and replay mode are copied out and a
+ * non-zero version reports support.
+ */
+static void dm_test_get_amd_vsdb_supported(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ aconnector->base.display_info.amd_vsdb.version = 2;
+ aconnector->base.display_info.amd_vsdb.replay_mode = true;
+
+ KUNIT_EXPECT_EQ(test, get_amd_vsdb(aconnector, &vsdb_info), 1);
+ KUNIT_EXPECT_EQ(test, vsdb_info.amd_vsdb_version, 2);
+ KUNIT_EXPECT_TRUE(test, vsdb_info.replay_mode);
+}
+
+/**
+ * dm_test_parse_hdmi_amd_vsdb_null_edid - Test NULL EDID returns -ENODEV
+ * @test: The KUnit test context
+ */
+static void dm_test_parse_hdmi_amd_vsdb_null_edid(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ KUNIT_EXPECT_EQ(test,
+ parse_hdmi_amd_vsdb(aconnector, NULL, &vsdb_info),
+ -ENODEV);
+}
+
+/**
+ * dm_test_parse_hdmi_amd_vsdb_no_extensions - Test EDID without extensions
+ * @test: The KUnit test context
+ *
+ * An EDID that declares no extension blocks has no CEA block to parse.
+ */
+static void dm_test_parse_hdmi_amd_vsdb_no_extensions(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
+ struct edid *edid;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ edid = kunit_kzalloc(test, sizeof(*edid), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, edid);
+
+ edid->extensions = 0;
+
+ KUNIT_EXPECT_EQ(test,
+ parse_hdmi_amd_vsdb(aconnector, edid, &vsdb_info),
+ -ENODEV);
+}
+
+/**
+ * dm_test_parse_hdmi_amd_vsdb_no_cea_ext - Test EDID with no CEA extension
+ * @test: The KUnit test context
+ *
+ * An extension block that is not a CEA block leaves no VSDB to parse.
+ */
+static void dm_test_parse_hdmi_amd_vsdb_no_cea_ext(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
+ struct edid *edid;
+ u8 *raw;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ /* Base block + one extension block that is NOT a CEA extension. */
+ raw = kunit_kzalloc(test, 2 * EDID_LENGTH, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, raw);
+ edid = (struct edid *)raw;
+ edid->extensions = 1;
+ raw[EDID_LENGTH] = DM_TEST_DISPLAYID_EXT;
+
+ KUNIT_EXPECT_EQ(test,
+ parse_hdmi_amd_vsdb(aconnector, edid, &vsdb_info),
+ -ENODEV);
+}
+
+/**
+ * dm_test_parse_displayid_vrr_null_edid - Test NULL EDID leaves range untouched
+ * @test: The KUnit test context
+ */
+static void dm_test_parse_displayid_vrr_null_edid(struct kunit *test)
+{
+ struct drm_connector *connector;
+
+ connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+
+ parse_edid_displayid_vrr(connector, NULL);
+
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.max_vfreq, 0);
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.min_vfreq, 0);
+}
+
+/**
+ * dm_test_parse_displayid_vrr_no_displayid - Test EDID without a DisplayID ext
+ * @test: The KUnit test context
+ *
+ * Without a DisplayID extension block there is no dynamic range to extract.
+ */
+static void dm_test_parse_displayid_vrr_no_displayid(struct kunit *test)
+{
+ struct drm_connector *connector;
+ struct edid *edid;
+ u8 *raw;
+
+ connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ raw = kunit_kzalloc(test, 2 * EDID_LENGTH, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, raw);
+ edid = (struct edid *)raw;
+ edid->extensions = 1;
+ raw[EDID_LENGTH] = DM_TEST_CEA_EXT;
+
+ parse_edid_displayid_vrr(connector, edid);
+
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.max_vfreq, 0);
+}
+
+/**
+ * dm_test_parse_displayid_vrr_sets_range - Test a DisplayID VRR block is parsed
+ * @test: The KUnit test context
+ *
+ * A DisplayID dynamic video timing range descriptor populates the connector's
+ * monitor refresh range.
+ */
+static void dm_test_parse_displayid_vrr_sets_range(struct kunit *test)
+{
+ struct drm_connector *connector;
+ struct edid *edid;
+ u8 *raw, *ext;
+
+ connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+ raw = kunit_kzalloc(test, 2 * EDID_LENGTH, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, raw);
+ edid = (struct edid *)raw;
+ edid->extensions = 1;
+
+ ext = raw + EDID_LENGTH;
+ ext[0] = DM_TEST_DISPLAYID_EXT;
+ /*
+ * DisplayID dynamic video timing range descriptor, parsed from offset
+ * 1: tag 0x25, flags 0 (single-byte max), payload length 9, then the
+ * min/max vfreq bytes.
+ */
+ ext[1] = 0x25;
+ ext[2] = 0x00;
+ ext[3] = 9;
+ ext[10] = 40;
+ ext[11] = 144;
+
+ parse_edid_displayid_vrr(connector, edid);
+
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.min_vfreq, 40);
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.max_vfreq, 144);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -4917,6 +5151,21 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_add_fs_modes_no_preferred_mode),
/* amdgpu_dm_connector_add_freesync_modes */
KUNIT_CASE(dm_test_add_freesync_modes_null_edid_noop),
+ /* amdgpu_dm_i2c_func */
+ KUNIT_CASE(dm_test_i2c_func_returns_flags),
+ /* amdgpu_dm_i2c_xfer */
+ KUNIT_CASE(dm_test_i2c_xfer_no_ddc_pin),
+ /* get_amd_vsdb */
+ KUNIT_CASE(dm_test_get_amd_vsdb_unsupported),
+ KUNIT_CASE(dm_test_get_amd_vsdb_supported),
+ /* parse_hdmi_amd_vsdb */
+ KUNIT_CASE(dm_test_parse_hdmi_amd_vsdb_null_edid),
+ KUNIT_CASE(dm_test_parse_hdmi_amd_vsdb_no_extensions),
+ KUNIT_CASE(dm_test_parse_hdmi_amd_vsdb_no_cea_ext),
+ /* parse_edid_displayid_vrr */
+ KUNIT_CASE(dm_test_parse_displayid_vrr_null_edid),
+ KUNIT_CASE(dm_test_parse_displayid_vrr_no_displayid),
+ KUNIT_CASE(dm_test_parse_displayid_vrr_sets_range),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 47/70] drm/amd/display: Add mode validation and CEC tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (45 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 46/70] drm/amd/display: Add i2c and EDID parsing " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 48/70] drm/amd/display: Add stream validation " Wayne Lin
` (22 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for connector mode validation and HDMI CEC:
mode_valid rejects interlaced and doublescan modes, set_edid with no
notifier, and the S3 suspend/resume CEC handlers.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 3 +
.../tests/amdgpu_dm_connector_test.c | 105 ++++++++++++++++++
2 files changed, 108 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 72c12484d218..3fa2392549eb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -356,6 +356,7 @@ void amdgpu_dm_hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector)
cec_notifier_set_phys_addr(n,
connector->display_info.source_physical_address);
}
+EXPORT_IF_KUNIT(amdgpu_dm_hdmi_cec_set_edid);
void amdgpu_dm_s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend)
{
@@ -376,6 +377,7 @@ void amdgpu_dm_s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend)
}
drm_connector_list_iter_end(&conn_iter);
}
+EXPORT_IF_KUNIT(amdgpu_dm_s3_handle_hdmi_cec);
struct drm_connector *
@@ -2254,6 +2256,7 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
/* TODO: error handling*/
return result;
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_mode_valid);
int amdgpu_dm_fill_hdr_info_packet(const struct drm_connector_state *state,
struct dc_info_packet *out)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index f60ce381683e..cfb114d5b879 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -4900,6 +4900,103 @@ static void dm_test_parse_displayid_vrr_sets_range(struct kunit *test)
KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.max_vfreq, 144);
}
+/**
+ * dm_test_mode_valid_interlace_rejected - Test interlaced modes are rejected
+ * @test: The KUnit test context
+ *
+ * Interlaced modes are rejected up front with MODE_ERROR before any sink or
+ * stream validation is attempted.
+ */
+static void dm_test_mode_valid_interlace_rejected(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_display_mode *mode;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ mode = kunit_kzalloc(test, sizeof(*mode), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ mode->flags = DRM_MODE_FLAG_INTERLACE;
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_connector_mode_valid(&aconnector->base, mode),
+ MODE_ERROR);
+}
+
+/**
+ * dm_test_mode_valid_dblscan_rejected - Test doublescan modes are rejected
+ * @test: The KUnit test context
+ *
+ * Doublescan modes are rejected up front with MODE_ERROR.
+ */
+static void dm_test_mode_valid_dblscan_rejected(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_display_mode *mode;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ mode = kunit_kzalloc(test, sizeof(*mode), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ mode->flags = DRM_MODE_FLAG_DBLSCAN;
+
+ KUNIT_EXPECT_EQ(test,
+ amdgpu_dm_connector_mode_valid(&aconnector->base, mode),
+ MODE_ERROR);
+}
+
+/**
+ * dm_test_hdmi_cec_set_edid_no_notifier - Test the no-notifier no-op path
+ * @test: The KUnit test context
+ *
+ * With aconnector->notifier NULL the function returns early and must not crash.
+ */
+static void dm_test_hdmi_cec_set_edid_no_notifier(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ amdgpu_dm_hdmi_cec_set_edid(aconnector);
+}
+
+/**
+ * dm_test_s3_handle_hdmi_cec_suspend - Test the suspend pass over connectors
+ * @test: The KUnit test context
+ *
+ * Suspend iterates all connectors, skipping writeback ones and calling the
+ * unset path on the rest; with NULL notifiers this is a crash-free no-op.
+ */
+static void dm_test_s3_handle_hdmi_cec_suspend(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_WRITEBACK);
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+
+ amdgpu_dm_s3_handle_hdmi_cec(drm, true);
+}
+
+/**
+ * dm_test_s3_handle_hdmi_cec_resume - Test the resume pass over connectors
+ * @test: The KUnit test context
+ *
+ * Resume iterates all connectors, skipping writeback ones and calling the set
+ * path on the rest; with NULL notifiers this is a crash-free no-op.
+ */
+static void dm_test_s3_handle_hdmi_cec_resume(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_WRITEBACK);
+ dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+
+ amdgpu_dm_s3_handle_hdmi_cec(drm, false);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -5166,6 +5263,14 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_parse_displayid_vrr_null_edid),
KUNIT_CASE(dm_test_parse_displayid_vrr_no_displayid),
KUNIT_CASE(dm_test_parse_displayid_vrr_sets_range),
+ /* amdgpu_dm_connector_mode_valid */
+ KUNIT_CASE(dm_test_mode_valid_interlace_rejected),
+ KUNIT_CASE(dm_test_mode_valid_dblscan_rejected),
+ /* amdgpu_dm_hdmi_cec_set_edid */
+ KUNIT_CASE(dm_test_hdmi_cec_set_edid_no_notifier),
+ /* amdgpu_dm_s3_handle_hdmi_cec */
+ KUNIT_CASE(dm_test_s3_handle_hdmi_cec_suspend),
+ KUNIT_CASE(dm_test_s3_handle_hdmi_cec_resume),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 48/70] drm/amd/display: Add stream validation tests for connector
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (46 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 47/70] drm/amd/display: Add mode validation and CEC " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:37 ` [PATCH 49/70] drm/amd/display: Adjust structure dml2_display_dlg_regs Wayne Lin
` (21 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Add KUnit coverage for amdgpu_dm_create_validate_stream_for_sink()
and amdgpu_dm_connector_funcs_update_after_detect(): null dm_state,
MST no-op, and unchanged sink handling.
Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 2 +
.../tests/amdgpu_dm_connector_test.c | 68 +++++++++++++++++++
2 files changed, 70 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 3fa2392549eb..da6ec75bb0f9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -650,6 +650,7 @@ void amdgpu_dm_update_connector_after_detect(
if (!drm_kms_helper_is_poll_worker())
mutex_unlock(&dev->mode_config.mutex);
}
+EXPORT_IF_KUNIT(amdgpu_dm_update_connector_after_detect);
enum dc_color_depth
amdgpu_dm_convert_color_depth_from_display_info(const struct drm_connector *connector,
@@ -2203,6 +2204,7 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
return stream;
}
+EXPORT_IF_KUNIT(amdgpu_dm_create_validate_stream_for_sink);
enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index cfb114d5b879..b58bb2d3309c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -4997,6 +4997,69 @@ static void dm_test_s3_handle_hdmi_cec_resume(struct kunit *test)
amdgpu_dm_s3_handle_hdmi_cec(drm, false);
}
+/**
+ * dm_test_create_validate_stream_null_dm_state - Test NULL state returns NULL
+ * @test: The KUnit test context
+ *
+ * Without a connector state there is nothing to validate against, so the
+ * helper bails out with NULL before touching the dc handle.
+ */
+static void dm_test_create_validate_stream_null_dm_state(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ KUNIT_EXPECT_NULL(test,
+ amdgpu_dm_create_validate_stream_for_sink(&aconnector->base,
+ NULL, NULL, NULL));
+}
+
+/**
+ * dm_test_update_after_detect_mst_noop - Test MST connectors are left to drm_mst
+ * @test: The KUnit test context
+ *
+ * An MST connector is handled by the drm_mst framework, so the function
+ * returns immediately and never dereferences the (NULL) dc_link.
+ */
+static void dm_test_update_after_detect_mst_noop(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+ aconnector->mst_mgr.mst_state = true;
+
+ amdgpu_dm_update_connector_after_detect(aconnector);
+}
+
+/**
+ * dm_test_update_after_detect_sink_unchanged - Test the short-pulse no-op path
+ * @test: The KUnit test context
+ *
+ * When the link reports no local sink and the connector already has no
+ * dc_sink, the "sink didn't change" path returns without touching DC.
+ */
+static void dm_test_update_after_detect_sink_unchanged(struct kunit *test)
+{
+ struct drm_device *drm = dm_test_alloc_drm(test);
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+
+ aconnector = dm_test_add_connector(test, drm, DRM_MODE_CONNECTOR_HDMIA);
+ link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link);
+
+ aconnector->dc_link = link;
+
+ /* link->local_sink and aconnector->dc_sink are both NULL. */
+ amdgpu_dm_update_connector_after_detect(aconnector);
+
+ KUNIT_EXPECT_NULL(test, aconnector->dc_sink);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -5271,6 +5334,11 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
/* amdgpu_dm_s3_handle_hdmi_cec */
KUNIT_CASE(dm_test_s3_handle_hdmi_cec_suspend),
KUNIT_CASE(dm_test_s3_handle_hdmi_cec_resume),
+ /* amdgpu_dm_create_validate_stream_for_sink */
+ KUNIT_CASE(dm_test_create_validate_stream_null_dm_state),
+ /* amdgpu_dm_update_connector_after_detect */
+ KUNIT_CASE(dm_test_update_after_detect_mst_noop),
+ KUNIT_CASE(dm_test_update_after_detect_sink_unchanged),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 49/70] drm/amd/display: Adjust structure dml2_display_dlg_regs
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (47 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 48/70] drm/amd/display: Add stream validation " Wayne Lin
@ 2026-07-15 13:37 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 50/70] drm/amd/display: Revert Fix DMSS not triggering for HDR to SDR transition Wayne Lin
` (20 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:37 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dillon Varone
From: Aurabindo Pillai <aurabindo.pillai@amd.com>
Adjust structure dml2_display_dlg_regs for future use
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
index 799e72243418..5a5f7b92c324 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
@@ -46,6 +46,9 @@ struct dml2_display_dlg_regs {
uint32_t dst_y_delta_drq_limit;
uint32_t refcyc_per_vm_dmdata;
uint32_t dmdata_dl_delta;
+ uint32_t dst_y_svp_drq_limit;
+ uint32_t force_prefetch_to_vblank;
+ uint32_t force_cursor_to_disp_pref;
// MRQ
uint32_t refcyc_per_meta_chunk_vblank_l;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 50/70] drm/amd/display: Revert Fix DMSS not triggering for HDR to SDR transition
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (48 preceding siblings ...)
2026-07-15 13:37 ` [PATCH 49/70] drm/amd/display: Adjust structure dml2_display_dlg_regs Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 51/70] drm/amd/display: Introduce dc_probe public object model Wayne Lin
` (19 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Justin Chen, Joshua Aberback,
Yihan Zhu
From: Justin Chen <Justin.Chen5@amd.com>
Reverting this commit as it causes a regression lighting up eDP panels:
This reverts commit 1fecc9989637 (drm/amd/display: Fix DMSS not triggering
for HDR to SDR transition)
Reviewed-by: Joshua Aberback <joshua.aberback@amd.com>
Reviewed-by: Yihan Zhu <yihan.zhu@amd.com>
Signed-off-by: Justin Chen <Justin.Chen5@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/dc/hwss/dce110/dce110_hwseq.c | 12 +++-------
.../amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 21 +++++------------
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 7 ++----
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 23 +++++--------------
.../drm/amd/display/modules/power/power_psr.c | 7 ------
.../amd/display/modules/power/power_replay.c | 7 ------
6 files changed, 17 insertions(+), 60 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index 4830a0d94177..262982ca5ad9 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -1286,9 +1286,7 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
return;
if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
- if (link->skip_implict_edp_power_control)
- return;
- if (hws)
+ if (!link->skip_implict_edp_power_control && hws)
hws->funcs.edp_backlight_control(link, false);
link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
}
@@ -1794,9 +1792,7 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
dc->link_srv->set_dsc_enable(pipe_ctx, true);
}
- if (!stream->dpms_off &&
- !(link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control))
+ if (!stream->dpms_off)
dc->link_srv->set_dpms_on(context, pipe_ctx);
/* DCN3.1 FPGA Workaround
@@ -1815,9 +1811,7 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
* is constructed with the same sink). Make sure not to override
* and link programming on the main.
*/
- if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM &&
- !(link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control)) {
+ if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) {
pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false;
}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
index 6f1ad651ed2c..b6f3c0480ab6 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
@@ -537,11 +537,9 @@ static void dcn31_reset_back_end_for_pipe(
}
ASSERT(!pipe_ctx->top_pipe);
- link = pipe_ctx->stream->link;
+ dc->hwss.set_abm_immediate_disable(pipe_ctx);
- if (!(link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control))
- dc->hwss.set_abm_immediate_disable(pipe_ctx);
+ link = pipe_ctx->stream->link;
if (dc->hwseq)
dc->hwseq->wa_state.skip_blank_stream = false;
@@ -557,11 +555,9 @@ static void dcn31_reset_back_end_for_pipe(
pipe_ctx->stream_res.tg,
OPTC_DSC_DISABLED, 0, 0);
- if (!(link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control)) {
- pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
- pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
- }
+ pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
+
+ pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
@@ -590,12 +586,7 @@ static void dcn31_reset_back_end_for_pipe(
* screen only, the dpms_off would be true but
* VBIOS lit up eDP, so check link status too.
*/
- if (link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control) {
- /* DMSS is holding the panel across the commit; skip dpms-off. */
- if (pipe_ctx->stream_res.audio)
- dc->hwss.disable_audio_stream(pipe_ctx);
- } else if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
+ if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
dc->link_srv->set_dpms_off(pipe_ctx);
else if (pipe_ctx->stream_res.audio)
dc->hwss.disable_audio_stream(pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
index 4ed7480d1efa..f14c39a643da 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
@@ -1818,11 +1818,8 @@ void dcn35_disable_link_output(struct dc_link *link,
disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
} else {
- if (!(signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control)) {
- link_hwss->disable_link_output(link, link_res, signal);
- link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
- }
+ link_hwss->disable_link_output(link, link_res, signal);
+ link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
}
/*
* Add the logic to extract BOTH power up and power down sequences
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 161ef57ebce1..54afd42d73ed 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -1102,11 +1102,8 @@ void dcn401_disable_link_output(struct dc_link *link,
disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
} else {
- if (!(signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control)) {
- link_hwss->disable_link_output(link, link_res, signal);
- link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
- }
+ link_hwss->disable_link_output(link, link_res, signal);
+ link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
}
if (signal == SIGNAL_TYPE_EDP &&
@@ -2154,12 +2151,7 @@ void dcn401_reset_back_end_for_pipe(
* screen only, the dpms_off would be true but
* VBIOS lit up eDP, so check link status too.
*/
- if (link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control) {
- /* DMSS is holding the panel across the commit; skip dpms-off. */
- if (pipe_ctx->stream_res.audio)
- dc->hwss.disable_audio_stream(pipe_ctx);
- } else if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
+ if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
dc->link_srv->set_dpms_off(pipe_ctx);
else if (pipe_ctx->stream_res.audio)
dc->hwss.disable_audio_stream(pipe_ctx);
@@ -2184,15 +2176,12 @@ void dcn401_reset_back_end_for_pipe(
* parent pipe.
*/
if (pipe_ctx->top_pipe == NULL) {
- if (!(link->connector_signal == SIGNAL_TYPE_EDP &&
- link->skip_implict_edp_power_control)) {
- dc->hwss.set_abm_immediate_disable(pipe_ctx);
+ dc->hwss.set_abm_immediate_disable(pipe_ctx);
- pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
+ pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
- pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
- }
+ pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_psr.c b/drivers/gpu/drm/amd/display/modules/power/power_psr.c
index 0ad4c4924696..5ecb570c204e 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_psr.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_psr.c
@@ -58,13 +58,6 @@ bool mod_power_psr_notify_mode_change(struct mod_power *mod_power,
// stream_index is passed as validated parameter
active_psr_events = core_power->map[stream_index].psr_events;
- /* DMSS holds the panel in a forced PSR freeze (e.g. during HDR/SDR toggle).
- * Re-running edp_setup_psr would reprogram DPCD 0x170 and disturb the freeze,
- * so skip the PSR re-setup until DMSS releases the override.
- */
- if (active_psr_events & psr_event_os_override_hold)
- return false;
-
/* Calculate PSR configurations */
mod_power_calc_psr_configs(&psr_config, link, stream);
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_replay.c b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
index 1ad2ee01d560..e782501442c4 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_replay.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
@@ -805,13 +805,6 @@ void mod_power_replay_notify_mode_change(struct mod_power *mod_power,
core_power = MOD_POWER_TO_CORE(mod_power);
active_replay_events = core_power->map[stream_index].replay_events;
- /* DMSS holds the panel in a forced freeze (e.g. during HDR/SDR toggle).
- * Re-running dp_setup_replay would reprogram DPCD 0x37B and disturb the
- * freeze, so skip the replay re-setup until DMSS releases the override.
- */
- if (active_replay_events & replay_event_os_override_hold)
- return;
-
link->replay_settings.replay_smu_opt_enable =
(link->replay_settings.config.replay_smu_opt_supported &&
mod_power_only_edp(dc->current_state, stream));
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 51/70] drm/amd/display: Introduce dc_probe public object model
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (49 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 50/70] drm/amd/display: Revert Fix DMSS not triggering for HDR to SDR transition Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 52/70] drm/amd/display: Introduce dc_update_state unified commit interface Wayne Lin
` (18 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="Y", Size: 6877 bytes --]
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
Performance measurement needs to commit through the same update entry
point as planes and streams, with DM working against an abstraction of
what to measure rather than the hardware block that performs it.
[How]
Add dc_probe.h defining dc_probe_type (the measurable quantity),
dc_probe_target_state (not measuring / measuring / measured),
dc_probe_scope (global only, per-stream/plane deferred), and
dc_probe_state (an inline descriptor with copy semantics, no refcount).
dc_state carries the committed set as probes[MAX_PROBES] plus
probe_count. dc_state_update carries dc_probe_updates as the desired
absolute set that DC diffs against the committed set.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/dc/core/dc_state.c | 3 +
drivers/gpu/drm/amd/display/dc/dc.h | 9 ++
drivers/gpu/drm/amd/display/dc/dc_probe.h | 97 +++++++++++++++++++
.../gpu/drm/amd/display/dc/inc/core_types.h | 12 +++
4 files changed, 121 insertions(+)
create mode 100644 drivers/gpu/drm/amd/display/dc/dc_probe.h
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index 1f183ae85a3f..a5df0101b504 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -360,6 +360,9 @@ void dc_state_destruct(struct dc_state *state)
}
state->phantom_plane_count = 0;
+ memset(state->probes, 0, sizeof(state->probes));
+ state->probe_count = 0;
+
state->stream_mask = 0;
memset(&state->res_ctx, 0, sizeof(state->res_ctx));
memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg));
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 436277acd034..3e22c1f8d4db 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -29,6 +29,7 @@
#include "dc_types.h"
#include "dc_state.h"
#include "dc_plane.h"
+#include "dc_probe.h"
#include "grph_object_defs.h"
#include "logger_types.h"
#include "hdcp_msg_types.h"
@@ -2105,6 +2106,14 @@ struct dc_surface_update {
struct cm_hist_control *cm_hist_control;
};
+struct dc_state_update {
+ struct dc_stream_state *stream;
+ struct dc_stream_update *stream_update;
+ struct dc_surface_update *surface_updates;
+ int surface_count;
+ const struct dc_probe_updates *probe_updates;
+};
+
struct dc_underflow_debug_data {
struct dcn_hubbub_reg_state *hubbub_reg_state;
struct dcn_hubp_reg_state *hubp_reg_state[MAX_PIPES];
diff --git a/drivers/gpu/drm/amd/display/dc/dc_probe.h b/drivers/gpu/drm/amd/display/dc/dc_probe.h
new file mode 100644
index 000000000000..ebf33b162b63
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dc_probe.h
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2025 Advanced Micro Devices, Inc.
+
+#ifndef _DC_PROBE_H_
+#define _DC_PROBE_H_
+
+#include "os_types.h"
+
+/**
+ * enum dc_probe_type - What DM wants to probe.
+ *
+ * Each value names a measurable quantity as an abstraction. DC resolves it to
+ * whatever HW measurement block fulfills it. DM never selects the HW block.
+ */
+enum dc_probe_type {
+ DC_PROBE_PEAK_MEM_BW = 0,
+ DC_PROBE_AVG_MEM_BW,
+ DC_PROBE_MEM_LATENCY,
+ DC_PROBE_URGENT_RAMP_LATENCY,
+ DC_PROBE_URGENT_ASSERTION_COUNT,
+ DC_PROBE_PREFETCH_DATA_SIZE,
+};
+
+/**
+ * enum dc_probe_target_state - Target lifecycle state DM wants DC to reach.
+ *
+ * DM sets this to describe the final state DC must reach by the end of the
+ * commit. DC performs whatever HW transition sequence is needed.
+ *
+ * @DC_PROBE_NOT_MEASURING: probe inactive, no valid data available.
+ * @DC_PROBE_MEASURING: probe runs continuously. The latest value can be
+ * read back at any time and may differ on each read.
+ * @DC_PROBE_MEASURED: probe performed one shot. The result is latched and
+ * stays valid until DM transitions back to DC_PROBE_NOT_MEASURING.
+ */
+enum dc_probe_target_state {
+ DC_PROBE_NOT_MEASURING = 0,
+ DC_PROBE_MEASURING,
+ DC_PROBE_MEASURED,
+};
+
+/**
+ * enum dc_probe_scope_type - What the probe is scoped to.
+ * @DC_PROBE_SCOPE_GLOBAL: whole memory subsystem, no stream/plane selector.
+ *
+ * Only GLOBAL is implemented. Per-stream/plane scoping must select targets by
+ * stable id, not object pointer — dc_state copy semantics would dangle a raw
+ * pointer when the absolute-set commit removes or replaces the target.
+ */
+enum dc_probe_scope_type {
+ DC_PROBE_SCOPE_GLOBAL = 0,
+};
+
+/**
+ * struct dc_probe_scope - Selects what a probe measures against.
+ * @type: scope kind, only DC_PROBE_SCOPE_GLOBAL is implemented.
+ */
+struct dc_probe_scope {
+ enum dc_probe_scope_type type;
+};
+
+/**
+ * struct dc_probe_state - DM-authored descriptor of a single probe.
+ *
+ * A plain inline value with copy semantics: no allocation, no refcount. DC
+ * resolves each descriptor to a HW measurement instance and diffs the desired
+ * set against the committed set to plan the transition.
+ *
+ * @type: what to measure.
+ * @target_state: desired lifecycle state for this probe.
+ * @scope: what the probe is scoped to (GLOBAL only for now).
+ */
+struct dc_probe_state {
+ enum dc_probe_type type;
+ enum dc_probe_target_state target_state;
+ struct dc_probe_scope scope;
+};
+
+#define MAX_PROBES 1
+
+/**
+ * struct dc_probe_updates - Absolute set of probes DM wants active.
+ *
+ * Mirrors the plane/stream absolute-set model: the array is the complete
+ * desired set. DC compares it against the committed set to add, remove, or
+ * transition probes.
+ *
+ * @probes: desired probe descriptors.
+ * @probe_count: number of valid entries in @probes.
+ */
+struct dc_probe_updates {
+ struct dc_probe_state probes[MAX_PROBES];
+ int probe_count;
+};
+
+#endif /* _DC_PROBE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index cbbc1fb4b3dd..c42626101cd7 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -622,6 +622,7 @@ struct dc_state {
* @stream_status: Planes status on a given stream
*/
struct dc_stream_status stream_status[MAX_PIPES];
+
/**
* @phantom_streams: Stream state properties for phantoms
*/
@@ -645,6 +646,17 @@ struct dc_state {
* @stream_count: Total phantom planes in use
*/
uint8_t phantom_plane_count;
+
+ /**
+ * @probes: Committed absolute set of probe descriptors.
+ */
+ struct dc_probe_state probes[MAX_PROBES];
+
+ /**
+ * @probe_count: Number of valid entries in @probes.
+ */
+ int probe_count;
+
/**
* @res_ctx: Persistent state of resources
*/
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 52/70] drm/amd/display: Introduce dc_update_state unified commit interface
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (50 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 51/70] drm/amd/display: Introduce dc_probe public object model Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 53/70] drm/amd/display: Refactor dc_validation_set array into single root struct Wayne Lin
` (17 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
dc_update_planes_and_stream() is typed against surface/stream arrays only,
leaving no extensible slot for future object classes. The public entry
point names and signatures need to stay stable as new object classes are
added.
[How]
Introduce dc_update_state() and dc_check_state_update(), both taking a
dc_state_update root object. dc_update_state() routes stream and plane
updates through the existing pipeline. Keep dc_update_planes_and_stream()
and dc_check_update_surfaces_for_stream() as shims that delegate.
Change dc_update_state_init() to take a const dc_state_update* and rename
dc_update_planes_and_stream_{init,prepare,execute,cleanup} ->
dc_update_state_{init,prepare,execute,cleanup}.
Rename surface_update_type -> dc_update_type and
surface_update_descriptor -> dc_update_descriptor.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 188 ++++++++++++++-------
drivers/gpu/drm/amd/display/dc/dc.h | 19 ++-
drivers/gpu/drm/amd/display/dc/dc_stream.h | 21 ++-
3 files changed, 155 insertions(+), 73 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 188615873791..f1805b03f0db 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -151,8 +151,8 @@ static const char DC_BUILD_ID[] = "production-build";
/* Private functions */
static inline void elevate_update_type(
- struct surface_update_descriptor *descriptor,
- enum surface_update_type new_type,
+ struct dc_update_descriptor *descriptor,
+ enum dc_update_type new_type,
enum dc_lock_descriptor new_locks
)
{
@@ -2793,10 +2793,10 @@ static bool is_surface_in_context(
return false;
}
-static struct surface_update_descriptor get_plane_info_update_type(const struct dc_surface_update *u)
+static struct dc_update_descriptor get_plane_info_update_type(const struct dc_surface_update *u)
{
struct pipe_update_bits *update_bits = &u->surface->update_bits;
- struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
+ struct dc_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
if (!u->plane_info)
return update_type;
@@ -2883,12 +2883,12 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct
return update_type;
}
-static struct surface_update_descriptor get_scaling_info_update_type(
+static struct dc_update_descriptor get_scaling_info_update_type(
const struct dc_check_config *check_config,
const struct dc_surface_update *u)
{
struct pipe_update_bits *update_bits = &u->surface->update_bits;
- struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
+ struct dc_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
if (!u->scaling_info)
return update_type;
@@ -2939,11 +2939,11 @@ static struct surface_update_descriptor get_scaling_info_update_type(
return update_type;
}
-static struct surface_update_descriptor det_surface_update(
+static struct dc_update_descriptor det_surface_update(
const struct dc_check_config *check_config,
struct dc_surface_update *u)
{
- struct surface_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
+ struct dc_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
struct pipe_update_bits *update_bits = &u->surface->update_bits;
if (u->surface->force_full_update) {
@@ -2954,8 +2954,7 @@ static struct surface_update_descriptor det_surface_update(
dc_pipe_update_bits_clear(update_bits);
- struct surface_update_descriptor inner_type = get_plane_info_update_type(u);
-
+ struct dc_update_descriptor inner_type = get_plane_info_update_type(u);
elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor);
inner_type = get_scaling_info_update_type(check_config, u);
@@ -3097,13 +3096,13 @@ static void force_immediate_gsl_plane_flip(struct dc *dc, struct dc_surface_upda
}
}
-static struct surface_update_descriptor check_update_surfaces_for_stream(
+static struct dc_update_descriptor check_update_surfaces_for_stream(
const struct dc_check_config *check_config,
struct dc_surface_update *updates,
int surface_count,
struct dc_stream_update *stream_update)
{
- struct surface_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
+ struct dc_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
/* When countdown finishes, promote this flip to full to trigger deferred final transition */
if (check_config->deferred_transition_state && !check_config->transition_countdown_to_steady_state) {
@@ -3226,7 +3225,7 @@ static struct surface_update_descriptor check_update_surfaces_for_stream(
}
for (int i = 0 ; i < surface_count; i++) {
- struct surface_update_descriptor inner_type =
+ struct dc_update_descriptor inner_type =
det_surface_update(check_config, &updates[i]);
elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor);
@@ -3238,20 +3237,57 @@ static struct surface_update_descriptor check_update_surfaces_for_stream(
/*
* dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full)
*
- * See :c:type:`enum surface_update_type <surface_update_type>` for explanation of update types
+ * See :c:type:`enum dc_update_type <dc_update_type>` for explanation of update types
+ */
+/**
+ * dc_check_state_update - Classify a dc_state_update by locking / re-entrancy requirements.
+ * @check_config: ASIC capabilities and display configuration context
+ * @updates: root update object describing the full desired commit
+ *
+ * Determines whether the update requires a fast, medium, or full lock
+ * by inspecting the stream, stream_update, and surface_updates carried on
+ * the root object. Perfmon classification is reserved for a future slice.
+ *
+ * Return: dc_update_descriptor with update_type and lock_descriptor.
*/
-struct surface_update_descriptor dc_check_update_surfaces_for_stream(
+struct dc_update_descriptor dc_check_state_update(
+ const struct dc_check_config *check_config,
+ struct dc_state_update *updates)
+{
+ if (updates->stream_update)
+ stream_update_flags_clear(&updates->stream_update->stream->update_flags);
+ for (int i = 0; i < updates->surface_count; i++)
+ dc_pipe_update_bits_clear(&updates->surface_updates[i].surface->update_bits);
+
+ return check_update_surfaces_for_stream(check_config, updates->surface_updates,
+ updates->surface_count, updates->stream_update);
+}
+
+/**
+ * dc_check_update_surfaces_for_stream - Shim for dc_check_state_update.
+ * @check_config: ASIC capabilities and display configuration context
+ * @updates: array of surface update descriptors
+ * @surface_count: number of entries in @updates
+ * @stream_update: optional stream update
+ *
+ * Packs the individual arguments into a dc_state_update and forwards to
+ * dc_check_state_update(). Preserved for out-of-tree and incremental callers.
+ *
+ * Return: dc_update_descriptor with update_type and lock_descriptor.
+ */
+struct dc_update_descriptor dc_check_update_surfaces_for_stream(
const struct dc_check_config *check_config,
struct dc_surface_update *updates,
int surface_count,
struct dc_stream_update *stream_update)
{
- if (stream_update)
- stream_update_flags_clear(&stream_update->stream->update_flags);
- for (int i = 0; i < surface_count; i++)
- dc_pipe_update_bits_clear(&updates[i].surface->update_bits);
+ struct dc_state_update root = {
+ .surface_updates = updates,
+ .surface_count = surface_count,
+ .stream_update = stream_update,
+ };
- return check_update_surfaces_for_stream(check_config, updates, surface_count, stream_update);
+ return dc_check_state_update(check_config, &root);
}
static struct dc_stream_status *stream_get_status(
@@ -3269,7 +3305,7 @@ static struct dc_stream_status *stream_get_status(
return NULL;
}
-static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
+static const enum dc_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
static void copy_surface_update_to_plane(
struct dc_plane_state *surface,
@@ -3737,13 +3773,13 @@ static bool update_planes_and_stream_state(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type *new_update_type,
+ enum dc_update_type *new_update_type,
struct dc_state **new_context)
{
struct dc_state *context;
int i;
unsigned int j;
- enum surface_update_type update_type;
+ enum dc_update_type update_type;
const struct dc_stream_status *stream_status;
struct dc_context *dc_ctx = dc->ctx;
@@ -4152,7 +4188,7 @@ static void add_link_update_dsc_config_sequence(
static void commit_planes_do_stream_update_sequence(struct dc *dc,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type update_type,
+ enum dc_update_type update_type,
struct dc_state *context,
struct block_sequence block_sequence[MAX_HWSS_BLOCK_SEQUENCE_SIZE],
unsigned int *num_steps)
@@ -4323,7 +4359,7 @@ static void commit_planes_do_stream_update_sequence(struct dc *dc,
static void commit_planes_do_stream_update(struct dc *dc,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type update_type,
+ enum dc_update_type update_type,
struct dc_state *context)
{
unsigned int j;
@@ -4726,7 +4762,7 @@ static void commit_planes_for_stream_fast(struct dc *dc,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type update_type,
+ enum dc_update_type update_type,
struct dc_state *context)
{
int i;
@@ -4846,7 +4882,7 @@ static void commit_planes_for_stream(struct dc *dc,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type update_type,
+ enum dc_update_type update_type,
struct dc_state *context)
{
int i;
@@ -5929,7 +5965,7 @@ static bool update_planes_and_stream_v2(struct dc *dc,
struct dc_stream_update *stream_update)
{
struct dc_state *context;
- enum surface_update_type update_type;
+ enum dc_update_type update_type;
struct dc_fast_update fast_update[MAX_SURFACES] = {0};
/* In cases where MPO and split or ODM are used transitions can
@@ -6014,7 +6050,7 @@ static void commit_planes_and_stream_update_on_current_context(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type update_type)
+ enum dc_update_type update_type)
{
struct dc_fast_update fast_update[MAX_SURFACES] = {0};
@@ -6046,7 +6082,7 @@ static void commit_planes_and_stream_update_with_new_context(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
- enum surface_update_type update_type,
+ enum dc_update_type update_type,
struct dc_state *new_context)
{
bool skip_new_context = false;
@@ -6114,7 +6150,7 @@ static bool update_planes_and_stream_v3(struct dc *dc,
struct dc_stream_update *stream_update)
{
struct dc_state *new_context;
- enum surface_update_type update_type;
+ enum dc_update_type update_type;
/*
* When this function returns true and new_context is not equal to
@@ -6160,28 +6196,61 @@ static void clear_update_bits(struct dc_surface_update *srf_updates,
dc_pipe_update_bits_clear(&srf_updates[i].surface->update_bits);
}
+/**
+ * dc_update_state - Commit an absolute dc_state_update.
+ * @dc: DC structure
+ * @updates: root update object carrying stream, plane, and probe updates
+ *
+ * When stream is non-NULL the stream and its plane updates are committed via
+ * the init/prepare/execute/cleanup pipeline. Probe commit is reserved for a
+ * future slice. dc_update_planes_and_stream() is now a shim over this function.
+ *
+ * Return: true on success, false on failure.
+ */
+bool dc_update_state(struct dc *dc, struct dc_state_update *updates)
+{
+ if (updates->stream != NULL) {
+ struct dc_update_scratch_space *scratch = dc_update_state_init(dc, updates);
+ bool more = true;
+
+ while (more) {
+ if (!dc_update_state_prepare(scratch))
+ return false;
+
+ dc_update_state_execute(scratch);
+ more = dc_update_state_cleanup(scratch);
+ }
+ }
+
+ return true;
+}
+
+/**
+ * dc_update_planes_and_stream - Shim for dc_update_state.
+ * @dc: DC structure
+ * @srf_updates: array of surface update descriptors
+ * @surface_count: number of entries in @srf_updates
+ * @stream: target stream
+ * @stream_update: optional stream update
+ *
+ * Packs the individual arguments into a dc_state_update and forwards to
+ * dc_update_state(). Preserved for out-of-tree and incremental callers.
+ *
+ * Return: true on success; false on failure.
+ */
bool dc_update_planes_and_stream(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update)
{
- struct dc_update_scratch_space *scratch = dc_update_planes_and_stream_init(
- dc,
- srf_updates,
- surface_count,
- stream,
- stream_update
- );
- bool more = true;
-
- while (more) {
- if (!dc_update_planes_and_stream_prepare(scratch))
- return false;
+ struct dc_state_update updates = {
+ .stream = stream,
+ .stream_update = stream_update,
+ .surface_updates = srf_updates,
+ .surface_count = surface_count,
+ };
- dc_update_planes_and_stream_execute(scratch);
- more = dc_update_planes_and_stream_cleanup(scratch);
- }
- return true;
+ return dc_update_state(dc, &updates);
}
void dc_commit_updates_for_stream(struct dc *dc,
@@ -8114,7 +8183,7 @@ struct dc_update_scratch_space {
struct dc_stream_update *stream_update;
bool update_v3;
bool do_clear_update_bits;
- enum surface_update_type update_type;
+ enum dc_update_type update_type;
struct dc_state *new_context;
enum update_v3_flow flow;
struct dc_state *backup_context;
@@ -8417,23 +8486,20 @@ static bool update_planes_and_stream_cleanup_v3(
return false;
}
-struct dc_update_scratch_space *dc_update_planes_and_stream_init(
+struct dc_update_scratch_space *dc_update_state_init(
struct dc *dc,
- struct dc_surface_update *surface_updates,
- int surface_count,
- struct dc_stream_state *stream,
- struct dc_stream_update *stream_update
+ const struct dc_state_update *updates
)
{
const enum dce_version version = dc->ctx->dce_version;
- struct dc_update_scratch_space *scratch = stream->update_scratch;
+ struct dc_update_scratch_space *scratch = updates->stream->update_scratch;
*scratch = (struct dc_update_scratch_space){
.dc = dc,
- .surface_updates = surface_updates,
- .surface_count = surface_count,
- .stream = stream,
- .stream_update = stream_update,
+ .surface_updates = updates->surface_updates,
+ .surface_count = updates->surface_count,
+ .stream = updates->stream,
+ .stream_update = updates->stream_update,
.update_v3 = version >= DCN_VERSION_4_01 || version == DCN_VERSION_3_2 || version == DCN_VERSION_3_21,
.do_clear_update_bits = version >= DCN_VERSION_1_0,
};
@@ -8441,7 +8507,7 @@ struct dc_update_scratch_space *dc_update_planes_and_stream_init(
return scratch;
}
-bool dc_update_planes_and_stream_prepare(
+bool dc_update_state_prepare(
struct dc_update_scratch_space *scratch
)
{
@@ -8450,7 +8516,7 @@ bool dc_update_planes_and_stream_prepare(
: update_planes_and_stream_prepare_v2(scratch);
}
-void dc_update_planes_and_stream_execute(
+void dc_update_state_execute(
const struct dc_update_scratch_space *scratch
)
{
@@ -8459,7 +8525,7 @@ void dc_update_planes_and_stream_execute(
: update_planes_and_stream_execute_v2(scratch);
}
-bool dc_update_planes_and_stream_cleanup(
+bool dc_update_state_cleanup(
struct dc_update_scratch_space *scratch
)
{
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 3e22c1f8d4db..f06539df7f0a 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -519,7 +519,7 @@ struct dc_static_screen_params {
* underscan we don't expect to see this call at all.
*/
-enum surface_update_type {
+enum dc_update_type {
UPDATE_TYPE_FAST, /* super fast, safe to execute in isr */
UPDATE_TYPE_MED, /* ISR safe, most of programming needed, no bw/clk change*/
UPDATE_TYPE_FULL, /* may need to shuffle resources */
@@ -532,8 +532,8 @@ enum dc_lock_descriptor {
LOCK_DESCRIPTOR_GLOBAL = 0x4,
};
-struct surface_update_descriptor {
- enum surface_update_type update_type;
+struct dc_update_descriptor {
+ enum dc_update_type update_type;
enum dc_lock_descriptor lock_descriptor;
};
@@ -2114,6 +2114,19 @@ struct dc_state_update {
const struct dc_probe_updates *probe_updates;
};
+/**
+ * dc_update_state - Commit an absolute dc_state_update.
+ * @dc: DC structure
+ * @updates: root update object carrying stream, plane, and probe updates
+ *
+ * When stream is non-NULL the stream and its plane updates are committed via
+ * the init/prepare/execute/cleanup pipeline. Probe commit is reserved for a
+ * future slice. dc_update_planes_and_stream() is now a shim over this function.
+ *
+ * Return: true on success, false on failure.
+ */
+bool dc_update_state(struct dc *dc, struct dc_state_update *updates);
+
struct dc_underflow_debug_data {
struct dcn_hubbub_reg_state *hubbub_reg_state;
struct dcn_hubp_reg_state *hubp_reg_state[MAX_PIPES];
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 8b164edc9c51..a866688ad9db 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -409,29 +409,27 @@ bool dc_update_planes_and_stream(struct dc *dc,
struct dc_stream_update *stream_update);
struct dc_update_scratch_space;
+struct dc_state_update;
size_t dc_update_scratch_space_size(void);
-struct dc_update_scratch_space *dc_update_planes_and_stream_init(
+struct dc_update_scratch_space *dc_update_state_init(
struct dc *dc,
- struct dc_surface_update *surface_updates,
- int surface_count,
- struct dc_stream_state *dc_stream,
- struct dc_stream_update *stream_update
+ const struct dc_state_update *updates
);
// Locked, false is failed
-bool dc_update_planes_and_stream_prepare(
+bool dc_update_state_prepare(
struct dc_update_scratch_space *scratch
);
// Unlocked
-void dc_update_planes_and_stream_execute(
+void dc_update_state_execute(
const struct dc_update_scratch_space *scratch
);
// Locked, true if call again
-bool dc_update_planes_and_stream_cleanup(
+bool dc_update_state_cleanup(
struct dc_update_scratch_space *scratch
);
@@ -518,7 +516,12 @@ void dc_enable_stereo(
/* Triggers multi-stream synchronization. */
void dc_trigger_sync(struct dc *dc, struct dc_state *context);
-struct surface_update_descriptor dc_check_update_surfaces_for_stream(
+struct dc_update_descriptor dc_check_state_update(
+ const struct dc_check_config *check_config,
+ struct dc_state_update *updates);
+
+/* Shim: packs args into dc_state_update and calls dc_check_state_update(). */
+struct dc_update_descriptor dc_check_update_surfaces_for_stream(
const struct dc_check_config *check_config,
struct dc_surface_update *updates,
int surface_count,
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 53/70] drm/amd/display: Refactor dc_validation_set array into single root struct
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (51 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 52/70] drm/amd/display: Introduce dc_update_state unified commit interface Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 54/70] drm/amd/display: Introduce dc_state_get_status unified status accessor Wayne Lin
` (16 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
dc_validate_with_context() took a C array of per-stream elements plus a
separate count. This flat array cannot be extended to carry global objects
without widening the signature further.
[How]
Rename the per-stream element to dc_validation_stream, and make
dc_validation_set a root struct holding streams[MAX_STREAMS] and
stream_count. Update dc_validate_with_context() to take a single
const dc_validation_set * and propagate the new shape through all DC-layer
callers and helpers. Remove the never-implemented
dce112_validate_with_context declaration and the orphaned dce100
forward-declare.
No behavior change.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 11 ++--
.../gpu/drm/amd/display/dc/core/dc_resource.c | 60 +++++++++----------
drivers/gpu/drm/amd/display/dc/dc.h | 22 +++++--
drivers/gpu/drm/amd/display/dc/inc/resource.h | 3 +-
.../dc/resource/dce100/dce100_resource.h | 1 -
.../dc/resource/dce112/dce112_resource.h | 7 ---
6 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index f1805b03f0db..3fa577a02df1 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -2479,7 +2479,7 @@ enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params
unsigned int i, j;
struct dc_state *context;
enum dc_status res = DC_OK;
- struct dc_validation_set set[MAX_STREAMS] = {0};
+ struct dc_validation_set set = {0};
struct pipe_ctx *pipe;
bool handle_exit_odm2to1 = false;
@@ -2512,14 +2512,15 @@ enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params
dc_stream_log(dc, stream);
- set[i].stream = stream;
+ set.streams[i].stream = stream;
if (status) {
- set[i].plane_count = (uint8_t)status->plane_count;
+ set.streams[i].plane_count = (uint8_t)status->plane_count;
for (j = 0; j < (unsigned int)status->plane_count; j++)
- set[i].plane_states[j] = status->plane_states[j];
+ set.streams[i].plane_states[j] = status->plane_states[j];
}
}
+ set.stream_count = (uint8_t)params->stream_count;
/* ODM Combine 2:1 power optimization is only applied for single stream
* scenario, it uses extra pipes than needed to reduce power consumption
@@ -2543,7 +2544,7 @@ enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params
context->power_source = params->power_source;
- res = dc_validate_with_context(dc, set, params->stream_count, context, DC_VALIDATE_MODE_AND_PROGRAMMING);
+ res = dc_validate_with_context(dc, &set, context, DC_VALIDATE_MODE_AND_PROGRAMMING);
/*
* Only update link encoder to stream assignment after bandwidth validation passed.
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index b21d41df0fab..d9492a460c2a 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4325,8 +4325,7 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
static bool planes_changed_for_existing_stream(struct dc_state *context,
struct dc_stream_state *stream,
- const struct dc_validation_set set[],
- unsigned int set_count)
+ const struct dc_validation_set *set)
{
unsigned int i, j;
struct dc_stream_status *stream_status = NULL;
@@ -4343,18 +4342,18 @@ static bool planes_changed_for_existing_stream(struct dc_state *context,
return false;
}
- for (i = 0; i < set_count; i++)
- if (set[i].stream == stream)
+ for (i = 0; i < set->stream_count; i++)
+ if (set->streams[i].stream == stream)
break;
- if (i == set_count)
+ if (i == set->stream_count)
ASSERT(0);
- if (set[i].plane_count != stream_status->plane_count)
+ if (set->streams[i].plane_count != stream_status->plane_count)
return true;
- for (j = 0; j < set[i].plane_count; j++)
- if (set[i].plane_states[j] != stream_status->plane_states[j])
+ for (j = 0; j < set->streams[i].plane_count; j++)
+ if (set->streams[i].plane_states[j] != stream_status->plane_states[j])
return true;
return false;
@@ -4363,23 +4362,22 @@ static bool planes_changed_for_existing_stream(struct dc_state *context,
static bool add_all_planes_for_stream(
const struct dc *dc,
struct dc_stream_state *stream,
- const struct dc_validation_set set[],
- unsigned int set_count,
+ const struct dc_validation_set *set,
struct dc_state *state)
{
unsigned int i, j;
- for (i = 0; i < set_count; i++)
- if (set[i].stream == stream)
+ for (i = 0; i < set->stream_count; i++)
+ if (set->streams[i].stream == stream)
break;
- if (i == set_count) {
+ if (i == set->stream_count) {
dm_error("Stream %p not found in set!\n", stream);
return false;
}
- for (j = 0; j < set[i].plane_count; j++)
- if (!dc_state_add_plane(dc, stream, set[i].plane_states[j], state))
+ for (j = 0; j < set->streams[i].plane_count; j++)
+ if (!dc_state_add_plane(dc, stream, set->streams[i].plane_states[j], state))
return false;
return true;
@@ -4389,8 +4387,7 @@ static bool add_all_planes_for_stream(
* dc_validate_with_context - Validate and update the potential new stream in the context object
*
* @dc: Used to get the current state status
- * @set: An array of dc_validation_set with all the current streams reference
- * @set_count: Total of streams
+ * @set: Root validation object holding all streams and their planes
* @context: New context
* @validate_mode: identify the validation mode
*
@@ -4404,8 +4401,7 @@ static bool add_all_planes_for_stream(
* In case of success, return DC_OK (1), otherwise, return a DC error.
*/
enum dc_status dc_validate_with_context(struct dc *dc,
- const struct dc_validation_set set[],
- unsigned int set_count,
+ const struct dc_validation_set *set,
struct dc_state *context,
enum dc_validate_mode validate_mode)
{
@@ -4426,8 +4422,8 @@ enum dc_status dc_validate_with_context(struct dc *dc,
for (i = 0; i < old_stream_count; i++) {
struct dc_stream_state *stream = context->streams[i];
- for (j = 0; j < set_count; j++) {
- if (stream == set[j].stream) {
+ for (j = 0; j < set->stream_count; j++) {
+ if (stream == set->streams[j].stream) {
found = true;
break;
}
@@ -4440,8 +4436,8 @@ enum dc_status dc_validate_with_context(struct dc *dc,
}
/* Second, build a list of new streams */
- for (i = 0; i < set_count; i++) {
- struct dc_stream_state *stream = set[i].stream;
+ for (i = 0; i < set->stream_count; i++) {
+ struct dc_stream_state *stream = set->streams[i].stream;
for (j = 0; j < old_stream_count; j++) {
if (stream == context->streams[j]) {
@@ -4459,10 +4455,10 @@ enum dc_status dc_validate_with_context(struct dc *dc,
/* Build a list of unchanged streams which is necessary for handling
* planes change such as added, removed, and updated.
*/
- for (i = 0; i < set_count; i++) {
+ for (i = 0; i < set->stream_count; i++) {
/* Check if stream is part of the delete list */
for (j = 0; j < del_streams_count; j++) {
- if (set[i].stream == del_streams[j]) {
+ if (set->streams[i].stream == del_streams[j]) {
found = true;
break;
}
@@ -4471,7 +4467,7 @@ enum dc_status dc_validate_with_context(struct dc *dc,
if (!found) {
/* Check if stream is part of the add list */
for (j = 0; j < add_streams_count; j++) {
- if (set[i].stream == add_streams[j]) {
+ if (set->streams[i].stream == add_streams[j]) {
found = true;
break;
}
@@ -4479,7 +4475,7 @@ enum dc_status dc_validate_with_context(struct dc *dc,
}
if (!found)
- unchanged_streams[unchanged_streams_count++] = set[i].stream;
+ unchanged_streams[unchanged_streams_count++] = set->streams[i].stream;
found = false;
}
@@ -4488,8 +4484,7 @@ enum dc_status dc_validate_with_context(struct dc *dc,
for (i = 0; i < unchanged_streams_count; i++) {
if (planes_changed_for_existing_stream(context,
unchanged_streams[i],
- set,
- set_count)) {
+ set)) {
if (!dc_state_rem_all_planes_for_stream(dc,
unchanged_streams[i],
@@ -4557,7 +4552,7 @@ enum dc_status dc_validate_with_context(struct dc *dc,
if (res != DC_OK)
goto fail;
- if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) {
+ if (!add_all_planes_for_stream(dc, add_streams[i], set, context)) {
res = DC_FAIL_ATTACH_SURFACES;
goto fail;
}
@@ -4567,9 +4562,8 @@ enum dc_status dc_validate_with_context(struct dc *dc,
for (i = 0; i < unchanged_streams_count; i++) {
if (planes_changed_for_existing_stream(context,
unchanged_streams[i],
- set,
- set_count)) {
- if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) {
+ set)) {
+ if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, context)) {
res = DC_FAIL_ATTACH_SURFACES;
goto fail;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index f06539df7f0a..bc2ed23407cc 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2182,9 +2182,9 @@ void dc_post_update_surfaces_to_stream(
void dc_get_default_tiling_info(const struct dc *dc, struct dc_tiling_info *tiling_info);
/**
- * struct dc_validation_set - Struct to store surface/stream associations for validation
+ * struct dc_validation_stream - Per-stream surface/stream association for validation
*/
-struct dc_validation_set {
+struct dc_validation_stream {
/**
* @stream: Stream state properties
*/
@@ -2201,6 +2201,21 @@ struct dc_validation_set {
uint8_t plane_count;
};
+/**
+ * struct dc_validation_set - Root validation input grouping all streams for a commit
+ */
+struct dc_validation_set {
+ /**
+ * @streams: Per-stream entries (stream + its planes)
+ */
+ struct dc_validation_stream streams[MAX_STREAMS];
+
+ /**
+ * @stream_count: Number of active entries in @streams
+ */
+ uint8_t stream_count;
+};
+
bool dc_validate_boot_timing(const struct dc *dc,
const struct dc_sink *sink,
struct dc_crtc_timing *crtc_timing);
@@ -2208,8 +2223,7 @@ bool dc_validate_boot_timing(const struct dc *dc,
enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state);
enum dc_status dc_validate_with_context(struct dc *dc,
- const struct dc_validation_set set[],
- unsigned int set_count,
+ const struct dc_validation_set *set,
struct dc_state *context,
enum dc_validate_mode validate_mode);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 945cdcefb7d4..b64ba8c0adb1 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -577,8 +577,7 @@ struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
const struct pipe_ctx *primary_pipe);
bool resource_validate_attach_surfaces(
- const struct dc_validation_set set[],
- int set_count,
+ const struct dc_validation_set *set,
const struct dc_state *old_context,
struct dc_state *context,
const struct resource_pool *pool);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h
index dd150a4b4610..bc130793348a 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h
@@ -33,7 +33,6 @@
struct dc;
struct resource_pool;
-struct dc_validation_set;
struct resource_pool *dce100_create_resource_pool(
uint8_t num_virtual_links,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h
index 3efc4c55d2d2..f2493945b8f4 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h
@@ -35,13 +35,6 @@ struct resource_pool *dce112_create_resource_pool(
uint8_t num_virtual_links,
struct dc *dc);
-enum dc_status dce112_validate_with_context(
- struct dc *dc,
- const struct dc_validation_set set[],
- int set_count,
- struct dc_state *context,
- struct dc_state *old_context);
-
enum dc_status dce112_validate_bandwidth(
struct dc *dc,
struct dc_state *context,
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 54/70] drm/amd/display: Introduce dc_state_get_status unified status accessor
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (52 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 53/70] drm/amd/display: Refactor dc_validation_set array into single root struct Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 55/70] drm/amd/display: Introduce program_perfmon hwss hook and BLS perfmon sequence Wayne Lin
` (15 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
dc_state_get_stream_status() is typed against streams only, leaving no
extensible slot for future status classes. The public status accessor
signature needs to stay stable as new status classes are added.
[How]
Add a dc_get_status_type bitmask and the dc_get_status_options /
dc_state_status structs. Implement dc_state_get_status() to populate the
output object per the options bitmask, and make dc_state_get_stream_status()
a shim over it.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/dc/core/dc_state.c | 57 ++++++++++++++-----
drivers/gpu/drm/amd/display/dc/dc.h | 44 ++++++++++++++
drivers/gpu/drm/amd/display/dc/dc_state.h | 7 +++
3 files changed, 94 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index a5df0101b504..03cb40e94d58 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -25,6 +25,7 @@
#include "dc_types.h"
#include "core_types.h"
#include "core_status.h"
+#include "dc.h"
#include "dc_state.h"
#include "dc_state_priv.h"
#include "dc_stream_priv.h"
@@ -682,28 +683,56 @@ bool dc_state_add_all_planes_for_stream(
/* Private dc_state functions */
/**
- * dc_state_get_stream_status - Get stream status from given dc state
- * @state: DC state to find the stream status in
- * @stream: The stream to get the stream status for
+ * dc_state_get_status - Unified status readback for dc_state.
+ * @status: output object populated per options->types
+ * @options: selects source state, status classes to fill, and optional filters
*
- * The given stream is expected to exist in the given dc state. Otherwise, NULL
- * will be returned.
+ * Return: DC_OK on success, DC_ERROR_UNEXPECTED if options or state is NULL.
*/
-struct dc_stream_status *dc_state_get_stream_status(
- struct dc_state *state,
- const struct dc_stream_state *stream)
+enum dc_status dc_state_get_status(struct dc_state_status *status,
+ const struct dc_get_status_options *options)
{
uint8_t i;
- if (state == NULL)
- return NULL;
+ if (!status || !options || !options->state)
+ return DC_ERROR_UNEXPECTED;
- for (i = 0; i < state->stream_count; i++) {
- if (stream == state->streams[i])
- return &state->stream_status[i];
+ if (options->types & DC_GET_STATUS_STREAM) {
+ status->stream_count = 0;
+ for (i = 0; i < options->state->stream_count; i++) {
+ if (options->stream &&
+ options->stream != options->state->streams[i])
+ continue;
+ status->stream_status[status->stream_count++] =
+ &options->state->stream_status[i];
+ }
}
- return NULL;
+ return DC_OK;
+}
+
+/**
+ * dc_state_get_stream_status - Shim for dc_state_get_status.
+ * @state: state to search
+ * @stream: stream to find status for
+ *
+ * Return: pointer to the matching dc_stream_status, or NULL if not found.
+ */
+struct dc_stream_status *dc_state_get_stream_status(
+ struct dc_state *state,
+ const struct dc_stream_state *stream)
+{
+ struct dc_state_status status = {};
+ struct dc_get_status_options options = {
+ .state = state,
+ .types = DC_GET_STATUS_STREAM,
+ .stream = stream,
+ };
+
+ if (dc_state_get_status(&status, &options) != DC_OK)
+ return NULL;
+
+ return status.stream_count > 0 ? status.stream_status[0] : NULL;
}
enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state,
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index bc2ed23407cc..2da89c7470de 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2127,6 +2127,50 @@ struct dc_state_update {
*/
bool dc_update_state(struct dc *dc, struct dc_state_update *updates);
+/**
+ * enum dc_get_status_type - Bitmask selecting which status classes to populate.
+ * @DC_GET_STATUS_STREAM: populate stream_status fields in dc_state_status
+ */
+enum dc_get_status_type {
+ DC_GET_STATUS_STREAM = (1u << 0),
+};
+
+/**
+ * struct dc_get_status_options - Input selector for dc_state_get_status.
+ * @state: source state to read status from
+ * @types: OR of dc_get_status_type values selecting classes to populate
+ * @stream: optional stream filter for DC_GET_STATUS_STREAM. NULL means
+ * populate status for all streams in the state
+ */
+struct dc_get_status_options {
+ struct dc_state *state;
+ uint32_t types;
+ const struct dc_stream_state *stream;
+};
+
+/**
+ * struct dc_state_status - Output-only status object from dc_state_get_status.
+ * @stream_count: number of valid entries in stream_status (DC_GET_STATUS_STREAM)
+ * @stream_status: pointers to live per-stream status entries
+ */
+struct dc_state_status {
+ int stream_count;
+ struct dc_stream_status *stream_status[MAX_STREAMS];
+};
+
+/**
+ * dc_state_get_status - Unified status readback for dc_state.
+ * @status: output object populated according to options->types
+ * @options: selects the source state, status classes to fill, and filters
+ *
+ * dc_state_get_stream_status() is a thin shim over this function with
+ * types = DC_GET_STATUS_STREAM and a stream filter.
+ *
+ * Return: DC_OK on success, DC_ERROR_UNEXPECTED if state is NULL.
+ */
+enum dc_status dc_state_get_status(struct dc_state_status *status,
+ const struct dc_get_status_options *options);
+
struct dc_underflow_debug_data {
struct dcn_hubbub_reg_state *hubbub_reg_state;
struct dcn_hubp_reg_state *hubp_reg_state[MAX_PIPES];
diff --git a/drivers/gpu/drm/amd/display/dc/dc_state.h b/drivers/gpu/drm/amd/display/dc/dc_state.h
index db1e63a7d460..acf461225e9d 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_state.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_state.h
@@ -74,4 +74,11 @@ bool dc_state_add_all_planes_for_stream(
struct dc_stream_status *dc_state_get_stream_status(
struct dc_state *state,
const struct dc_stream_state *stream);
+
+struct dc_state_status;
+struct dc_get_status_options;
+
+enum dc_status dc_state_get_status(struct dc_state_status *status,
+ const struct dc_get_status_options *options);
+
#endif /* _DC_STATE_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 55/70] drm/amd/display: Introduce program_perfmon hwss hook and BLS perfmon sequence
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (53 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 54/70] drm/amd/display: Introduce dc_state_get_status unified status accessor Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 56/70] drm/amd/display: Wire probe commit path into dc_update_state Wayne Lin
` (14 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
The hubbub perfmon peak-bandwidth path used a monolithic function
combining counter configuration and enable in one call, and wrote results
into a caller-supplied struct outside the dc_state model. A BLS-driven
approach builds the measurement from stateless primitives, gates it to OTG
frame boundaries, and stores results in dc_state.
[How]
- Rename the peak-BW vtable members from "unbounded_bandwidth" to
"out_of_order_bandwidth" and split them into arm and start operations.
- Add the full set of perfmon BLS primitives - param structs, union
members, enum entries, executors, and hwss_add_* builders - for reset,
arm, every start_measuring_* and every get_* operation.
- Add dc_probe_status (valid, type, result union) plus probe_status[] to
dc_state.
- Replace the measure_memory_qos hook with program_perfmon(dc, context),
which writes results into probe_status[].
- dc_get_qos_info no longer calls the removed hook.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 17 +-
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 337 ++++++++++++++++++
.../gpu/drm/amd/display/dc/core/dc_state.c | 1 +
.../drm/amd/display/dc/hwss/hw_sequencer.h | 191 +++++++++-
.../gpu/drm/amd/display/dc/inc/core_types.h | 27 ++
.../gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 12 +-
6 files changed, 562 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 3fa577a02df1..a3665c49a381 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -8125,24 +8125,13 @@ void dc_log_preos_dmcub_info(const struct dc *dc)
bool dc_get_qos_info(struct dc *dc, struct dc_qos_info *info)
{
const struct dc_clocks *clk = &dc->current_state->bw_ctx.bw.dcn.clk;
- struct dc_measured_memory_qos measured = {};
struct dc_requested_memory_qos requested = {};
memset(info, 0, sizeof(*info));
- // Check if measurement function is available
- if (!dc->hwss.measure_memory_qos) {
- return false;
- }
-
- dc->hwss.measure_memory_qos(dc, &measured);
-
- info->actual_peak_bw_in_mbps = measured.peak_bw_mbps;
- info->actual_avg_bw_in_mbps = measured.avg_bw_mbps;
- info->actual_min_latency_in_ns = measured.min_latency_ns;
- info->actual_max_latency_in_ns = measured.max_latency_ns;
- info->actual_avg_latency_in_ns = measured.avg_latency_ns;
- info->dcn_bandwidth_ub_in_mbps = (uint32_t)(clk->fclk_khz / 1000 * 64);
+ /* TODO: remove the actual_* fields from struct dc_qos_info once all callers
+ * read measured QoS from dc_state probe_status instead of this struct. */
+ info->dcn_bandwidth_ub_in_mbps = (uint32_t)(clk->fclk_khz / 1000 * 64);
if (dc->clk_mgr && dc->clk_mgr->funcs->get_requested_memory_qos) {
dc->clk_mgr->funcs->get_requested_memory_qos(dc->clk_mgr, &requested);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index 6002175420a0..07ec00e11f2d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -1495,6 +1495,48 @@ void hwss_execute_sequence(struct dc *dc,
case HUBBUB_SOFT_RESET:
hwss_hubbub_soft_reset(params);
break;
+ case HUBBUB_PERFMON_RESET:
+ hwss_hubbub_perfmon_reset(params);
+ break;
+ case HUBBUB_PERFMON_ARM_OUT_OF_ORDER_BW:
+ hwss_hubbub_perfmon_arm_out_of_order_bw(params);
+ break;
+ case HUBBUB_PERFMON_START_OUT_OF_ORDER_BW:
+ hwss_hubbub_perfmon_start_out_of_order_bw(params);
+ break;
+ case HUBBUB_PERFMON_START_IN_ORDER_BW:
+ hwss_hubbub_perfmon_start_in_order_bw(params);
+ break;
+ case HUBBUB_PERFMON_START_MEMORY_LATENCIES:
+ hwss_hubbub_perfmon_start_memory_latencies(params);
+ break;
+ case HUBBUB_PERFMON_START_URGENT_ASSERTION_COUNT:
+ hwss_hubbub_perfmon_start_urgent_assertion_count(params);
+ break;
+ case HUBBUB_PERFMON_START_URGENT_RAMP_LATENCY:
+ hwss_hubbub_perfmon_start_urgent_ramp_latency(params);
+ break;
+ case HUBBUB_PERFMON_START_PREFETCH_DATA_SIZE:
+ hwss_hubbub_perfmon_start_prefetch_data_size(params);
+ break;
+ case HUBBUB_PERFMON_GET_OUT_OF_ORDER_BW:
+ hwss_hubbub_perfmon_get_out_of_order_bw(params);
+ break;
+ case HUBBUB_PERFMON_GET_IN_ORDER_BW:
+ hwss_hubbub_perfmon_get_in_order_bw(params);
+ break;
+ case HUBBUB_PERFMON_GET_MEMORY_LATENCIES:
+ hwss_hubbub_perfmon_get_memory_latencies(params);
+ break;
+ case HUBBUB_PERFMON_GET_URGENT_ASSERTION_COUNT:
+ hwss_hubbub_perfmon_get_urgent_assertion_count(params);
+ break;
+ case HUBBUB_PERFMON_GET_PREFETCH_DATA_SIZE:
+ hwss_hubbub_perfmon_get_prefetch_data_size(params);
+ break;
+ case HUBBUB_PERFMON_GET_URGENT_RAMP_LATENCY:
+ hwss_hubbub_perfmon_get_urgent_ramp_latency(params);
+ break;
case HUBP_CLK_CNTL:
hwss_hubp_clk_cntl(params);
break;
@@ -3251,6 +3293,139 @@ void hwss_hubbub_soft_reset(union block_sequence_params *params)
params->hubbub_soft_reset_params.hubbub_soft_reset(hubbub, reset);
}
+void hwss_hubbub_perfmon_reset(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_reset_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.reset)
+ hubbub->funcs->perfmon.reset(hubbub);
+}
+
+void hwss_hubbub_perfmon_arm_out_of_order_bw(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_arm_out_of_order_bw_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.arm_measuring_out_of_order_bandwidth)
+ hubbub->funcs->perfmon.arm_measuring_out_of_order_bandwidth(hubbub);
+}
+
+void hwss_hubbub_perfmon_start_out_of_order_bw(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_start_out_of_order_bw_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.start_measuring_out_of_order_bandwidth)
+ hubbub->funcs->perfmon.start_measuring_out_of_order_bandwidth(hubbub);
+}
+
+void hwss_hubbub_perfmon_start_in_order_bw(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_start_in_order_bw_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.start_measuring_in_order_bandwidth)
+ hubbub->funcs->perfmon.start_measuring_in_order_bandwidth(hubbub);
+}
+
+void hwss_hubbub_perfmon_start_memory_latencies(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_start_memory_latencies_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.start_measuring_memory_latencies)
+ hubbub->funcs->perfmon.start_measuring_memory_latencies(hubbub);
+}
+
+void hwss_hubbub_perfmon_start_urgent_assertion_count(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_start_urgent_assertion_count_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.start_measuring_urgent_assertion_count)
+ hubbub->funcs->perfmon.start_measuring_urgent_assertion_count(hubbub);
+}
+
+void hwss_hubbub_perfmon_start_urgent_ramp_latency(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_start_urgent_ramp_latency_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.start_measuring_urgent_ramp_latency)
+ hubbub->funcs->perfmon.start_measuring_urgent_ramp_latency(
+ hubbub,
+ ¶ms->hubbub_perfmon_start_urgent_ramp_latency_params.latency_params);
+}
+
+void hwss_hubbub_perfmon_start_prefetch_data_size(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_start_prefetch_data_size_params.hubbub;
+
+ if (hubbub && hubbub->funcs->perfmon.start_measuring_prefetch_data_size)
+ hubbub->funcs->perfmon.start_measuring_prefetch_data_size(hubbub);
+}
+
+void hwss_hubbub_perfmon_get_out_of_order_bw(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_get_out_of_order_bw_params.hubbub;
+ uint32_t refclk_mhz = params->hubbub_perfmon_get_out_of_order_bw_params.refclk_mhz;
+ uint32_t *mbps = params->hubbub_perfmon_get_out_of_order_bw_params.bandwidth_mbps;
+ uint32_t *duration = params->hubbub_perfmon_get_out_of_order_bw_params.duration_ns;
+
+ if (hubbub && hubbub->funcs->perfmon.get_out_of_order_bandwidth_mbps && mbps)
+ *mbps = hubbub->funcs->perfmon.get_out_of_order_bandwidth_mbps(
+ hubbub, refclk_mhz, duration);
+}
+
+void hwss_hubbub_perfmon_get_in_order_bw(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_get_in_order_bw_params.hubbub;
+ uint32_t refclk_mhz = params->hubbub_perfmon_get_in_order_bw_params.refclk_mhz;
+ uint32_t min_duration_ns = params->hubbub_perfmon_get_in_order_bw_params.min_duration_ns;
+ uint32_t *mbps = params->hubbub_perfmon_get_in_order_bw_params.bandwidth_mbps;
+ uint32_t *duration = params->hubbub_perfmon_get_in_order_bw_params.duration_ns;
+
+ if (hubbub && hubbub->funcs->perfmon.get_in_order_bandwidth_mbps && mbps)
+ *mbps = hubbub->funcs->perfmon.get_in_order_bandwidth_mbps(
+ hubbub, refclk_mhz, min_duration_ns, duration);
+}
+
+void hwss_hubbub_perfmon_get_memory_latencies(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_get_memory_latencies_params.hubbub;
+ uint32_t refclk_mhz = params->hubbub_perfmon_get_memory_latencies_params.refclk_mhz;
+ struct hubbub_system_latencies *result = params->hubbub_perfmon_get_memory_latencies_params.result;
+
+ if (hubbub && hubbub->funcs->perfmon.get_memory_latencies_ns && result)
+ hubbub->funcs->perfmon.get_memory_latencies_ns(
+ hubbub, refclk_mhz, &result->min_latency_ns, &result->max_latency_ns, &result->avg_latency_ns);
+}
+
+void hwss_hubbub_perfmon_get_urgent_assertion_count(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_get_urgent_assertion_count_params.hubbub;
+ uint32_t refclk_mhz = params->hubbub_perfmon_get_urgent_assertion_count_params.refclk_mhz;
+ uint32_t *count = params->hubbub_perfmon_get_urgent_assertion_count_params.assertion_count;
+
+ if (hubbub && hubbub->funcs->perfmon.get_urgent_assertion_count)
+ hubbub->funcs->perfmon.get_urgent_assertion_count(
+ hubbub, refclk_mhz, count, NULL, NULL);
+}
+
+void hwss_hubbub_perfmon_get_prefetch_data_size(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_get_prefetch_data_size_params.hubbub;
+ uint32_t *prefetch_size = params->hubbub_perfmon_get_prefetch_data_size_params.prefetch_data_size;
+
+ if (hubbub && hubbub->funcs->perfmon.get_prefetch_data_size && prefetch_size)
+ *prefetch_size = hubbub->funcs->perfmon.get_prefetch_data_size(hubbub);
+}
+
+void hwss_hubbub_perfmon_get_urgent_ramp_latency(union block_sequence_params *params)
+{
+ struct hubbub *hubbub = params->hubbub_perfmon_get_urgent_ramp_latency_params.hubbub;
+ uint32_t refclk_mhz = params->hubbub_perfmon_get_urgent_ramp_latency_params.refclk_mhz;
+ uint32_t *latency_ns = params->hubbub_perfmon_get_urgent_ramp_latency_params.latency_ns;
+
+ if (hubbub && hubbub->funcs->perfmon.get_urgent_ramp_latency_ns && latency_ns)
+ *latency_ns = hubbub->funcs->perfmon.get_urgent_ramp_latency_ns(
+ hubbub, refclk_mhz);
+}
+
void hwss_hubp_clk_cntl(union block_sequence_params *params)
{
struct hubp *hubp = params->hubp_clk_cntl_params.hubp;
@@ -4422,6 +4597,168 @@ void hwss_add_hubbub_soft_reset(struct block_sequence_state *seq_state,
}
}
+void hwss_add_hubbub_perfmon_reset(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_RESET;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_reset_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_arm_out_of_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_ARM_OUT_OF_ORDER_BW;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_arm_out_of_order_bw_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_start_out_of_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_START_OUT_OF_ORDER_BW;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_out_of_order_bw_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_start_in_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_START_IN_ORDER_BW;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_in_order_bw_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_start_memory_latencies(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_START_MEMORY_LATENCIES;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_memory_latencies_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_start_urgent_assertion_count(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_START_URGENT_ASSERTION_COUNT;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_urgent_assertion_count_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_start_urgent_ramp_latency(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub,
+ const struct hubbub_urgent_latency_params *latency_params)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_START_URGENT_RAMP_LATENCY;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_urgent_ramp_latency_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_urgent_ramp_latency_params.latency_params =
+ *latency_params;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_start_prefetch_data_size(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_START_PREFETCH_DATA_SIZE;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_start_prefetch_data_size_params.hubbub = hubbub;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_get_out_of_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ uint32_t *bandwidth_mbps, uint32_t *duration_ns)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_OUT_OF_ORDER_BW;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_out_of_order_bw_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_out_of_order_bw_params.refclk_mhz = refclk_mhz;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_out_of_order_bw_params.bandwidth_mbps = bandwidth_mbps;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_out_of_order_bw_params.duration_ns = duration_ns;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_get_in_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz, uint32_t min_duration_ns,
+ uint32_t *bandwidth_mbps, uint32_t *duration_ns)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_IN_ORDER_BW;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_in_order_bw_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_in_order_bw_params.refclk_mhz = refclk_mhz;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_in_order_bw_params.min_duration_ns = min_duration_ns;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_in_order_bw_params.bandwidth_mbps = bandwidth_mbps;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_in_order_bw_params.duration_ns = duration_ns;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_get_memory_latencies(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ struct hubbub_system_latencies *result)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_MEMORY_LATENCIES;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_memory_latencies_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_memory_latencies_params.refclk_mhz = refclk_mhz;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_memory_latencies_params.result = result;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_get_urgent_assertion_count(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ uint32_t *assertion_count)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_URGENT_ASSERTION_COUNT;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_urgent_assertion_count_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_urgent_assertion_count_params.refclk_mhz = refclk_mhz;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_urgent_assertion_count_params.assertion_count = assertion_count;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_get_prefetch_data_size(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t *prefetch_data_size)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_PREFETCH_DATA_SIZE;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_prefetch_data_size_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_prefetch_data_size_params.prefetch_data_size = prefetch_data_size;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_hubbub_perfmon_get_urgent_ramp_latency(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ uint32_t *latency_ns)
+{
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_URGENT_RAMP_LATENCY;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_urgent_ramp_latency_params.hubbub = hubbub;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_urgent_ramp_latency_params.refclk_mhz = refclk_mhz;
+ seq_state->steps[*seq_state->num_steps].params.hubbub_perfmon_get_urgent_ramp_latency_params.latency_ns = latency_ns;
+ (*seq_state->num_steps)++;
+ }
+}
+
void hwss_add_hubp_clk_cntl(struct block_sequence_state *seq_state,
struct hubp *hubp,
bool enable)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index 03cb40e94d58..a62a435054c6 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -362,6 +362,7 @@ void dc_state_destruct(struct dc_state *state)
state->phantom_plane_count = 0;
memset(state->probes, 0, sizeof(state->probes));
+ memset(state->probe_status, 0, sizeof(state->probe_status));
state->probe_count = 0;
state->stream_mask = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index e8bf96a7d63a..6754da1e6ee2 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -32,6 +32,7 @@
#include "inc/hw/link_encoder.h"
#include "inc/core_status.h"
#include "inc/hw/hw_shared.h"
+#include "inc/hw/dchubbub.h"
#include "dsc/dsc.h"
#include "link_service_types.h"
@@ -53,7 +54,6 @@ struct drr_params;
struct dc_underflow_debug_data;
struct dsc_optc_config;
struct vm_system_aperture_param;
-struct dc_measured_memory_qos;
struct stream_encoder;
struct hpo_dp_stream_encoder;
struct hpo_frl_stream_encoder;
@@ -580,6 +580,77 @@ struct hubbub_soft_reset_params {
bool reset;
};
+struct hubbub_perfmon_reset_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_arm_out_of_order_bw_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_start_out_of_order_bw_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_start_in_order_bw_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_start_memory_latencies_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_start_urgent_assertion_count_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_start_urgent_ramp_latency_params {
+ struct hubbub *hubbub;
+ struct hubbub_urgent_latency_params latency_params;
+};
+
+struct hubbub_perfmon_start_prefetch_data_size_params {
+ struct hubbub *hubbub;
+};
+
+struct hubbub_perfmon_get_out_of_order_bw_params {
+ struct hubbub *hubbub;
+ uint32_t refclk_mhz;
+ uint32_t *bandwidth_mbps;
+ uint32_t *duration_ns;
+};
+
+struct hubbub_perfmon_get_in_order_bw_params {
+ struct hubbub *hubbub;
+ uint32_t refclk_mhz;
+ uint32_t min_duration_ns;
+ uint32_t *bandwidth_mbps;
+ uint32_t *duration_ns;
+};
+
+struct hubbub_perfmon_get_memory_latencies_params {
+ struct hubbub *hubbub;
+ uint32_t refclk_mhz;
+ struct hubbub_system_latencies *result;
+};
+
+struct hubbub_perfmon_get_urgent_assertion_count_params {
+ struct hubbub *hubbub;
+ uint32_t refclk_mhz;
+ uint32_t *assertion_count;
+};
+
+struct hubbub_perfmon_get_prefetch_data_size_params {
+ struct hubbub *hubbub;
+ uint32_t *prefetch_data_size;
+};
+
+struct hubbub_perfmon_get_urgent_ramp_latency_params {
+ struct hubbub *hubbub;
+ uint32_t refclk_mhz;
+ uint32_t *latency_ns;
+};
+
struct hubp_clk_cntl_params {
struct hubp *hubp;
bool enable;
@@ -1031,6 +1102,20 @@ union block_sequence_params {
struct hubp_set_blank_en_params hubp_set_blank_en_params;
struct hubp_disable_control_params hubp_disable_control_params;
struct hubbub_soft_reset_params hubbub_soft_reset_params;
+ struct hubbub_perfmon_reset_params hubbub_perfmon_reset_params;
+ struct hubbub_perfmon_arm_out_of_order_bw_params hubbub_perfmon_arm_out_of_order_bw_params;
+ struct hubbub_perfmon_start_out_of_order_bw_params hubbub_perfmon_start_out_of_order_bw_params;
+ struct hubbub_perfmon_start_in_order_bw_params hubbub_perfmon_start_in_order_bw_params;
+ struct hubbub_perfmon_start_memory_latencies_params hubbub_perfmon_start_memory_latencies_params;
+ struct hubbub_perfmon_start_urgent_assertion_count_params hubbub_perfmon_start_urgent_assertion_count_params;
+ struct hubbub_perfmon_start_urgent_ramp_latency_params hubbub_perfmon_start_urgent_ramp_latency_params;
+ struct hubbub_perfmon_start_prefetch_data_size_params hubbub_perfmon_start_prefetch_data_size_params;
+ struct hubbub_perfmon_get_out_of_order_bw_params hubbub_perfmon_get_out_of_order_bw_params;
+ struct hubbub_perfmon_get_in_order_bw_params hubbub_perfmon_get_in_order_bw_params;
+ struct hubbub_perfmon_get_memory_latencies_params hubbub_perfmon_get_memory_latencies_params;
+ struct hubbub_perfmon_get_urgent_assertion_count_params hubbub_perfmon_get_urgent_assertion_count_params;
+ struct hubbub_perfmon_get_prefetch_data_size_params hubbub_perfmon_get_prefetch_data_size_params;
+ struct hubbub_perfmon_get_urgent_ramp_latency_params hubbub_perfmon_get_urgent_ramp_latency_params;
struct hubp_clk_cntl_params hubp_clk_cntl_params;
struct hubp_init_params hubp_init_params;
struct hubp_set_vm_system_aperture_settings_params hubp_set_vm_system_aperture_settings_params;
@@ -1258,6 +1343,20 @@ enum block_sequence_func {
HUBBUB_PROGRAM_WATERMARKS,
HUBBUB_PROGRAM_ARBITER,
HUBBUB_PROGRAM_COMPBUF_SEGMENTS,
+ HUBBUB_PERFMON_RESET,
+ HUBBUB_PERFMON_ARM_OUT_OF_ORDER_BW,
+ HUBBUB_PERFMON_START_OUT_OF_ORDER_BW,
+ HUBBUB_PERFMON_START_IN_ORDER_BW,
+ HUBBUB_PERFMON_START_MEMORY_LATENCIES,
+ HUBBUB_PERFMON_START_URGENT_ASSERTION_COUNT,
+ HUBBUB_PERFMON_START_URGENT_RAMP_LATENCY,
+ HUBBUB_PERFMON_START_PREFETCH_DATA_SIZE,
+ HUBBUB_PERFMON_GET_OUT_OF_ORDER_BW,
+ HUBBUB_PERFMON_GET_IN_ORDER_BW,
+ HUBBUB_PERFMON_GET_MEMORY_LATENCIES,
+ HUBBUB_PERFMON_GET_URGENT_ASSERTION_COUNT,
+ HUBBUB_PERFMON_GET_PREFETCH_DATA_SIZE,
+ HUBBUB_PERFMON_GET_URGENT_RAMP_LATENCY,
/* This must be the last value in this enum, add new ones above */
HWSS_BLOCK_SEQUENCE_FUNC_COUNT
};
@@ -1591,14 +1690,16 @@ struct hw_sequencer_funcs {
struct dc_underflow_debug_data *out_data);
/**
- * measure_memory_qos - Measure memory QoS metrics
- * @dc: DC structure
- * @qos: Pointer to dc_measured_memory_qos struct to populate with measured values
+ * program_perfmon - Program/transition perfmon probes for a commit.
+ * @dc: DC structure
+ * @context: target state; probes, probe_count, and probe_status are
+ * read from and written to this object
*
- * Populates the provided dc_measured_memory_qos struct with peak bandwidth, average bandwidth,
- * max latency, min latency, and average latency from hardware performance counters.
+ * Invoked during the execute phase of dc_update_state. The hook resolves
+ * each probe's transition by diffing @context against dc->current_state
+ * and latches MEASURED results into @context->probe_status.
*/
- void (*measure_memory_qos)(struct dc *dc, struct dc_measured_memory_qos *qos);
+ void (*program_perfmon)(struct dc *dc, struct dc_state *context);
};
@@ -1875,6 +1976,34 @@ void hwss_hubp_disable_control(union block_sequence_params *params);
void hwss_hubbub_soft_reset(union block_sequence_params *params);
+void hwss_hubbub_perfmon_reset(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_arm_out_of_order_bw(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_start_out_of_order_bw(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_start_in_order_bw(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_start_memory_latencies(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_start_urgent_assertion_count(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_start_urgent_ramp_latency(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_start_prefetch_data_size(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_get_out_of_order_bw(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_get_in_order_bw(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_get_memory_latencies(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_get_urgent_assertion_count(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_get_prefetch_data_size(union block_sequence_params *params);
+
+void hwss_hubbub_perfmon_get_urgent_ramp_latency(union block_sequence_params *params);
+
void hwss_hubp_clk_cntl(union block_sequence_params *params);
void hwss_hubp_init(union block_sequence_params *params);
@@ -2213,6 +2342,54 @@ void hwss_add_hubbub_soft_reset(struct block_sequence_state *seq_state,
void (*hubbub_soft_reset)(struct hubbub *hubbub, bool reset),
bool reset);
+void hwss_add_hubbub_perfmon_reset(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_arm_out_of_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_start_out_of_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_start_in_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_start_memory_latencies(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_start_urgent_assertion_count(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_start_urgent_ramp_latency(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub,
+ const struct hubbub_urgent_latency_params *latency_params);
+
+void hwss_add_hubbub_perfmon_start_prefetch_data_size(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub);
+
+void hwss_add_hubbub_perfmon_get_out_of_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ uint32_t *bandwidth_mbps, uint32_t *duration_ns);
+
+void hwss_add_hubbub_perfmon_get_in_order_bw(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz, uint32_t min_duration_ns,
+ uint32_t *bandwidth_mbps, uint32_t *duration_ns);
+
+void hwss_add_hubbub_perfmon_get_memory_latencies(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ struct hubbub_system_latencies *result);
+
+void hwss_add_hubbub_perfmon_get_urgent_assertion_count(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ uint32_t *assertion_count);
+
+void hwss_add_hubbub_perfmon_get_prefetch_data_size(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t *prefetch_data_size);
+
+void hwss_add_hubbub_perfmon_get_urgent_ramp_latency(struct block_sequence_state *seq_state,
+ struct hubbub *hubbub, uint32_t refclk_mhz,
+ uint32_t *latency_ns);
+
void hwss_add_hubp_clk_cntl(struct block_sequence_state *seq_state,
struct hubp *hubp,
bool enable);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index c42626101cd7..ac3e9eaa569c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -33,6 +33,7 @@
#include "dc_bios_types.h"
#include "mem_input.h"
#include "hubp.h"
+#include "hw/dchubbub.h"
#include "mpc.h"
#include "dwb.h"
#include "hw/dio.h"
@@ -609,6 +610,27 @@ struct dc_dmub_cmd {
enum dm_dmub_wait_type wait_type;
};
+/**
+ * struct dc_probe_status - DC-internal latched perfmon results for a probe.
+ * @valid: true if a measurement was latched this commit.
+ * @type: type of the probe that produced this result.
+ * @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
+ * @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
+ * stored as struct hubbub_system_latencies.
+ * @u.urgent_assertion_count: number of urgent assertion events (DC_PROBE_URGENT_ASSERTION_COUNT).
+ * @u.prefetch_data_size: total prefetch data in bytes (DC_PROBE_PREFETCH_DATA_SIZE).
+ */
+struct dc_probe_status {
+ bool valid;
+ enum dc_probe_type type;
+ union {
+ uint32_t bandwidth_mbps;
+ struct hubbub_system_latencies latency;
+ uint32_t urgent_assertion_count;
+ uint32_t prefetch_data_size;
+ } u;
+};
+
/**
* struct dc_state - The full description of a state requested by users
*/
@@ -652,6 +674,11 @@ struct dc_state {
*/
struct dc_probe_state probes[MAX_PROBES];
+ /**
+ * @probe_status: Committed absolute set of probe results.
+ */
+ struct dc_probe_status probe_status[MAX_PROBES];
+
/**
* @probe_count: Number of valid entries in @probes.
*/
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
index 4307362749f0..fd742b320128 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -158,6 +158,12 @@ struct hubbub_urgent_latency_params {
uint32_t bw_factor_x1000;
};
+struct hubbub;
+struct dchub_init_data;
+struct dc_dcc_surface_param;
+struct dc_surface_dcc_cap;
+union dcn_watermark_set;
+struct dml2_display_arb_regs;
struct hubbub_funcs {
void (*update_dchub)(
struct hubbub *hubbub,
@@ -274,9 +280,11 @@ struct hubbub_funcs {
const struct hubbub_urgent_latency_params *params);
uint32_t (*get_urgent_ramp_latency_ns)(struct hubbub *hubbub,
uint32_t refclk_mhz);
- void (*start_measuring_unbounded_bandwidth)(
+ void (*arm_measuring_out_of_order_bandwidth)(
struct hubbub *hubbub);
- uint32_t (*get_unbounded_bandwidth_mbps)(struct hubbub *hubbub,
+ void (*start_measuring_out_of_order_bandwidth)(
+ struct hubbub *hubbub);
+ uint32_t (*get_out_of_order_bandwidth_mbps)(struct hubbub *hubbub,
uint32_t refclk_mhz, uint32_t *duration_ns);
void (*start_measuring_in_order_bandwidth)(
struct hubbub *hubbub);
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 56/70] drm/amd/display: Wire probe commit path into dc_update_state
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (54 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 55/70] drm/amd/display: Introduce program_perfmon hwss hook and BLS perfmon sequence Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 57/70] drm/amd/display: Make dc_state_update const in commit path Wayne Lin
` (13 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
The dc_update_state commit interface and the dc_probe object model existed
but were not connected: there was no path to validate, commit, and program
a probe through the update pipeline, nor to read the result back. The
measurement waits on OTG frame edges and must not block fast updates.
[How]
- Move the per-commit scratch off dc_stream_state onto a dc-owned pool;
acquire at init, release on cleanup or prepare failure, serialized by the
DM global lock every commit path already holds.
- dc_update_state drives stream commits, probe-only commits, or both through
one staged init/prepare/execute/cleanup loop with a null-arg guard. prepare
releases the scratch slot on failure; cleanup releases it on success.
- Probe prepare installs the absolute probe set in place; execute calls the
perfmon programming hook in the unlocked window and latches results.
- Add resource_validate_probe_set, a context-free achievability check shared
by dc_validate_global_state (full update) and probe prepare (probe-only).
- dc_state_get_status gains a probe status class with a probe filter and a
by-type mapping; dc_validation_set gains probes/probe_count. Drop the dead
actual_* fields from struct dc_qos_info.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 314 +++++++++++++-----
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 4 +-
.../gpu/drm/amd/display/dc/core/dc_resource.c | 38 +++
.../gpu/drm/amd/display/dc/core/dc_state.c | 11 +
.../gpu/drm/amd/display/dc/core/dc_stream.c | 22 +-
drivers/gpu/drm/amd/display/dc/dc.h | 122 ++++++-
drivers/gpu/drm/amd/display/dc/dc_stream.h | 27 --
.../drm/amd/display/dc/hwss/hw_sequencer.h | 4 +-
.../gpu/drm/amd/display/dc/inc/core_types.h | 56 ++--
.../gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 6 -
drivers/gpu/drm/amd/display/dc/inc/resource.h | 4 +
11 files changed, 428 insertions(+), 180 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index a3665c49a381..2bd579340b64 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -898,6 +898,32 @@ void dc_stream_set_static_screen_params(struct dc *dc,
dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, params);
}
+static void dc_destruct_update_scratch_pool(struct dc *dc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
+ kfree(dc->update_scratch_pool[i]);
+ dc->update_scratch_pool[i] = NULL;
+ dc->update_scratch_in_use[i] = false;
+ }
+}
+
+static bool dc_construct_update_scratch_pool(struct dc *dc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
+ dc->update_scratch_pool[i] = kzalloc(
+ sizeof(struct dc_update_scratch_space), GFP_KERNEL);
+ if (!dc->update_scratch_pool[i])
+ return false;
+ dc->update_scratch_in_use[i] = false;
+ }
+
+ return true;
+}
+
static void dc_destruct(struct dc *dc)
{
// reset link encoder assignment table on destruct
@@ -905,6 +931,8 @@ static void dc_destruct(struct dc *dc)
!dc->config.unify_link_enc_assignment)
link_enc_cfg_init(dc, dc->current_state);
+ dc_destruct_update_scratch_pool(dc);
+
if (dc->current_state) {
dc_state_release(dc->current_state);
dc->current_state = NULL;
@@ -1148,6 +1176,11 @@ static bool dc_construct(struct dc *dc,
goto fail;
}
+ if (!dc_construct_update_scratch_pool(dc)) {
+ dm_error("%s: failed to create update scratch pool\n", __func__);
+ goto fail;
+ }
+
return true;
fail:
@@ -3235,11 +3268,6 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
return overall_type;
}
-/*
- * dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full)
- *
- * See :c:type:`enum dc_update_type <dc_update_type>` for explanation of update types
- */
/**
* dc_check_state_update - Classify a dc_state_update by locking / re-entrancy requirements.
* @check_config: ASIC capabilities and display configuration context
@@ -3247,7 +3275,8 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
*
* Determines whether the update requires a fast, medium, or full lock
* by inspecting the stream, stream_update, and surface_updates carried on
- * the root object. Perfmon classification is reserved for a future slice.
+ * the root object. A probe update elevates the result to at least MED with
+ * the PROBE lock, so a probe-carrying commit takes the probe mutex.
*
* Return: dc_update_descriptor with update_type and lock_descriptor.
*/
@@ -3255,13 +3284,20 @@ struct dc_update_descriptor dc_check_state_update(
const struct dc_check_config *check_config,
struct dc_state_update *updates)
{
+ struct dc_update_descriptor desc = {0};
+
if (updates->stream_update)
stream_update_flags_clear(&updates->stream_update->stream->update_flags);
for (int i = 0; i < updates->surface_count; i++)
dc_pipe_update_bits_clear(&updates->surface_updates[i].surface->update_bits);
- return check_update_surfaces_for_stream(check_config, updates->surface_updates,
+ desc = check_update_surfaces_for_stream(check_config, updates->surface_updates,
updates->surface_count, updates->stream_update);
+
+ if (updates->probe_updates && updates->probe_updates->probe_count > 0)
+ elevate_update_type(&desc, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_PROBE);
+
+ return desc;
}
/**
@@ -3283,9 +3319,11 @@ struct dc_update_descriptor dc_check_update_surfaces_for_stream(
struct dc_stream_update *stream_update)
{
struct dc_state_update root = {
+ .stream = stream_update ? stream_update->stream : NULL,
+ .stream_update = stream_update,
.surface_updates = updates,
.surface_count = surface_count,
- .stream_update = stream_update,
+ .probe_updates = NULL
};
return dc_check_state_update(check_config, &root);
@@ -3704,13 +3742,6 @@ static bool full_update_required_weak(
const struct dc_stream_update *stream_update,
const struct dc_stream_state *stream);
-struct pipe_split_policy_backup {
- bool dynamic_odm_policy;
- bool subvp_policy;
- enum pipe_split_policy mpc_policy;
- char force_odm[MAX_PIPES];
-};
-
static void backup_and_set_minimal_pipe_split_policy(struct dc *dc,
struct dc_state *context,
struct pipe_split_policy_backup *policy)
@@ -6197,30 +6228,60 @@ static void clear_update_bits(struct dc_surface_update *srf_updates,
dc_pipe_update_bits_clear(&srf_updates[i].surface->update_bits);
}
+static struct dc_update_scratch_space *dc_update_scratch_acquire(struct dc *dc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
+ if (dc->update_scratch_in_use[i])
+ continue;
+
+ dc->update_scratch_in_use[i] = true;
+ return dc->update_scratch_pool[i];
+ }
+
+ /* TODO: add recoverable scratch acquisition failure handling. */
+ ASSERT(false);
+ return NULL;
+}
+
+static void dc_update_scratch_release(struct dc *dc,
+ struct dc_update_scratch_space *scratch)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) {
+ if (dc->update_scratch_pool[i] == scratch) {
+ dc->update_scratch_in_use[i] = false;
+ return;
+ }
+ }
+}
+
/**
* dc_update_state - Commit an absolute dc_state_update.
* @dc: DC structure
* @updates: root update object carrying stream, plane, and probe updates
- *
- * When stream is non-NULL the stream and its plane updates are committed via
- * the init/prepare/execute/cleanup pipeline. Probe commit is reserved for a
- * future slice. dc_update_planes_and_stream() is now a shim over this function.
- *
* Return: true on success, false on failure.
*/
bool dc_update_state(struct dc *dc, struct dc_state_update *updates)
{
- if (updates->stream != NULL) {
- struct dc_update_scratch_space *scratch = dc_update_state_init(dc, updates);
- bool more = true;
+ struct dc_update_scratch_space *scratch;
+ bool more = true;
- while (more) {
- if (!dc_update_state_prepare(scratch))
- return false;
+ if (!dc || !updates)
+ return false;
- dc_update_state_execute(scratch);
- more = dc_update_state_cleanup(scratch);
- }
+ scratch = dc_update_state_init(dc, updates);
+ if (!scratch)
+ return false;
+
+ while (more) {
+ if (!dc_update_state_prepare(scratch))
+ return false;
+
+ dc_update_state_execute(scratch);
+ more = dc_update_state_cleanup(scratch);
}
return true;
@@ -8129,8 +8190,6 @@ bool dc_get_qos_info(struct dc *dc, struct dc_qos_info *info)
memset(info, 0, sizeof(*info));
- /* TODO: remove the actual_* fields from struct dc_qos_info once all callers
- * read measured QoS from dc_state probe_status instead of this struct. */
info->dcn_bandwidth_ub_in_mbps = (uint32_t)(clk->fclk_khz / 1000 * 64);
if (dc->clk_mgr && dc->clk_mgr->funcs->get_requested_memory_qos) {
@@ -8156,38 +8215,6 @@ unsigned int dc_override_memory_bandwidth_request(
dc->clk_mgr, bw_mbps * 1000) / 1000;
}
-enum update_v3_flow {
- UPDATE_V3_FLOW_INVALID,
- UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST,
- UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL,
- UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS,
- UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW,
- UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT,
-};
-
-struct dc_update_scratch_space {
- struct dc *dc;
- struct dc_surface_update *surface_updates;
- int surface_count;
- struct dc_stream_state *stream;
- struct dc_stream_update *stream_update;
- bool update_v3;
- bool do_clear_update_bits;
- enum dc_update_type update_type;
- struct dc_state *new_context;
- enum update_v3_flow flow;
- struct dc_state *backup_context;
- struct dc_state *intermediate_context;
- struct pipe_split_policy_backup intermediate_policy;
- struct dc_surface_update intermediate_updates[MAX_SURFACES];
- int intermediate_count;
-};
-
-size_t dc_update_scratch_space_size(void)
-{
- return sizeof(struct dc_update_scratch_space);
-}
-
static bool update_planes_and_stream_prepare_v2(
struct dc_update_scratch_space *scratch
)
@@ -8354,6 +8381,19 @@ static bool update_planes_and_stream_prepare_v3(
return false;
}
+/**
+ * should_commit_intermediate_context - Does this flow commit a transient
+ * minimal-transition intermediate context
+ * @flow: the commit flow selected for this iteration
+ *
+ * Return: true if this iteration commits the intermediate context.
+ */
+static bool should_commit_intermediate_context(enum update_v3_flow flow)
+{
+ return flow == UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW
+ || flow == UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT;
+}
+
static void update_planes_and_stream_execute_v3_commit(
const struct dc_update_scratch_space *scratch,
bool intermediate_update,
@@ -8377,6 +8417,8 @@ static void update_planes_and_stream_execute_v3(
const struct dc_update_scratch_space *scratch
)
{
+ bool intermediate_context = should_commit_intermediate_context(scratch->flow);
+
switch (scratch->flow) {
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST:
commit_planes_for_stream_fast(
@@ -8392,16 +8434,16 @@ static void update_planes_and_stream_execute_v3(
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL:
case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS:
- update_planes_and_stream_execute_v3_commit(scratch, false, false, true);
+ update_planes_and_stream_execute_v3_commit(scratch, false, intermediate_context, true);
break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW:
- update_planes_and_stream_execute_v3_commit(scratch, false, true,
+ update_planes_and_stream_execute_v3_commit(scratch, false, intermediate_context,
scratch->dc->check_config.deferred_transition_state);
break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT:
- update_planes_and_stream_execute_v3_commit(scratch, true, true, false);
+ update_planes_and_stream_execute_v3_commit(scratch, true, intermediate_context, false);
break;
case UPDATE_V3_FLOW_INVALID:
@@ -8482,45 +8524,139 @@ struct dc_update_scratch_space *dc_update_state_init(
)
{
const enum dce_version version = dc->ctx->dce_version;
- struct dc_update_scratch_space *scratch = updates->stream->update_scratch;
-
- *scratch = (struct dc_update_scratch_space){
- .dc = dc,
- .surface_updates = updates->surface_updates,
- .surface_count = updates->surface_count,
- .stream = updates->stream,
- .stream_update = updates->stream_update,
- .update_v3 = version >= DCN_VERSION_4_01 || version == DCN_VERSION_3_2 || version == DCN_VERSION_3_21,
- .do_clear_update_bits = version >= DCN_VERSION_1_0,
- };
+ struct dc_update_scratch_space *scratch = dc_update_scratch_acquire(dc);
+ bool has_stream_or_plane = updates->stream || updates->stream_update || updates->surface_updates;
+ bool has_probe = updates->probe_updates;
+ bool surface_without_stream = updates->surface_updates && !updates->stream;
+ bool stream_update_without_stream = updates->stream_update && !updates->stream;
+ bool bad_surface_count = updates->surface_count > 0 && !updates->surface_updates;
+
+ if (!scratch)
+ return NULL;
+
+ if (!has_stream_or_plane && !has_probe) {
+ dc_update_scratch_release(dc, scratch);
+ return NULL;
+ }
+
+ if (surface_without_stream || stream_update_without_stream || bad_surface_count) {
+ dc_update_scratch_release(dc, scratch);
+ return NULL;
+ }
+
+ memset(scratch, 0, sizeof(*scratch));
+
+ scratch->dc = dc;
+ scratch->surface_updates = updates->surface_updates;
+ scratch->surface_count = updates->surface_count;
+ scratch->stream = updates->stream;
+ scratch->stream_update = updates->stream_update;
+ scratch->probe_updates = updates->probe_updates;
+ scratch->update_v3 = version >= DCN_VERSION_4_01
+ || version == DCN_VERSION_3_2
+ || version == DCN_VERSION_3_21;
+ scratch->do_clear_update_bits = version >= DCN_VERSION_1_0;
+ scratch->new_context = NULL;
+ scratch->flow = UPDATE_V3_FLOW_INVALID;
return scratch;
}
-bool dc_update_state_prepare(
- struct dc_update_scratch_space *scratch
-)
+/**
+ * dc_update_probes_prepare - Commit the desired probe set into new_context.
+ * @scratch: commit scratch carrying the probe updates
+ *
+ * Return: true on success or when there is nothing to do; false when the
+ * desired set is unachievable.
+ */
+static bool dc_update_probes_prepare(struct dc_update_scratch_space *scratch)
+{
+ struct dc *dc = scratch->dc;
+ const struct dc_probe_updates *probe_updates = scratch->probe_updates;
+ uint8_t i;
+
+ if (!probe_updates)
+ return true;
+
+ if (resource_validate_probe_set(dc, probe_updates->probes,
+ (uint8_t)probe_updates->probe_count) != DC_OK)
+ return false;
+
+ if (!scratch->new_context)
+ scratch->new_context = dc->current_state;
+
+ for (i = 0; i < probe_updates->probe_count && i < MAX_PROBES; i++)
+ scratch->new_context->probes[i] = probe_updates->probes[i];
+ scratch->new_context->probe_count = probe_updates->probe_count;
+
+ return true;
+}
+
+/**
+ * dc_update_probes_execute - Program the committed probes.
+ * @scratch: commit scratch carrying the probe updates
+ *
+ */
+static void dc_update_probes_execute(const struct dc_update_scratch_space *scratch)
+{
+ struct dc *dc = scratch->dc;
+
+ if (should_commit_intermediate_context(scratch->flow))
+ return;
+
+ if (dc->hwss.program_perfmon)
+ dc->hwss.program_perfmon(dc, scratch->new_context);
+}
+
+bool dc_update_state_prepare(struct dc_update_scratch_space *scratch)
{
- return scratch->update_v3
- ? update_planes_and_stream_prepare_v3(scratch)
- : update_planes_and_stream_prepare_v2(scratch);
+ if (scratch->stream) {
+ bool ok = scratch->update_v3
+ ? update_planes_and_stream_prepare_v3(scratch)
+ : update_planes_and_stream_prepare_v2(scratch);
+
+ if (!ok)
+ goto release_scratch;
+ }
+
+ if (!dc_update_probes_prepare(scratch))
+ goto release_scratch;
+
+ return true;
+
+release_scratch:
+ /* execute and cleanup never run on this path, so release here. */
+ dc_update_scratch_release(scratch->dc, scratch);
+ return false;
}
void dc_update_state_execute(
const struct dc_update_scratch_space *scratch
)
{
- scratch->update_v3
- ? update_planes_and_stream_execute_v3(scratch)
- : update_planes_and_stream_execute_v2(scratch);
+ if (scratch->stream)
+ scratch->update_v3
+ ? update_planes_and_stream_execute_v3(scratch)
+ : update_planes_and_stream_execute_v2(scratch);
+
+ if (scratch->probe_updates)
+ dc_update_probes_execute(scratch);
}
bool dc_update_state_cleanup(
struct dc_update_scratch_space *scratch
)
{
- return scratch->update_v3
- ? update_planes_and_stream_cleanup_v3(scratch)
- : update_planes_and_stream_cleanup_v2(scratch);
+ bool more = false;
+
+ if (scratch->stream)
+ more = scratch->update_v3
+ ? update_planes_and_stream_cleanup_v3(scratch)
+ : update_planes_and_stream_cleanup_v2(scratch);
+
+ if (!more)
+ dc_update_scratch_release(scratch->dc, scratch);
+
+ return more;
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index 07ec00e11f2d..8b54bab98283 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -3388,7 +3388,7 @@ void hwss_hubbub_perfmon_get_memory_latencies(union block_sequence_params *param
{
struct hubbub *hubbub = params->hubbub_perfmon_get_memory_latencies_params.hubbub;
uint32_t refclk_mhz = params->hubbub_perfmon_get_memory_latencies_params.refclk_mhz;
- struct hubbub_system_latencies *result = params->hubbub_perfmon_get_memory_latencies_params.result;
+ struct dc_probe_latencies *result = params->hubbub_perfmon_get_memory_latencies_params.result;
if (hubbub && hubbub->funcs->perfmon.get_memory_latencies_ns && result)
hubbub->funcs->perfmon.get_memory_latencies_ns(
@@ -4711,7 +4711,7 @@ void hwss_add_hubbub_perfmon_get_in_order_bw(struct block_sequence_state *seq_st
void hwss_add_hubbub_perfmon_get_memory_latencies(struct block_sequence_state *seq_state,
struct hubbub *hubbub, uint32_t refclk_mhz,
- struct hubbub_system_latencies *result)
+ struct dc_probe_latencies *result)
{
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
seq_state->steps[*seq_state->num_steps].func = HUBBUB_PERFMON_GET_MEMORY_LATENCIES;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index d9492a460c2a..b970f152d67f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4383,6 +4383,40 @@ static bool add_all_planes_for_stream(
return true;
}
+/**
+ * resource_validate_probe_set - Validate a probe descriptor set against the ASIC.
+ * @dc: DC instance providing the HWSS capability hooks
+ * @probes: desired probe descriptors
+ * @probe_count: number of valid entries in @probes
+ *
+ * Return: DC_OK if achievable, otherwise a DC error.
+ */
+enum dc_status resource_validate_probe_set(struct dc *dc,
+ const struct dc_probe_state *probes,
+ uint8_t probe_count)
+{
+ uint8_t i;
+
+ if (probe_count == 0)
+ return DC_OK;
+
+ if (!dc->hwss.program_perfmon)
+ return DC_NOT_SUPPORTED;
+
+ if (probe_count > MAX_PROBES)
+ return DC_NOT_SUPPORTED;
+
+ for (i = 0; i < probe_count; i++) {
+ if (probes[i].target_state == DC_PROBE_MEASURING)
+ return DC_NOT_SUPPORTED;
+
+ if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ return DC_NOT_SUPPORTED;
+ }
+
+ return DC_OK;
+}
+
/**
* dc_validate_with_context - Validate and update the potential new stream in the context object
*
@@ -4754,6 +4788,10 @@ enum dc_status dc_validate_global_state(
if (result == DC_OK)
result = dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, validate_mode);
+ if (result == DC_OK)
+ result = resource_validate_probe_set(dc, new_ctx->probes,
+ (uint8_t)new_ctx->probe_count);
+
return result;
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index a62a435054c6..5c5f38bc04de 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -709,6 +709,17 @@ enum dc_status dc_state_get_status(struct dc_state_status *status,
}
}
+ if (options->types & DC_GET_STATUS_PROBE) {
+ status->probe_count = 0;
+ for (i = 0; i < options->state->probe_count; i++) {
+ if (options->probe &&
+ options->probe->type != options->state->probes[i].type)
+ continue;
+ status->probe_status[status->probe_count++] =
+ &options->state->probe_status[i];
+ }
+ }
+
return DC_OK;
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index a32b6eb796f7..562accfeff79 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -194,7 +194,6 @@ static void dc_stream_free(struct kref *kref)
struct dc_stream_state *stream = container_of(kref, struct dc_stream_state, refcount);
dc_stream_destruct(stream);
- kfree(stream->update_scratch);
kfree(stream);
}
@@ -219,13 +218,6 @@ struct dc_stream_state *dc_create_stream_for_sink(
if (stream == NULL)
goto fail;
- DC_RUN_WITH_PREEMPTION_ENABLED(stream->update_scratch =
- kzalloc((int32_t) dc_update_scratch_space_size(),
- GFP_ATOMIC));
-
- if (stream->update_scratch == NULL)
- goto fail;
-
if (dc_stream_construct(stream, sink) == false)
goto fail;
@@ -234,10 +226,8 @@ struct dc_stream_state *dc_create_stream_for_sink(
return stream;
fail:
- if (stream) {
- kfree(stream->update_scratch);
+ if (stream)
kfree(stream);
- }
return NULL;
}
@@ -250,16 +240,6 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream)
if (!new_stream)
return NULL;
- // Scratch is not meant to be reused across copies, as might have self-referential pointers
- new_stream->update_scratch = kzalloc(
- (int32_t) dc_update_scratch_space_size(),
- GFP_KERNEL
- );
- if (!new_stream->update_scratch) {
- kfree(new_stream);
- return NULL;
- }
-
if (new_stream->sink)
dc_sink_retain(new_stream->sink);
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 2da89c7470de..0913fab7504c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -530,6 +530,7 @@ enum dc_lock_descriptor {
LOCK_DESCRIPTOR_STREAM = 0x1,
LOCK_DESCRIPTOR_LINK = 0x2,
LOCK_DESCRIPTOR_GLOBAL = 0x4,
+ LOCK_DESCRIPTOR_PROBE = 0x8,
};
struct dc_update_descriptor {
@@ -1018,14 +1019,9 @@ struct dc_bounding_box_overrides {
};
struct dc_qos_info {
- uint32_t actual_peak_bw_in_mbps;
uint32_t qos_bandwidth_lb_in_mbps;
- uint32_t actual_avg_bw_in_mbps;
uint32_t calculated_avg_bw_in_mbps;
- uint32_t actual_max_latency_in_ns;
- uint32_t actual_min_latency_in_ns;
uint32_t qos_max_latency_ub_in_ns;
- uint32_t actual_avg_latency_in_ns;
uint32_t qos_avg_latency_ub_in_ns;
uint32_t dcn_bandwidth_ub_in_mbps;
uint32_t qos_max_bw_budget_in_mbps;
@@ -1987,6 +1983,12 @@ struct dc {
struct dc_state *current_state;
struct resource_pool *res_pool;
+ /**
+ * @update_scratch_pool: Per-commit scratch buffers for dc_update_state.
+ */
+ struct dc_update_scratch_space *update_scratch_pool[MAX_STREAMS + 1];
+ bool update_scratch_in_use[MAX_STREAMS + 1];
+
struct clk_mgr *clk_mgr;
/* Display Engine Clock levels */
@@ -2114,25 +2116,107 @@ struct dc_state_update {
const struct dc_probe_updates *probe_updates;
};
+/**
+ * dc_check_state_update() - Classify an update without committing it.
+ * @check_config: DC check configuration
+ * @updates: root update object to classify
+ *
+ * Return: descriptor indicating update type and required lock scope.
+ */
+struct dc_update_descriptor dc_check_state_update(
+ const struct dc_check_config *check_config,
+ struct dc_state_update *updates);
+
/**
* dc_update_state - Commit an absolute dc_state_update.
* @dc: DC structure
* @updates: root update object carrying stream, plane, and probe updates
*
- * When stream is non-NULL the stream and its plane updates are committed via
- * the init/prepare/execute/cleanup pipeline. Probe commit is reserved for a
- * future slice. dc_update_planes_and_stream() is now a shim over this function.
- *
* Return: true on success, false on failure.
*/
bool dc_update_state(struct dc *dc, struct dc_state_update *updates);
+struct dc_update_scratch_space;
+
+/**
+ * dc_update_state_init - Acquire and initialise a commit scratch buffer.
+ * @dc: DC structure
+ * @updates: update descriptor; validated before the slot is acquired
+ *
+ * Return: a scratch slot on success, NULL if validation fails or the pool
+ * is exhausted. The slot must be released via dc_update_state_cleanup() on
+ * success, or automatically by dc_update_state_prepare() on failure.
+ */
+struct dc_update_scratch_space *dc_update_state_init(
+ struct dc *dc,
+ const struct dc_state_update *updates
+);
+
+/**
+ * dc_update_state_prepare - Prepare the commit under the global lock.
+ * @scratch: commit scratch from dc_update_state_init()
+ *
+ * On failure the scratch slot is released and false is returned; the caller
+ * must not call execute or cleanup.
+ */
+bool dc_update_state_prepare(struct dc_update_scratch_space *scratch);
+
+/**
+ * dc_update_state_execute - Program hardware; called without the global lock.
+ * @scratch: commit scratch from dc_update_state_init()
+ */
+void dc_update_state_execute(const struct dc_update_scratch_space *scratch);
+
+/**
+ * dc_update_state_cleanup - Finalise the commit and release the scratch slot.
+ * @scratch: commit scratch from dc_update_state_init()
+ *
+ * Must be called with the global lock held. Returns true if the caller must
+ * loop back to prepare (SEAMLESS continuation).
+ */
+bool dc_update_state_cleanup(struct dc_update_scratch_space *scratch);
+
+/**
+ * struct dc_probe_latencies - min/max/avg memory latency in ns.
+ * @max_latency_ns: maximum latency in nanoseconds
+ * @avg_latency_ns: average latency in nanoseconds
+ * @min_latency_ns: minimum latency in nanoseconds
+ */
+struct dc_probe_latencies {
+ uint32_t max_latency_ns;
+ uint32_t avg_latency_ns;
+ uint32_t min_latency_ns;
+};
+
+/**
+ * struct dc_probe_status - results for a probe.
+ * @valid: true if a measurement was latched.
+ * @type: type of the probe that produced this result.
+ * @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
+ * @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
+ * stored as struct dc_probe_latencies.
+ * @u.urgent_assertion_count: number of urgent assertion events (DC_PROBE_URGENT_ASSERTION_COUNT).
+ * @u.prefetch_data_size: total prefetch data in bytes (DC_PROBE_PREFETCH_DATA_SIZE).
+ */
+struct dc_probe_status {
+ bool valid;
+ enum dc_probe_type type;
+ union {
+ uint32_t bandwidth_mbps;
+ struct dc_probe_latencies latency;
+ uint32_t urgent_assertion_count;
+ uint32_t prefetch_data_size;
+ } u;
+};
+
/**
* enum dc_get_status_type - Bitmask selecting which status classes to populate.
* @DC_GET_STATUS_STREAM: populate stream_status fields in dc_state_status
+ * @DC_GET_STATUS_PROBE: populate probe_status fields in dc_state_status
*/
enum dc_get_status_type {
DC_GET_STATUS_STREAM = (1u << 0),
+ DC_GET_STATUS_PROBE = (1u << 1),
};
/**
@@ -2141,21 +2225,28 @@ enum dc_get_status_type {
* @types: OR of dc_get_status_type values selecting classes to populate
* @stream: optional stream filter for DC_GET_STATUS_STREAM. NULL means
* populate status for all streams in the state
+ * @probe: optional probe filter for DC_GET_STATUS_PROBE. NULL means
+ * populate status for all probes in the state
*/
struct dc_get_status_options {
struct dc_state *state;
uint32_t types;
const struct dc_stream_state *stream;
+ const struct dc_probe_state *probe;
};
/**
* struct dc_state_status - Output-only status object from dc_state_get_status.
* @stream_count: number of valid entries in stream_status (DC_GET_STATUS_STREAM)
* @stream_status: pointers to live per-stream status entries
+ * @probe_count: number of valid entries in probe_status (DC_GET_STATUS_PROBE)
+ * @probe_status: pointers to live per-probe status entries
*/
struct dc_state_status {
int stream_count;
struct dc_stream_status *stream_status[MAX_STREAMS];
+ int probe_count;
+ struct dc_probe_status *probe_status[MAX_PROBES];
};
/**
@@ -2163,9 +2254,6 @@ struct dc_state_status {
* @status: output object populated according to options->types
* @options: selects the source state, status classes to fill, and filters
*
- * dc_state_get_stream_status() is a thin shim over this function with
- * types = DC_GET_STATUS_STREAM and a stream filter.
- *
* Return: DC_OK on success, DC_ERROR_UNEXPECTED if state is NULL.
*/
enum dc_status dc_state_get_status(struct dc_state_status *status,
@@ -2258,6 +2346,16 @@ struct dc_validation_set {
* @stream_count: Number of active entries in @streams
*/
uint8_t stream_count;
+
+ /**
+ * @probes: Global probe descriptors to validate alongside the streams
+ */
+ struct dc_probe_state probes[MAX_PROBES];
+
+ /**
+ * @probe_count: Number of active entries in @probes
+ */
+ uint8_t probe_count;
};
bool dc_validate_boot_timing(const struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index a866688ad9db..4530f294f1c2 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -329,7 +329,6 @@ struct dc_stream_state {
enum dc_drr_trigger_mode drr_trigger_mode;
- struct dc_update_scratch_space *update_scratch;
bool firmware_controlled_hdr_info_packet;
};
@@ -408,30 +407,8 @@ bool dc_update_planes_and_stream(struct dc *dc,
struct dc_stream_state *dc_stream,
struct dc_stream_update *stream_update);
-struct dc_update_scratch_space;
struct dc_state_update;
-size_t dc_update_scratch_space_size(void);
-
-struct dc_update_scratch_space *dc_update_state_init(
- struct dc *dc,
- const struct dc_state_update *updates
-);
-
-// Locked, false is failed
-bool dc_update_state_prepare(
- struct dc_update_scratch_space *scratch
-);
-
-// Unlocked
-void dc_update_state_execute(
- const struct dc_update_scratch_space *scratch
-);
-
-// Locked, true if call again
-bool dc_update_state_cleanup(
- struct dc_update_scratch_space *scratch
-);
/*
* Set up surface attributes and associate to a stream
@@ -516,10 +493,6 @@ void dc_enable_stereo(
/* Triggers multi-stream synchronization. */
void dc_trigger_sync(struct dc *dc, struct dc_state *context);
-struct dc_update_descriptor dc_check_state_update(
- const struct dc_check_config *check_config,
- struct dc_state_update *updates);
-
/* Shim: packs args into dc_state_update and calls dc_check_state_update(). */
struct dc_update_descriptor dc_check_update_surfaces_for_stream(
const struct dc_check_config *check_config,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index 6754da1e6ee2..4549c435501a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -631,7 +631,7 @@ struct hubbub_perfmon_get_in_order_bw_params {
struct hubbub_perfmon_get_memory_latencies_params {
struct hubbub *hubbub;
uint32_t refclk_mhz;
- struct hubbub_system_latencies *result;
+ struct dc_probe_latencies *result;
};
struct hubbub_perfmon_get_urgent_assertion_count_params {
@@ -2377,7 +2377,7 @@ void hwss_add_hubbub_perfmon_get_in_order_bw(struct block_sequence_state *seq_st
void hwss_add_hubbub_perfmon_get_memory_latencies(struct block_sequence_state *seq_state,
struct hubbub *hubbub, uint32_t refclk_mhz,
- struct hubbub_system_latencies *result);
+ struct dc_probe_latencies *result);
void hwss_add_hubbub_perfmon_get_urgent_assertion_count(struct block_sequence_state *seq_state,
struct hubbub *hubbub, uint32_t refclk_mhz,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index ac3e9eaa569c..e87f9fd60bcb 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -610,27 +610,6 @@ struct dc_dmub_cmd {
enum dm_dmub_wait_type wait_type;
};
-/**
- * struct dc_probe_status - DC-internal latched perfmon results for a probe.
- * @valid: true if a measurement was latched this commit.
- * @type: type of the probe that produced this result.
- * @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
- * @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
- * stored as struct hubbub_system_latencies.
- * @u.urgent_assertion_count: number of urgent assertion events (DC_PROBE_URGENT_ASSERTION_COUNT).
- * @u.prefetch_data_size: total prefetch data in bytes (DC_PROBE_PREFETCH_DATA_SIZE).
- */
-struct dc_probe_status {
- bool valid;
- enum dc_probe_type type;
- union {
- uint32_t bandwidth_mbps;
- struct hubbub_system_latencies latency;
- uint32_t urgent_assertion_count;
- uint32_t prefetch_data_size;
- } u;
-};
-
/**
* struct dc_state - The full description of a state requested by users
*/
@@ -774,4 +753,39 @@ struct dc_requested_memory_qos {
uint32_t max_bw_budget_in_mbps;
};
+enum update_v3_flow {
+ UPDATE_V3_FLOW_INVALID,
+ UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST,
+ UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL,
+ UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS,
+ UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW,
+ UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT,
+};
+
+struct pipe_split_policy_backup {
+ bool dynamic_odm_policy;
+ bool subvp_policy;
+ enum pipe_split_policy mpc_policy;
+ char force_odm[MAX_PIPES];
+};
+
+struct dc_update_scratch_space {
+ struct dc *dc;
+ struct dc_surface_update *surface_updates;
+ int surface_count;
+ struct dc_stream_state *stream;
+ struct dc_stream_update *stream_update;
+ const struct dc_probe_updates *probe_updates;
+ bool update_v3;
+ bool do_clear_update_bits;
+ enum dc_update_type update_type;
+ struct dc_state *new_context;
+ enum update_v3_flow flow;
+ struct dc_state *backup_context;
+ struct dc_state *intermediate_context;
+ struct pipe_split_policy_backup intermediate_policy;
+ struct dc_surface_update intermediate_updates[MAX_SURFACES];
+ int intermediate_count;
+};
+
#endif /* _CORE_TYPES_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
index fd742b320128..02bc0010e565 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -145,12 +145,6 @@ struct dcn_hubbub_reg_state {
uint32_t compbuf_ctrl;
};
-struct hubbub_system_latencies {
- uint32_t max_latency_ns;
- uint32_t avg_latency_ns;
- uint32_t min_latency_ns;
-};
-
struct hubbub_urgent_latency_params {
uint32_t refclk_mhz;
uint32_t t_win_ns;
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index b64ba8c0adb1..d3171e70e07c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -582,6 +582,10 @@ bool resource_validate_attach_surfaces(
struct dc_state *context,
const struct resource_pool *pool);
+enum dc_status resource_validate_probe_set(struct dc *dc,
+ const struct dc_probe_state *probes,
+ uint8_t probe_count);
+
enum dc_status resource_map_clock_resources(
const struct dc *dc,
struct dc_state *context,
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 57/70] drm/amd/display: Make dc_state_update const in commit path
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (55 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 56/70] drm/amd/display: Wire probe commit path into dc_update_state Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 58/70] drm/amd/display: Remove unused-but-set variable hubp from Wayne Lin
` (12 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Dominik Kaszewski
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
The state-update commit path only reads the caller's update
descriptor, it never mutates the dc_state_update root. Making the
pointer const documents that contract.
[How]
Add const to the updates parameter of dc_update_state and
dc_check_state_update. Mark the single-assignment locals in
dc_update_state_init const and replace the memset plus
field-by-field assignment with a compound literal initializer.
Reviewed-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 42 ++++++++++++------------
drivers/gpu/drm/amd/display/dc/dc.h | 4 +--
2 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 2bd579340b64..318c3b28e918 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -3282,7 +3282,7 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
*/
struct dc_update_descriptor dc_check_state_update(
const struct dc_check_config *check_config,
- struct dc_state_update *updates)
+ const struct dc_state_update *updates)
{
struct dc_update_descriptor desc = {0};
@@ -6264,7 +6264,7 @@ static void dc_update_scratch_release(struct dc *dc,
* @updates: root update object carrying stream, plane, and probe updates
* Return: true on success, false on failure.
*/
-bool dc_update_state(struct dc *dc, struct dc_state_update *updates)
+bool dc_update_state(struct dc *dc, const struct dc_state_update *updates)
{
struct dc_update_scratch_space *scratch;
bool more = true;
@@ -8525,11 +8525,11 @@ struct dc_update_scratch_space *dc_update_state_init(
{
const enum dce_version version = dc->ctx->dce_version;
struct dc_update_scratch_space *scratch = dc_update_scratch_acquire(dc);
- bool has_stream_or_plane = updates->stream || updates->stream_update || updates->surface_updates;
- bool has_probe = updates->probe_updates;
- bool surface_without_stream = updates->surface_updates && !updates->stream;
- bool stream_update_without_stream = updates->stream_update && !updates->stream;
- bool bad_surface_count = updates->surface_count > 0 && !updates->surface_updates;
+ const bool has_stream_or_plane = updates->stream || updates->stream_update || updates->surface_updates;
+ const bool has_probe = updates->probe_updates;
+ const bool surface_without_stream = updates->surface_updates && !updates->stream;
+ const bool stream_update_without_stream = updates->stream_update && !updates->stream;
+ const bool bad_surface_count = updates->surface_count > 0 && !updates->surface_updates;
if (!scratch)
return NULL;
@@ -8544,20 +8544,20 @@ struct dc_update_scratch_space *dc_update_state_init(
return NULL;
}
- memset(scratch, 0, sizeof(*scratch));
-
- scratch->dc = dc;
- scratch->surface_updates = updates->surface_updates;
- scratch->surface_count = updates->surface_count;
- scratch->stream = updates->stream;
- scratch->stream_update = updates->stream_update;
- scratch->probe_updates = updates->probe_updates;
- scratch->update_v3 = version >= DCN_VERSION_4_01
- || version == DCN_VERSION_3_2
- || version == DCN_VERSION_3_21;
- scratch->do_clear_update_bits = version >= DCN_VERSION_1_0;
- scratch->new_context = NULL;
- scratch->flow = UPDATE_V3_FLOW_INVALID;
+ *scratch = (struct dc_update_scratch_space){
+ .dc = dc,
+ .surface_updates = updates->surface_updates,
+ .surface_count = updates->surface_count,
+ .stream = updates->stream,
+ .stream_update = updates->stream_update,
+ .probe_updates = updates->probe_updates,
+ .update_v3 = version >= DCN_VERSION_4_01
+ || version == DCN_VERSION_3_2
+ || version == DCN_VERSION_3_21,
+ .do_clear_update_bits = version >= DCN_VERSION_1_0,
+ .new_context = NULL,
+ .flow = UPDATE_V3_FLOW_INVALID,
+ };
return scratch;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 0913fab7504c..743dde3d10ab 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2125,7 +2125,7 @@ struct dc_state_update {
*/
struct dc_update_descriptor dc_check_state_update(
const struct dc_check_config *check_config,
- struct dc_state_update *updates);
+ const struct dc_state_update *updates);
/**
* dc_update_state - Commit an absolute dc_state_update.
@@ -2134,7 +2134,7 @@ struct dc_update_descriptor dc_check_state_update(
*
* Return: true on success, false on failure.
*/
-bool dc_update_state(struct dc *dc, struct dc_state_update *updates);
+bool dc_update_state(struct dc *dc, const struct dc_state_update *updates);
struct dc_update_scratch_space;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 58/70] drm/amd/display: Remove unused-but-set variable hubp from
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (56 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 57/70] drm/amd/display: Make dc_state_update const in commit path Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 59/70] drm/amd/display: set new_stream to NULL after release Wayne Lin
` (11 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Gleb Markov, George Zhang
From: Gleb Markov <markov.gi@npc-ksb.ru>
The final check of hubp for NULL covers all remaining lines of code, since
the value of hubp does not change until the end of the method.
This check is redundant because hubp1 is already dereferenced within the
macro.
If it were NULL, the program would have already failed to proceed.
Remove the left part of the expression with the logical "&&".
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: be1fb44389ca ("drm/amd/display: Check null pointers before used").
Reviewed-by: George Zhang <george.zhang@amd.com>
Signed-off-by: Gleb Markov <markov.gi@npc-ksb.ru>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
index 7c97a774141f..d8eb5996b577 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
@@ -772,8 +772,7 @@ bool hubp1_is_flip_pending(struct hubp *hubp)
if (flip_pending)
return true;
- if (hubp &&
- earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part)
+ if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part)
return true;
return false;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 59/70] drm/amd/display: set new_stream to NULL after release
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (57 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 58/70] drm/amd/display: Remove unused-but-set variable hubp from Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 60/70] drm/amd/display: Register DCN as a PMFW DF C-state client on DCN42 Wayne Lin
` (10 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, WenTao Liang, stable,
George Zhang
From: WenTao Liang <vulab@iscas.ac.cn>
In dm_update_crtc_state(), the skip_modeset path releases new_stream
via dc_stream_release() but does not set the pointer to NULL.
If a later error (e.g., color management failure) triggers the fail
label, the error path calls dc_stream_release() again on the same
dangling pointer, causing a double release and potential use-after-free.
Fix this by setting new_stream to NULL after the initial release.
Fixes: 9b690ef3c7042 ("drm/amd/display: Avoid full modeset when not required")
Cc: stable@vger.kernel.org
Reviewed-by: George Zhang <george.zhang@amd.com>
Signed-off-by: WenTao Liang <vulab@iscas.ac.cn>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 +
1 file changed, 1 insertion(+)
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 9a3f78c17a5a..5a9afc0607b2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6063,6 +6063,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
/* Release extra reference */
if (new_stream)
dc_stream_release(new_stream);
+ new_stream = NULL;
/*
* We want to do dc stream updates that do not require a
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 60/70] drm/amd/display: Register DCN as a PMFW DF C-state client on DCN42
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (58 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 59/70] drm/amd/display: set new_stream to NULL after release Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 61/70] drm/amd/display: fix wrong register field in dccg35_set_hdmistreamclk_src_new Wayne Lin
` (9 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Leo Chen, Nicholas Kazlauskas
From: Leo Chen <leo.chen@amd.com>
[Why]
DCN must not gate DF C-state locally via the DCHUBBUB ALLOW_SELF_REFRESH
controls: forcing a local "disallow" during MM-stutter re-entry can wedge the
fabric and hang boot. When DCN is disallowing c-state or has invalid watermarks
we should be explicit about it rather than using the watermark force selector.
[How]
Register DCN as a client of PMFW's DF C-state arbiter and signal over DALSMC
whether DCN permits DF C-state; PMFW allows DF C-state only once every client
(including DCN) has voted "allow".
- dc_clocks.cstate_allow: last DCN vote acked by PMFW
- clk_mgr_funcs::notify_cstate_disable(clk_mgr, disable)
prepare_bandwidth and headless dc_power_down_on_boot vote Allow;
hardware_release votes Disallow; init_clocks
(D0 entry) only clears the cache (cstate_allow) so the next allow re-syncs with
PMFW.
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c | 28 ++++++++++++++++++
.../display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h | 1 +
.../amd/display/dc/clk_mgr/dcn42/dcn42_smu.c | 29 ++++++++++++++++++-
.../amd/display/dc/clk_mgr/dcn42/dcn42_smu.h | 2 ++
drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++
drivers/gpu/drm/amd/display/dc/dc.h | 9 ++++++
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.c | 10 +++++++
.../gpu/drm/amd/display/dc/inc/hw/clk_mgr.h | 10 +++++++
8 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
index 3baac7fa313a..c7b9bad93a93 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
@@ -375,6 +375,24 @@ void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base)
dcn42_smu_enable_pme_wa(clk_mgr);
}
+void dcn42_notify_cstate_disable(struct clk_mgr *clk_mgr_base, bool disable)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ bool target_allow = !disable;
+
+ DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
+
+ /* Idempotent: only send when the cached vote actually changes. */
+ if (clk_mgr_base->clks.cstate_allow == target_allow)
+ return;
+
+ if (dcn42_smu_set_df_cstate_disable(clk_mgr, disable))
+ clk_mgr_base->clks.cstate_allow = target_allow;
+ else
+ DC_LOG_WARNING("%s: PMFW did not ack DfCstateDisable(%s); leaving cstate_allow=%d to retry\n",
+ __func__, disable ? "Disable" : "Allow", clk_mgr_base->clks.cstate_allow);
+}
+
bool dcn42_are_clock_states_equal(struct dc_clocks *a,
struct dc_clocks *b)
@@ -594,6 +612,15 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
init_clk_states(clk_mgr_base);
+ /*
+ * DF C-state policy
+ * D0 entry must NOT send a PMFW message, but must unconditionally clear
+ * the cached vote so the next allow-side transition (prepare_bandwidth
+ * or dc_power_down_on_boot) is guaranteed to issue a fresh
+ * DfCstateDisable(Allow) and resync DAL with PMFW.
+ */
+ clk_mgr_base->clks.cstate_allow = false;
+
// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
if (dcn42_is_spll_ssc_enabled(clk_mgr_base))
clk_mgr_base->dp_dto_source_clock_in_khz =
@@ -1038,6 +1065,7 @@ static struct clk_mgr_funcs dcn42_funcs = {
.get_max_clock_khz = dcn42_get_max_clock_khz,
.get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist,
.is_smu_present = dcn42_is_smu_present,
+ .notify_cstate_disable = dcn42_notify_cstate_disable,
};
struct clk_mgr_funcs dcn42_fpga_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h
index 9568ca06f00f..330242747fff 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h
@@ -67,6 +67,7 @@ unsigned int dcn42_convert_wck_ratio(uint8_t wck_ratio);
extern struct dcn42_ss_info_table dcn42_ss_info_table;
void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_watermarks *table);
void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base);
+void dcn42_notify_cstate_disable(struct clk_mgr *clk_mgr_base, bool disable);
void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base);
void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base);
void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c
index 6d0012b7d6dc..5e8d979f25f0 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c
@@ -85,7 +85,8 @@
#define DALSMC_MSG_DispIPS2Exit 0x11 ///< Display IPS2 exit
#define DALSMC_MSG_QueryIPS2Support 0x12 ///< Return 1: support; else not supported
-#define DALSMC_Message_Count 0x13 ///< Total number of VBIS and DAL messages
+#define DALSMC_MSG_DfCstateDisable 0x13 ///< DCN DF C-state vote (PMFW FWDEV-193711): param 0 = Allow, 1 = Disable
+#define DALSMC_Message_Count 0x14 ///< Total number of VBIS and DAL messages
/** @}*/
@@ -428,3 +429,29 @@ void dcn42_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
enable);
smu_print("%s: smu_set_dtbclk = %d\n", __func__, enable ? 1 : 0);
}
+
+/*
+ * Vote DCN's DF C-state policy to PMFW. param: 0 = Allow, 1 = Disable.
+ * Returns true only when PMFW acknowledged the vote (or there is no SMU to
+ * talk to, in which case there is no DF arbiter to satisfy). On a non-OK
+ * response the caller must NOT update its cached cstate_allow so the next
+ * transition retries
+ */
+bool dcn42_smu_set_df_cstate_disable(struct clk_mgr_internal *clk_mgr, bool disable)
+{
+ int retv;
+
+ if (!clk_mgr->smu_present)
+ return true;
+
+ retv = dcn42_smu_send_msg_with_param(
+ clk_mgr,
+ DALSMC_MSG_DfCstateDisable,
+ disable ? 1 : 0);
+
+ smu_print("%s: DfCstateDisable param = %d, return = %d\n",
+ __func__, disable ? 1 : 0, retv);
+
+ /* dcn42_smu_send_msg_with_param() returns -1 on a non-OK PMFW response. */
+ return retv != -1;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h
index 8ba7ff04dc05..10c67326ff7e 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h
@@ -187,4 +187,6 @@ void dcn42_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *cl
int dcn42_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr);
int dcn42_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr);
+bool dcn42_smu_set_df_cstate_disable(struct clk_mgr_internal *clk_mgr, bool disable);
+
#endif /* DAL_DC_42_SMU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 318c3b28e918..24a01e07a44c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -6544,6 +6544,9 @@ void dc_power_down_on_boot(struct dc *dc)
if (dc->caps.ips_support)
dc_exit_ips_for_hw_access(dc);
dc->hwss.power_down_on_boot(dc);
+
+ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+ dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, false);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 743dde3d10ab..fcaa17b9ab1a 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -759,6 +759,15 @@ struct dc_clocks {
* Elements below are not compared for the purposes of
* optimization required
*/
+
+ /*
+ * @cstate_allow
+ *
+ * DCN's DF C-state vote as last successfully acknowledged by PMFW.
+ * false = DCN does NOT permit DF C-state;
+ * true = DCN permits DF C-state;
+ */
+ bool cstate_allow;
bool prev_p_state_change_support;
bool fclk_prev_p_state_change_support;
int num_ways;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
index 4376bf26f4ce..151a29bf0e9d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
@@ -946,7 +946,11 @@ bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx,
}
void dcn42_hardware_release(struct dc *dc)
{
+ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+ dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, true);
+
dcn35_hardware_release(dc);
+
dc_dmub_srv_release_hw(dc);
}
@@ -1082,6 +1086,12 @@ void dcn42_prepare_bandwidth(
}
dcn401_prepare_bandwidth(dc, context);
+
+ /* valid C-state watermarks have now been committed to HW, so it
+ * is safe to vote "allow" to PMFW.
+ */
+ if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+ dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, false);
}
void dcn42_optimize_bandwidth(struct dc *dc, struct dc_state *context)
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
index 68dc2d4ba7ca..ec678bd249ef 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
@@ -412,6 +412,16 @@ struct clk_mgr_funcs {
struct clk_mgr *clk_mgr,
struct dc_requested_memory_qos *qos);
+ /**
+ * notify_cstate_disable - Vote DCN's DF C-state policy to PMFW.
+ * @disable: true -> vote "disable"
+ * false -> vote "allow"
+ * Sends the message only when the cached dc_clocks.cstate_allow would
+ * change, then updates the cache on an OK response (idempotent no-op
+ * otherwise).
+ */
+ void (*notify_cstate_disable)(struct clk_mgr *clk_mgr, bool disable);
+
void (*build_clock_update_for_bls)(struct clk_mgr *clk_mgr,
struct dc_state *context, bool safe_to_lower,
struct block_sequence_state *seq_state);
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 61/70] drm/amd/display: fix wrong register field in dccg35_set_hdmistreamclk_src_new
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (59 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 60/70] drm/amd/display: Register DCN as a PMFW DF C-state client on DCN42 Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 62/70] drm/amd/display: wire DCN42B mcache programming callback Wayne Lin
` (8 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dyllan Kobal, George Zhang
From: Dyllan Kobal <dyllan.kobal@zetier.com>
dccg35_set_hdmistreamclk_src_new() updates HDMISTREAMCLK_CNTL but
passes DPSTREAMCLK0_SRC_SEL as the field identifier in the second
REG_UPDATE_2 slot.
The current behavior is harmless on DCN3.5 because both fields share the
same bit layout, but it is still incorrect and could break on future
hardware revisions.
Fixes: d36771a03412 ("drm/amd/display: Add DCCG DIO, HPO, OPP, and OPTC support for FRL")
Reviewed-by: George Zhang <george.zhang@amd.com>
Signed-off-by: Dyllan Kobal <dyllan.kobal@zetier.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
index 95ba9baa5102..a7db8a5194e4 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
@@ -572,7 +572,7 @@ static void dccg35_set_hdmistreamclk_src_new(
case 0:
REG_UPDATE_2(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN,
(src == HDMI_STREAM_REFCLK) ? 0 : 1,
- DPSTREAMCLK0_SRC_SEL,
+ HDMISTREAMCLK0_SRC_SEL,
(src == HDMI_STREAM_REFCLK) ? 0 : src);
break;
default:
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 62/70] drm/amd/display: wire DCN42B mcache programming callback
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (60 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 61/70] drm/amd/display: fix wrong register field in dccg35_set_hdmistreamclk_src_new Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 63/70] drm/amd/display: Trim DCE from DCN-only builds Wayne Lin
` (7 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Pengpeng Hou, George Zhang
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
DCN42B enables DML2 and DML21 by default and defines
dcn42b_prepare_mcache_programming(), but the resource function table only
wires the callback when CONFIG_DRM_AMD_DC_DML21 is defined.
There is no in-tree Kconfig symbol named DRM_AMD_DC_DML21, so the
preprocessor always removes the callback entry. Sibling DCN42 and DCN401
resource tables wire their prepare_mcache_programming callbacks
unconditionally, and the core DC code already checks whether the callback
pointer is present before calling it.
Remove the stale guard so DCN42B exposes the callback relation that its
source and DML21 build world already provide.
Reviewed-by: George Zhang <george.zhang@amd.com>
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index 343e10b4e096..2334bc5b75b8 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@ -1915,9 +1915,7 @@ static struct resource_funcs dcn42b_res_pool_funcs = {
.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
.add_phantom_pipes = dcn32_add_phantom_pipes,
.calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes,
-#ifdef CONFIG_DRM_AMD_DC_DML21
.prepare_mcache_programming = dcn42b_prepare_mcache_programming,
-#endif
.build_pipe_pix_clk_params = dcn42b_build_pipe_pix_clk_params,
.get_power_profile = dcn401_get_power_profile,
.get_vstartup_for_pipe = dcn401_get_vstartup_for_pipe,
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 63/70] drm/amd/display: Trim DCE from DCN-only builds
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (61 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 62/70] drm/amd/display: wire DCN42B mcache programming callback Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 64/70] drm/amd/display: hide Apple Studio Display secondary tile Wayne Lin
` (6 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Gaghik Khachatrian, Aric Cyr
From: Gaghik Khachatrian <gaghik.khachatrian@amd.com>
Removed dependency on legacy DCE sources in production builds for
platforms that only support DCN ASICs. This decouples the always-compiled
shared/DCN code from DCE while preserving DCE for platforms that need it.
No functional change when TRIM_DCE is disabled.
DCE support is preserved for platforms that require it.
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Gaghik Khachatrian <gaghik.khachatrian@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/dc/bios/bios_parser_interface.c | 2 +
.../display/dc/bios/command_table_helper.c | 2 +
.../display/dc/bios/command_table_helper.h | 2 +
.../display/dc/bios/command_table_helper2.c | 2 +
.../display/dc/bios/command_table_helper2.h | 4 +-
.../dc/bios/command_table_helper_struct.h | 2 +
.../dc/bios/dcn10/command_table_helper2_dcn.c | 293 +++
.../dc/bios/dcn10/command_table_helper2_dcn.h | 34 +
.../gpu/drm/amd/display/dc/clk_mgr/Makefile | 2 +-
.../gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c | 4 +
.../display/dc/clk_mgr/dcn10/dcn10_clk_mgr.c | 203 ++
.../display/dc/clk_mgr/dcn10/dcn10_clk_mgr.h | 43 +
.../display/dc/clk_mgr/dcn10/rv1_clk_mgr.c | 9 +-
.../display/dc/clk_mgr/dcn10/rv2_clk_mgr.c | 6 +-
.../display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c | 12 +-
.../dc/clk_mgr/dcn201/dcn201_clk_mgr.c | 6 +-
.../amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c | 6 +-
.../display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c | 8 +-
.../display/dc/clk_mgr/dcn301/vg_clk_mgr.c | 8 +-
.../display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c | 10 +-
.../dc/clk_mgr/dcn314/dcn314_clk_mgr.c | 10 +-
.../dc/clk_mgr/dcn315/dcn315_clk_mgr.c | 10 +-
.../dc/clk_mgr/dcn316/dcn316_clk_mgr.c | 10 +-
.../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 18 +-
.../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 12 +-
.../dc/clk_mgr/dcn401/dcn401_clk_mgr.c | 18 +-
.../display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c | 14 +-
.../dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c | 10 +-
.../gpu/drm/amd/display/dc/core/dc_resource.c | 78 +
.../dc/dcn10/dcn10_hw_sequencer_debug.c | 2 +-
.../gpu/drm/amd/display/dc/gpio/hw_factory.c | 4 +
.../drm/amd/display/dc/gpio/hw_translate.c | 4 +
.../amd/display/dc/hwss/dce110/dce110_hwseq.h | 3 +
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 1958 +++++++++++++++++
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 66 +-
.../amd/display/dc/hwss/dcn10/dcn10_init.c | 44 +-
.../amd/display/dc/hwss/dcn20/dcn20_init.c | 42 +-
.../amd/display/dc/hwss/dcn201/dcn201_init.c | 44 +-
.../amd/display/dc/hwss/dcn21/dcn21_hwseq.c | 8 +-
.../amd/display/dc/hwss/dcn21/dcn21_init.c | 36 +-
.../amd/display/dc/hwss/dcn30/dcn30_init.c | 34 +-
.../amd/display/dc/hwss/dcn301/dcn301_init.c | 32 +-
.../amd/display/dc/hwss/dcn31/dcn31_init.c | 34 +-
.../amd/display/dc/hwss/dcn314/dcn314_init.c | 32 +-
.../amd/display/dc/hwss/dcn32/dcn32_init.c | 34 +-
.../amd/display/dc/hwss/dcn35/dcn35_init.c | 32 +-
.../amd/display/dc/hwss/dcn351/dcn351_init.c | 32 +-
.../amd/display/dc/hwss/dcn401/dcn401_init.c | 34 +-
.../amd/display/dc/hwss/dcn42/dcn42_init.c | 34 +-
.../gpu/drm/amd/display/dc/irq/irq_service.c | 31 +
.../gpu/drm/amd/display/dc/irq/irq_service.h | 9 +
.../dc/resource/dcn10/dcn10_resource.c | 2 +-
.../dc/resource/dcn20/dcn20_resource.c | 2 +-
.../dc/resource/dcn201/dcn201_resource.c | 2 +-
.../dc/resource/dcn21/dcn21_resource.c | 2 +-
.../dc/resource/dcn30/dcn30_resource.c | 2 +-
.../dc/resource/dcn301/dcn301_resource.c | 2 +-
.../dc/resource/dcn31/dcn31_resource.c | 4 +-
.../dc/resource/dcn314/dcn314_resource.c | 2 +-
.../dc/resource/dcn315/dcn315_resource.c | 2 +-
.../dc/resource/dcn316/dcn316_resource.c | 2 +-
.../dc/resource/dcn32/dcn32_resource.c | 2 +-
.../dc/resource/dcn321/dcn321_resource.c | 2 +-
.../dc/resource/dcn35/dcn35_resource.c | 2 +-
.../dc/resource/dcn351/dcn351_resource.c | 2 +-
.../dc/resource/dcn36/dcn36_resource.c | 2 +-
.../dc/resource/dcn401/dcn401_resource.c | 2 +-
.../dc/resource/dcn42/dcn42_resource.c | 2 +-
.../dc/resource/dcn42b/dcn42b_resource.c | 2 +-
.../amd/display/include/link_service_types.h | 6 +-
70 files changed, 3074 insertions(+), 357 deletions(-)
create mode 100644 drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.c
create mode 100644 drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.h
create mode 100644 drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.c
create mode 100644 drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.h
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c
index 0079a1e26efd..02ac1993c71c 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c
@@ -40,9 +40,11 @@ struct dc_bios *dal_bios_parser_create(
bios = firmware_parser_create(init, dce_version);
+#if !defined(TRIM_DCE)
/* Fall back to old bios parser for older asics */
if (bios == NULL)
bios = bios_parser_create(init, dce_version);
+#endif
return bios;
}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c
index 91bc8a06e2cf..7d64aa9cc733 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c
@@ -31,6 +31,7 @@
#include "command_table_helper.h"
+#if !defined(TRIM_DCE)
bool dal_bios_parser_init_cmd_tbl_helper(
const struct command_table_helper **h,
enum dce_version dce)
@@ -69,6 +70,7 @@ bool dal_bios_parser_init_cmd_tbl_helper(
return false;
}
}
+#endif
/* real implementations */
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h
index 547700e119a6..f0849abcbe08 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h
@@ -29,9 +29,11 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/command_table_helper_dce60.h"
#endif
+#if !defined(TRIM_DCE)
#include "dce80/command_table_helper_dce80.h"
#include "dce110/command_table_helper_dce110.h"
#include "dce112/command_table_helper_dce112.h"
+#endif
#include "command_table_helper_struct.h"
bool dal_bios_parser_init_cmd_tbl_helper(const struct command_table_helper **h,
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
index 902f06ac43c6..b974c57e92d0 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
@@ -45,6 +45,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
return true;
#endif
+#if !defined(TRIM_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@@ -58,6 +59,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
case DCE_VERSION_11_0:
*h = dal_cmd_tbl_helper_dce110_get_table();
return true;
+#endif
case DCE_VERSION_11_2:
case DCE_VERSION_11_22:
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h
index 66e0a3e73768..9e6c44afeceb 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h
@@ -29,9 +29,11 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/command_table_helper_dce60.h"
#endif
+#if !defined(TRIM_DCE)
#include "dce80/command_table_helper_dce80.h"
#include "dce110/command_table_helper_dce110.h"
-#include "dce112/command_table_helper2_dce112.h"
+#endif
+#include "dcn10/command_table_helper2_dcn.h"
#include "command_table_helper_struct.h"
bool dal_bios_parser_init_cmd_tbl_helper2(const struct command_table_helper **h,
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h
index 1f2c0a3f06f9..31e56fba15b8 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h
@@ -26,9 +26,11 @@
#ifndef __DAL_COMMAND_TABLE_HELPER_STRUCT_H__
#define __DAL_COMMAND_TABLE_HELPER_STRUCT_H__
+#if !defined(TRIM_DCE)
#include "dce80/command_table_helper_dce80.h"
#include "dce110/command_table_helper_dce110.h"
#include "dce112/command_table_helper_dce112.h"
+#endif
struct _DIG_ENCODER_CONTROL_PARAMETERS_V2;
struct command_table_helper {
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.c b/drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.c
new file mode 100644
index 000000000000..5b483ac29192
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2012-15 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 "dm_services.h"
+
+#include "atom.h"
+
+#include "include/bios_parser_types.h"
+
+#include "../command_table_helper.h"
+
+#include "../command_table_helper2.h"
+
+static uint8_t signal_type_to_atom_dig_mode(enum signal_type s)
+{
+ uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP;
+
+ switch (s) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_EDP:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP;
+ break;
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI;
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_HDMI;
+ break;
+ case SIGNAL_TYPE_HDMI_FRL:
+ atom_dig_mode = 4;
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP_MST;
+ break;
+ default:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI;
+ break;
+ }
+
+ return atom_dig_mode;
+}
+
+static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
+{
+ uint8_t atom_hpd_sel = 0;
+
+ switch (id) {
+ case HPD_SOURCEID1:
+ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD1_SEL;
+ break;
+ case HPD_SOURCEID2:
+ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD2_SEL;
+ break;
+ case HPD_SOURCEID3:
+ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD3_SEL;
+ break;
+ case HPD_SOURCEID4:
+ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD4_SEL;
+ break;
+ case HPD_SOURCEID5:
+ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD5_SEL;
+ break;
+ case HPD_SOURCEID6:
+ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD6_SEL;
+ break;
+ case HPD_SOURCEID_UNKNOWN:
+ default:
+ atom_hpd_sel = 0;
+ break;
+ }
+ return atom_hpd_sel;
+}
+
+static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
+{
+ (void)id;
+ /* On any ASIC after DCE80, we manually program the DIG_FE
+ * selection (see connect_dig_be_to_fe function of the link
+ * encoder), so translation should always return 0 (no FE).
+ */
+
+ return 0;
+}
+
+static bool clock_source_id_to_atom(
+ enum clock_source_id id,
+ uint32_t *atom_pll_id)
+{
+ bool result = true;
+
+ if (atom_pll_id != NULL)
+ switch (id) {
+ case CLOCK_SOURCE_COMBO_PHY_PLL0:
+ *atom_pll_id = ATOM_COMBOPHY_PLL0;
+ break;
+ case CLOCK_SOURCE_COMBO_PHY_PLL1:
+ *atom_pll_id = ATOM_COMBOPHY_PLL1;
+ break;
+ case CLOCK_SOURCE_COMBO_PHY_PLL2:
+ *atom_pll_id = ATOM_COMBOPHY_PLL2;
+ break;
+ case CLOCK_SOURCE_COMBO_PHY_PLL3:
+ *atom_pll_id = ATOM_COMBOPHY_PLL3;
+ break;
+ case CLOCK_SOURCE_COMBO_PHY_PLL4:
+ *atom_pll_id = ATOM_COMBOPHY_PLL4;
+ break;
+ case CLOCK_SOURCE_COMBO_PHY_PLL5:
+ *atom_pll_id = ATOM_COMBOPHY_PLL5;
+ break;
+ case CLOCK_SOURCE_COMBO_DISPLAY_PLL0:
+ *atom_pll_id = ATOM_PPLL0;
+ break;
+ case CLOCK_SOURCE_ID_DFS:
+ *atom_pll_id = ATOM_GCK_DFS;
+ break;
+ case CLOCK_SOURCE_ID_VCE:
+ *atom_pll_id = ATOM_DP_DTO;
+ break;
+ case CLOCK_SOURCE_ID_DP_DTO:
+ *atom_pll_id = ATOM_DP_DTO;
+ break;
+ case CLOCK_SOURCE_ID_UNDEFINED:
+ /* Should not happen */
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ result = false;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static uint8_t encoder_action_to_atom(enum bp_encoder_control_action action)
+{
+ uint8_t atom_action = 0;
+
+ switch (action) {
+ case ENCODER_CONTROL_ENABLE:
+ atom_action = ATOM_ENABLE;
+ break;
+ case ENCODER_CONTROL_DISABLE:
+ atom_action = ATOM_DISABLE;
+ break;
+ case ENCODER_CONTROL_SETUP:
+ atom_action = ATOM_ENCODER_CMD_STREAM_SETUP;
+ break;
+ case ENCODER_CONTROL_INIT:
+ atom_action = ATOM_ENCODER_INIT;
+ break;
+ default:
+ BREAK_TO_DEBUGGER(); /* Unhandle action in driver.!! */
+ break;
+ }
+
+ return atom_action;
+}
+
+static uint8_t disp_power_gating_action_to_atom(
+ enum bp_pipe_control_action action)
+{
+ uint8_t atom_pipe_action = 0;
+
+ switch (action) {
+ case ASIC_PIPE_DISABLE:
+ atom_pipe_action = ATOM_DISABLE;
+ break;
+ case ASIC_PIPE_ENABLE:
+ atom_pipe_action = ATOM_ENABLE;
+ break;
+ case ASIC_PIPE_INIT:
+ atom_pipe_action = ATOM_INIT;
+ break;
+ default:
+ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
+ break;
+ }
+
+ return atom_pipe_action;
+}
+
+static bool dc_clock_type_to_atom(
+ enum bp_dce_clock_type id,
+ uint32_t *atom_clock_type)
+{
+ bool retCode = true;
+
+ if (atom_clock_type != NULL) {
+ switch (id) {
+ case DCECLOCK_TYPE_DISPLAY_CLOCK:
+ *atom_clock_type = DCE_CLOCK_TYPE_DISPCLK;
+ break;
+
+ case DCECLOCK_TYPE_DPREFCLK:
+ *atom_clock_type = DCE_CLOCK_TYPE_DPREFCLK;
+ break;
+
+ default:
+ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
+ break;
+ }
+ }
+
+ return retCode;
+}
+
+static uint8_t transmitter_color_depth_to_atom(enum transmitter_color_depth id)
+{
+ uint8_t atomColorDepth = 0;
+
+ switch (id) {
+ case TRANSMITTER_COLOR_DEPTH_24:
+ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
+ break;
+ case TRANSMITTER_COLOR_DEPTH_30:
+ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
+ break;
+ case TRANSMITTER_COLOR_DEPTH_36:
+ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
+ break;
+ case TRANSMITTER_COLOR_DEPTH_48:
+ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
+ break;
+ default:
+ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
+ break;
+ }
+
+ return atomColorDepth;
+}
+
+/* function table */
+static const struct command_table_helper command_table_helper_funcs = {
+ .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom2,
+ .encoder_action_to_atom = encoder_action_to_atom,
+ .engine_bp_to_atom = engine_bp_to_atom,
+ .clock_source_id_to_atom = clock_source_id_to_atom,
+ .clock_source_id_to_atom_phy_clk_src_id =
+ clock_source_id_to_atom_phy_clk_src_id,
+ .signal_type_to_atom_dig_mode = signal_type_to_atom_dig_mode,
+ .hpd_sel_to_atom = hpd_sel_to_atom,
+ .dig_encoder_sel_to_atom = dig_encoder_sel_to_atom,
+ .phy_id_to_atom = phy_id_to_atom,
+ .disp_power_gating_action_to_atom = disp_power_gating_action_to_atom,
+ .clock_source_id_to_ref_clk_src = NULL,
+ .transmitter_bp_to_atom = NULL,
+ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom2,
+ .encoder_mode_bp_to_atom =
+ dal_cmd_table_helper_encoder_mode_bp_to_atom2,
+ .dc_clock_type_to_atom = dc_clock_type_to_atom,
+ .transmitter_color_depth_to_atom = transmitter_color_depth_to_atom,
+};
+
+/*
+ * dal_cmd_tbl_helper_dce112_get_table2
+ *
+ * @brief
+ * Initialize command table helper functions
+ *
+ * @param
+ * const struct command_table_helper **h - [out] struct of functions
+ *
+ */
+const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table2(void)
+{
+ return &command_table_helper_funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.h b/drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.h
new file mode 100644
index 000000000000..b6fca8fa6b88
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dcn10/command_table_helper2_dcn.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012-15 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 __DAL_COMMAND_TABLE_HELPER2_DCN_H__
+#define __DAL_COMMAND_TABLE_HELPER2_DCN_H__
+
+struct command_table_helper;
+
+/* Initialize command table helper functions */
+const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table2(void);
+
+#endif /* __DAL_COMMAND_TABLE_HELPER2_DCN_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
index fb234a729bdc..a0e0e1ecf3ad 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
@@ -66,7 +66,7 @@ ifdef CONFIG_DRM_AMD_DC_FP
###############################################################################
# DCN10
###############################################################################
-CLK_MGR_DCN10 = rv1_clk_mgr.o rv1_clk_mgr_vbios_smu.o rv2_clk_mgr.o
+CLK_MGR_DCN10 = dcn10_clk_mgr.o rv1_clk_mgr.o rv1_clk_mgr_vbios_smu.o rv2_clk_mgr.o
AMD_DAL_CLK_MGR_DCN10 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn10/,$(CLK_MGR_DCN10))
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
index 5f9a6bb84324..f99d12b648b6 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
@@ -30,10 +30,12 @@
#include "dc_state_priv.h"
#include "link_service.h"
+#if !defined(TRIM_DCE)
#include "dce100/dce_clk_mgr.h"
#include "dce110/dce110_clk_mgr.h"
#include "dce112/dce112_clk_mgr.h"
#include "dce120/dce120_clk_mgr.h"
+#endif /* !TRIM_DCE */
#include "dcn10/rv1_clk_mgr.h"
#include "dcn10/rv2_clk_mgr.h"
#include "dcn20/dcn20_clk_mgr.h"
@@ -151,6 +153,7 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
struct hw_asic_id asic_id = ctx->asic_id;
switch (asic_id.chip_family) {
+#if !defined(TRIM_DCE)
case FAMILY_SI:
case FAMILY_CI:
case FAMILY_KV: {
@@ -210,6 +213,7 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
dce120_clk_mgr_construct(ctx, clk_mgr);
return &clk_mgr->base;
}
+#endif /* !TRIM_DCE */
#if defined(CONFIG_DRM_AMD_DC_FP)
case FAMILY_RV: {
struct clk_mgr_internal *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.c
new file mode 100644
index 000000000000..374aea165ed0
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012-16 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 "core_types.h"
+#include "clk_mgr_internal.h"
+#include "dcn10_clk_mgr.h"
+#include "dal_asic_id.h"
+
+int dcn10_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz)
+{
+ struct bp_set_dce_clock_parameters dce_clk_params;
+ struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
+ struct dc *dc = clk_mgr->base.ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ int actual_clock = requested_clk_khz;
+ /* Prepare to program display clock*/
+ memset(&dce_clk_params, 0, sizeof(dce_clk_params));
+
+ /* Make sure requested clock isn't lower than minimum threshold*/
+ if (requested_clk_khz > 0)
+ requested_clk_khz = max(requested_clk_khz,
+ clk_mgr->base.dentist_vco_freq_khz / 62);
+
+ dce_clk_params.target_clock_frequency = requested_clk_khz;
+ dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
+ dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
+
+ bp->funcs->set_dce_clock(bp, &dce_clk_params);
+ actual_clock = dce_clk_params.target_clock_frequency;
+
+ if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
+ if (clk_mgr->dfs_bypass_disp_clk != actual_clock)
+ dmcu->funcs->set_psr_wait_loop(dmcu,
+ actual_clock / 1000 / 7);
+ }
+
+ clk_mgr->dfs_bypass_disp_clk = actual_clock;
+ return actual_clock;
+
+}
+
+int dcn10_set_dprefclk(struct clk_mgr_internal *clk_mgr)
+{
+ struct bp_set_dce_clock_parameters dce_clk_params;
+ struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
+
+ memset(&dce_clk_params, 0, sizeof(dce_clk_params));
+
+ /*Program DP ref Clock*/
+ /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
+ dce_clk_params.target_clock_frequency = 0;
+ dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
+ dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
+ if (!((clk_mgr->base.ctx->asic_id.chip_family == FAMILY_AI) &&
+ ASICREV_IS_VEGA20_P(clk_mgr->base.ctx->asic_id.hw_internal_rev)))
+ dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
+ (dce_clk_params.pll_id ==
+ CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
+ else
+ dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
+
+ bp->funcs->set_dce_clock(bp, &dce_clk_params);
+
+ /* Returns the dp_refclk that was set */
+ return dce_clk_params.target_clock_frequency;
+}
+
+unsigned int dcn_dentist_get_divider_from_did(unsigned int did)
+{
+ if (did < DENTIST_BASE_DID_1)
+ did = DENTIST_BASE_DID_1;
+ if (did > DENTIST_MAX_DID)
+ did = DENTIST_MAX_DID;
+
+ if (did < DENTIST_BASE_DID_2) {
+ return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
+ * (did - DENTIST_BASE_DID_1);
+ } else if (did < DENTIST_BASE_DID_3) {
+ return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
+ * (did - DENTIST_BASE_DID_2);
+ } else if (did < DENTIST_BASE_DID_4) {
+ return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
+ * (did - DENTIST_BASE_DID_3);
+ } else {
+ return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
+ * (did - DENTIST_BASE_DID_4);
+ }
+}
+
+/* SW will adjust DP REF Clock average value for all purposes
+ * (DP DTO / DP Audio DTO and DP GTC)
+ if clock is spread for all cases:
+ -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
+ calculations for DS_INCR/DS_MODULO (this is planned to be default case)
+ -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
+ calculations (not planned to be used, but average clock should still
+ be valid)
+ -if SS enabled on DP Ref clock and HW de-spreading disabled
+ (should not be case with CIK) then SW should program all rates
+ generated according to average value (case as with previous ASICs)
+ */
+
+int dcn_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz)
+{
+ if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
+ struct fixed31_32 ss_percentage = dc_fixpt_div_int(
+ dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
+ clk_mgr_dce->dprefclk_ss_divider), 200);
+ struct fixed31_32 adj_dp_ref_clk_khz;
+
+ ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
+ adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
+ dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
+ }
+ return dp_ref_clk_khz;
+}
+
+int dcn_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
+{
+ struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+ return dcn_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_base->dprefclk_khz);
+}
+
+void dcn_clock_read_ss_info(struct clk_mgr_internal *clk_mgr_dce)
+{
+ struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+ int ss_info_num = bp->funcs->get_ss_entry_number(
+ bp, AS_SIGNAL_TYPE_GPU_PLL);
+
+ if (ss_info_num) {
+ struct spread_spectrum_info info = { { 0 } };
+ enum bp_result result = bp->funcs->get_spread_spectrum_info(
+ bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
+
+ /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
+ * even if SS not enabled and in that case
+ * SSInfo.spreadSpectrumPercentage !=0 would be sign
+ * that SS is enabled
+ */
+ if (result == BP_RESULT_OK &&
+ info.spread_spectrum_percentage != 0) {
+ clk_mgr_dce->ss_on_dprefclk = true;
+ clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
+
+ if (info.type.CENTER_MODE == 0) {
+ /* TODO: Currently for DP Reference clock we
+ * need only SS percentage for
+ * downspread */
+ clk_mgr_dce->dprefclk_ss_percentage =
+ info.spread_spectrum_percentage;
+ }
+
+ return;
+ }
+
+ result = bp->funcs->get_spread_spectrum_info(
+ bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
+
+ /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
+ * even if SS not enabled and in that case
+ * SSInfo.spreadSpectrumPercentage !=0 would be sign
+ * that SS is enabled
+ */
+ if (result == BP_RESULT_OK &&
+ info.spread_spectrum_percentage != 0) {
+ clk_mgr_dce->ss_on_dprefclk = true;
+ clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
+
+ if (info.type.CENTER_MODE == 0) {
+ /* Currently for DP Reference clock we
+ * need only SS percentage for
+ * downspread */
+ clk_mgr_dce->dprefclk_ss_percentage =
+ info.spread_spectrum_percentage;
+ }
+ if (clk_mgr_dce->base.ctx->dc->config.ignore_dpref_ss)
+ clk_mgr_dce->dprefclk_ss_percentage = 0;
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.h
new file mode 100644
index 000000000000..24c7a78522c5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/dcn10_clk_mgr.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012-16 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 DAL_DC_DCN10_CLK_MGR_H_
+#define DAL_DC_DCN10_CLK_MGR_H_
+
+#include "dc.h"
+
+/* functions shared with higher DCN clk mgrs */
+int dcn10_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz);
+int dcn10_set_dprefclk(struct clk_mgr_internal *clk_mgr);
+
+int dcn_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz);
+
+void dcn_clock_read_ss_info(struct clk_mgr_internal *dccg_dce);
+
+int dcn_get_dp_ref_freq_khz(struct clk_mgr *dccg);
+
+unsigned int dcn_dentist_get_divider_from_did(unsigned int did);
+
+#endif /* DAL_DC_DCN10_CLK_MGR_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
index 06a51f47aed7..e36ef034a534 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
@@ -26,8 +26,7 @@
#include "core_types.h"
#include "clk_mgr_internal.h"
#include "rv1_clk_mgr.h"
-#include "dce100/dce_clk_mgr.h"
-#include "dce112/dce112_clk_mgr.h"
+#include "dcn10_clk_mgr.h"
#include "rv1_clk_mgr_vbios_smu.h"
#include "rv1_clk_mgr_clk.h"
@@ -303,14 +302,14 @@ static void rv1_enable_pme_wa(struct clk_mgr *clk_mgr_base)
static struct clk_mgr_funcs rv1_clk_funcs = {
.init_clocks = rv1_init_clocks,
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = rv1_update_clocks,
.enable_pme_wa = rv1_enable_pme_wa,
};
static struct clk_mgr_internal_funcs rv1_clk_internal_funcs = {
.set_dispclk = rv1_vbios_smu_set_dispclk,
- .set_dprefclk = dce112_set_dprefclk
+ .set_dprefclk = dcn10_set_dprefclk
};
void rv1_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_mgr, struct pp_smu_funcs *pp_smu)
@@ -342,7 +341,7 @@ void rv1_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_
if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
clk_mgr->dfs_bypass_enabled = true;
- dce_clock_read_ss_info(clk_mgr);
+ dcn_clock_read_ss_info(clk_mgr);
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv2_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv2_clk_mgr.c
index b9ba6dbc2b46..5c33b520e70d 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv2_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv2_clk_mgr.c
@@ -27,11 +27,11 @@
#include "clk_mgr_internal.h"
#include "rv1_clk_mgr.h"
#include "rv2_clk_mgr.h"
-#include "dce112/dce112_clk_mgr.h"
+#include "dcn10_clk_mgr.h"
static struct clk_mgr_internal_funcs rv2_clk_internal_funcs = {
- .set_dispclk = dce112_set_dispclk,
- .set_dprefclk = dce112_set_dprefclk
+ .set_dispclk = dcn10_set_dispclk,
+ .set_dprefclk = dcn10_set_dprefclk
};
void rv2_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_mgr, struct pp_smu_funcs *pp_smu)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
index cbd989b6a3df..2dc9417969ed 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
@@ -26,7 +26,7 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-#include "dce100/dce_clk_mgr.h"
+#include "dcn10/dcn10_clk_mgr.h"
#include "dcn20_clk_mgr.h"
#include "reg_helper.h"
#include "core_types.h"
@@ -436,8 +436,8 @@ void dcn2_read_clocks_from_hw_dentist(struct clk_mgr *clk_mgr_base)
REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, &dppclk_wdivider);
- disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
- dpp_divider = dentist_get_divider_from_did(dppclk_wdivider);
+ disp_divider = dcn_dentist_get_divider_from_did(dispclk_wdivider);
+ dpp_divider = dcn_dentist_get_divider_from_did(dppclk_wdivider);
if (disp_divider && dpp_divider) {
/* Calculate the current DFS clock, in kHz.*/
@@ -518,7 +518,7 @@ static void dcn2_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc
}
static struct clk_mgr_funcs dcn2_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = dcn2_update_clocks,
.init_clocks = dcn2_init_clocks,
.enable_pme_wa = dcn2_enable_pme_wa,
@@ -558,7 +558,7 @@ void dcn20_clk_mgr_construct(
/* DFS Slice 2 should be used for DPREFCLK */
dprefclk_did = REG_READ(CLK3_CLK2_DFS_CNTL);
/* Convert DPREFCLK DFS Slice DID to actual divider */
- target_div = dentist_get_divider_from_did(dprefclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dprefclk_did);
/* get FbMult value */
pll_req_reg = REG_READ(CLK3_CLK_PLL_REQ);
@@ -588,5 +588,5 @@ void dcn20_clk_mgr_construct(
//Also there is no plan for now that DFS BYPASS will be used on NV10/12/14.
clk_mgr->dfs_bypass_enabled = false;
- dce_clock_read_ss_info(clk_mgr);
+ dcn_clock_read_ss_info(clk_mgr);
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
index 76c612ecfe3c..192e1bf905e3 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
@@ -29,7 +29,7 @@
#include "clk_mgr_internal.h"
#include "dcn201_clk_mgr.h"
#include "dcn20/dcn20_clk_mgr.h"
-#include "dce100/dce_clk_mgr.h"
+#include "dcn10/dcn10_clk_mgr.h"
#include "dm_helpers.h"
#include "dm_services.h"
@@ -170,7 +170,7 @@ static void dcn201_update_clocks(struct clk_mgr *clk_mgr_base,
}
static struct clk_mgr_funcs dcn201_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = dcn201_update_clocks,
.init_clocks = dcn201_init_clocks,
.get_clock = dcn2_get_clock,
@@ -213,5 +213,5 @@ void dcn201_clk_mgr_construct(struct dc_context *ctx,
if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
clk_mgr->dfs_bypass_enabled = true;
- dce_clock_read_ss_info(clk_mgr);
+ dcn_clock_read_ss_info(clk_mgr);
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
index b5378344d2bc..6c24cf204ec6 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
@@ -29,7 +29,7 @@
#include "dcn20/dcn20_clk_mgr.h"
#include "dml/dcn20/dcn20_fpu.h"
-#include "dce100/dce_clk_mgr.h"
+#include "dcn10/dcn10_clk_mgr.h"
#include "rn_clk_mgr_vbios_smu.h"
#include "reg_helper.h"
#include "core_types.h"
@@ -565,7 +565,7 @@ static void rn_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct dc_l
}
static struct clk_mgr_funcs dcn21_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = rn_update_clocks,
.init_clocks = rn_init_clocks,
.enable_pme_wa = rn_enable_pme_wa,
@@ -770,7 +770,7 @@ void rn_clk_mgr_construct(
rn_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info);
clk_mgr->base.dprefclk_khz = 600000;
- dce_clock_read_ss_info(clk_mgr);
+ dcn_clock_read_ss_info(clk_mgr);
clk_mgr->base.bw_params = &rn_bw_params;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
index 958b8d1dad2f..1e8056657257 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
@@ -27,7 +27,7 @@
#include "clk_mgr_internal.h"
#include "dcn30_clk_mgr_smu_msg.h"
#include "dcn20/dcn20_clk_mgr.h"
-#include "dce100/dce_clk_mgr.h"
+#include "dcn10/dcn10_clk_mgr.h"
#include "dcn30/dcn30_clk_mgr.h"
#include "dml/dcn30/dcn30_fpu.h"
#include "dcn30/dcn30m_clk_mgr.h"
@@ -493,7 +493,7 @@ static void dcn30_notify_link_rate_change(struct clk_mgr *clk_mgr_base, struct d
}
static struct clk_mgr_funcs dcn3_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = dcn3_update_clocks,
.init_clocks = dcn3_init_clocks,
.notify_wm_ranges = dcn3_notify_wm_ranges,
@@ -517,7 +517,7 @@ static void dcn3_init_clocks_fpga(struct clk_mgr *clk_mgr)
}
struct clk_mgr_funcs dcn3_fpga_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = dcn2_update_clocks_fpga,
.init_clocks = dcn3_init_clocks_fpga,
};
@@ -567,7 +567,7 @@ void dcn3_clk_mgr_construct(
clk_mgr->smu_present = false;
- dce_clock_read_ss_info(clk_mgr);
+ dcn_clock_read_ss_info(clk_mgr);
clk_mgr->base.bw_params = kzalloc(sizeof(*clk_mgr->base.bw_params), GFP_KERNEL);
if (!clk_mgr->base.bw_params) {
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
index e40bbc495fc4..24e084448121 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
@@ -26,8 +26,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
@@ -482,7 +482,7 @@ static bool vg_are_clock_states_equal(struct dc_clocks *a,
static struct clk_mgr_funcs vg_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = vg_update_clocks,
.init_clocks = vg_init_clocks,
.enable_pme_wa = vg_enable_pme_wa,
@@ -748,7 +748,7 @@ void vg_clk_mgr_construct(
vg_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
clk_mgr->base.base.dprefclk_khz = 600000;
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
clk_mgr->base.base.bw_params = &vg_bw_params;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
index ff47af3854b6..2c90b5e68dc1 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
@@ -28,8 +28,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
@@ -666,7 +666,7 @@ int dcn31_get_dtb_ref_freq_khz(struct clk_mgr *clk_mgr_base)
}
static struct clk_mgr_funcs dcn31_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn31_update_clocks,
.init_clocks = dcn31_init_clocks,
@@ -744,9 +744,9 @@ void dcn31_clk_mgr_construct(
clk_mgr->base.base.dprefclk_khz = 600000;
clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
/*if bios enabled SS, driver needs to adjust dtb clock, only enable with correct bios*/
- //clk_mgr->base.dccg->ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(clk_mgr_internal, clk_mgr->base.base.dprefclk_khz);
+ //clk_mgr->base.dccg->ref_dtbclk_khz = dcn_adjust_dp_ref_freq_for_ss(clk_mgr_internal, clk_mgr->base.base.dprefclk_khz);
clk_mgr->base.base.bw_params = &dcn31_bw_params;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
index 24f6304011ae..c00f33385ff4 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
@@ -31,8 +31,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
@@ -200,7 +200,7 @@ void dcn314_init_clocks(struct clk_mgr *clk_mgr)
// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
if (dcn314_is_spll_ssc_enabled(clk_mgr))
clk_mgr->dp_dto_source_clock_in_khz =
- dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr->dprefclk_khz);
+ dcn_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr->dprefclk_khz);
else
clk_mgr->dp_dto_source_clock_in_khz = clk_mgr->dprefclk_khz;
}
@@ -766,7 +766,7 @@ static void dcn314_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *cl
}
static struct clk_mgr_funcs dcn314_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn314_update_clocks,
.init_clocks = dcn314_init_clocks,
@@ -861,7 +861,7 @@ void dcn314_clk_mgr_construct(
clk_mgr->base.base.dprefclk_khz = 600000;
clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
dcn314_read_ss_info_from_lut(&clk_mgr->base);
/*if bios enabled SS, driver needs to adjust dtb clock, only enable with correct bios*/
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
index 75d39cb26dba..aa52fed048de 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
@@ -28,8 +28,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
#include "dcn31/dcn31_clk_mgr.h"
@@ -600,7 +600,7 @@ static void dcn315_enable_pme_wa(struct clk_mgr *clk_mgr_base)
}
static struct clk_mgr_funcs dcn315_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn315_update_clocks,
.init_clocks = dcn31_init_clocks,
@@ -675,8 +675,8 @@ void dcn315_clk_mgr_construct(
clk_mgr->base.base.dprefclk_khz = 600000;
clk_mgr->base.base.dprefclk_khz = dcn315_smu_get_dpref_clk(&clk_mgr->base);
clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz;
- dce_clock_read_ss_info(&clk_mgr->base);
- clk_mgr->base.base.clks.ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz);
+ dcn_clock_read_ss_info(&clk_mgr->base);
+ clk_mgr->base.base.clks.ref_dtbclk_khz = dcn_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz);
clk_mgr->base.base.bw_params = &dcn315_bw_params;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
index c7fecbdfda2c..d9f76aa2a8c8 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
@@ -28,8 +28,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
#include "dcn31/dcn31_clk_mgr.h"
@@ -576,7 +576,7 @@ static void dcn316_clk_mgr_helper_populate_bw_params(
static struct clk_mgr_funcs dcn316_funcs = {
.enable_pme_wa = dcn316_enable_pme_wa,
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn316_update_clocks,
.init_clocks = dcn31_init_clocks,
@@ -659,9 +659,9 @@ void dcn316_clk_mgr_construct(
clk_mgr->base.base.dprefclk_khz = 600000;
clk_mgr->base.base.dprefclk_khz = dcn316_smu_get_dpref_clk(&clk_mgr->base);
clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz;
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
/*clk_mgr->base.dccg->ref_dtbclk_khz =
- dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz);*/
+ dcn_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz);*/
clk_mgr->base.base.bw_params = &dcn316_bw_params;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
index be0e3836a6c1..66c26b0f1fd3 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
@@ -27,7 +27,7 @@
#include "clk_mgr_internal.h"
#include "dcn32/dcn32_clk_mgr_smu_msg.h"
#include "dcn20/dcn20_clk_mgr.h"
-#include "dce100/dce_clk_mgr.h"
+#include "dcn10/dcn10_clk_mgr.h"
#include "dcn31/dcn31_clk_mgr.h"
#include "dcn32/dcn32_clk_mgr.h"
#include "reg_helper.h"
@@ -409,7 +409,7 @@ static void dcn32_update_clocks_update_dentist(
}
} else if (new_dispclk_wdivider == 127 && old_dispclk_wdivider != 127) {
/* request clock with 126 divider first */
- uint32_t temp_disp_divider = dentist_get_divider_from_did(126);
+ uint32_t temp_disp_divider = dcn_dentist_get_divider_from_did(126);
uint32_t temp_dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / temp_disp_divider;
if (clk_mgr->smu_present)
@@ -490,7 +490,7 @@ static int dcn32_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
unsigned int disp_divider;
REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
- disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
+ disp_divider = dcn_dentist_get_divider_from_did(dispclk_wdivider);
/* Return DISPCLK freq in Khz */
if (disp_divider)
@@ -922,31 +922,31 @@ static void dcn32_dump_clk_registers(struct clk_state_registers_and_bypass *regs
}
/* Convert DISPCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dispclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dispclk_did);
//Get dispclk in khz
regs_and_bypass->dispclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DISPCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dppclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dppclk_did);
//Get dppclk in khz
regs_and_bypass->dppclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DPREFCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dprefclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dprefclk_did);
//Get dprefclk in khz
regs_and_bypass->dprefclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DCFCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dcfclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dcfclk_did);
//Get dcfclk in khz
regs_and_bypass->dcfclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DTBCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dtbclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dtbclk_did);
//Get dtbclk in khz
regs_and_bypass->dtbclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
@@ -1139,7 +1139,7 @@ static void dcn32_set_min_memclk(struct clk_mgr *clk_mgr_base, unsigned int memc
}
static struct clk_mgr_funcs dcn32_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn32_update_clocks,
.dump_clk_registers = dcn32_dump_clk_registers,
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
index a69824e1eb26..600746d6013c 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
@@ -29,8 +29,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
@@ -758,7 +758,7 @@ void dcn35_init_clocks(struct clk_mgr *clk_mgr)
// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
if (dcn35_is_spll_ssc_enabled(clk_mgr))
clk_mgr->dp_dto_source_clock_in_khz =
- dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr->dprefclk_khz);
+ dcn_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr->dprefclk_khz);
else
clk_mgr->dp_dto_source_clock_in_khz = clk_mgr->dprefclk_khz;
@@ -1346,7 +1346,7 @@ static unsigned int dcn35_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum c
}
static struct clk_mgr_funcs dcn35_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn35_update_clocks,
.init_clocks = dcn35_init_clocks,
@@ -1360,7 +1360,7 @@ static struct clk_mgr_funcs dcn35_funcs = {
};
struct clk_mgr_funcs dcn35_fpga_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = dcn35_update_clocks_fpga,
.init_clocks = dcn35_init_clocks_fpga,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
@@ -1499,7 +1499,7 @@ void dcn35_clk_mgr_construct(
clk_mgr->base.base.dprefclk_khz = dcn35_smu_get_dprefclk(&clk_mgr->base);
clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
/*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/
dcn35_read_ss_info_from_lut(&clk_mgr->base);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
index 42ce5a304125..add0b9ee53db 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
@@ -6,7 +6,7 @@
#include "clk_mgr_internal.h"
#include "dcn401/dcn401_clk_mgr_smu_msg.h"
#include "dcn20/dcn20_clk_mgr.h"
-#include "dce100/dce_clk_mgr.h"
+#include "dcn10/dcn10_clk_mgr.h"
#include "dcn31/dcn31_clk_mgr.h"
#include "dcn32/dcn32_clk_mgr.h"
#include "dcn401/dcn401_clk_mgr.h"
@@ -358,37 +358,37 @@ static void dcn401_dump_clk_registers(struct clk_state_registers_and_bypass *reg
fclk_did = REG_READ(CLK2_CLK2_DFS_CNTL);
/* Convert DISPCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dispclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dispclk_did);
//Get dispclk in khz
regs_and_bypass->dispclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DISPCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dppclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dppclk_did);
//Get dppclk in khz
regs_and_bypass->dppclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DPREFCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dprefclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dprefclk_did);
//Get dprefclk in khz
regs_and_bypass->dprefclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DCFCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dcfclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dcfclk_did);
//Get dcfclk in khz
regs_and_bypass->dcfclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DTBCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(dtbclk_did);
+ target_div = dcn_dentist_get_divider_from_did(dtbclk_did);
//Get dtbclk in khz
regs_and_bypass->dtbclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
/* Convert DTBCLK DFS Slice DID to divider*/
- target_div = dentist_get_divider_from_did(fclk_did);
+ target_div = dcn_dentist_get_divider_from_did(fclk_did);
//Get fclk in khz
regs_and_bypass->fclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
* clk_mgr->base.dentist_vco_freq_khz) / target_div;
@@ -1552,7 +1552,7 @@ static int dcn401_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
unsigned int disp_divider;
REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
- disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
+ disp_divider = dcn_dentist_get_divider_from_did(dispclk_wdivider);
/* Return DISPCLK freq in Khz */
if (disp_divider)
@@ -1599,7 +1599,7 @@ static void dcn401_execute_clk_mgr_block_sequence_bls(struct clk_mgr *clk_mgr_ba
}
static struct clk_mgr_funcs dcn401_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn401_get_dtb_ref_freq_khz,
.update_clocks = dcn401_update_clocks,
.dump_clk_registers = dcn401_dump_clk_registers,
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
index c7b9bad93a93..1cac2c9d4e60 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
@@ -7,8 +7,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
@@ -624,7 +624,7 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
if (dcn42_is_spll_ssc_enabled(clk_mgr_base))
clk_mgr_base->dp_dto_source_clock_in_khz =
- dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz);
+ dcn_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz);
else
clk_mgr_base->dp_dto_source_clock_in_khz = clk_mgr_base->dprefclk_khz;
@@ -911,7 +911,7 @@ int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base)
unsigned int disp_divider;
REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider);
- disp_divider = dentist_get_divider_from_did(dispclk_wdivider);
+ disp_divider = dcn_dentist_get_divider_from_did(dispclk_wdivider);
/* Return DISPCLK freq in Khz */
if (disp_divider)
@@ -1053,7 +1053,7 @@ void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
}
static struct clk_mgr_funcs dcn42_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn42_update_clocks,
.init_clocks = dcn42_init_clocks,
@@ -1069,7 +1069,7 @@ static struct clk_mgr_funcs dcn42_funcs = {
};
struct clk_mgr_funcs dcn42_fpga_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.update_clocks = dcn42_update_clocks_fpga,
.init_clocks = dcn42_init_clocks_fpga,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
@@ -1131,7 +1131,7 @@ void dcn42_clk_mgr_construct(
/* Saved clocks configured at boot for debug purposes */
dcn42_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr);
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
/*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/
dcn42_read_ss_info_from_lut(&clk_mgr->base);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c
index 4be5abdc60ea..f2bc8b3bd9ad 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42b/dcn42b_clk_mgr.c
@@ -9,8 +9,8 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-// For dce12_get_dp_ref_freq_khz
-#include "dce100/dce_clk_mgr.h"
+// For dcn_get_dp_ref_freq_khz
+#include "dcn10/dcn10_clk_mgr.h"
// For dcn20_update_clocks_update_dpp_dto
#include "dcn20/dcn20_clk_mgr.h"
@@ -238,7 +238,7 @@ void dcn42b_init_clocks(struct clk_mgr *clk_mgr_base)
// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
if (dcn42_is_spll_ssc_enabled(clk_mgr_base))
clk_mgr_base->dp_dto_source_clock_in_khz =
- dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz);
+ dcn_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz);
else
clk_mgr_base->dp_dto_source_clock_in_khz = clk_mgr_base->dprefclk_khz;
@@ -398,7 +398,7 @@ uint32_t dcn42b_get_clock_freq_from_clkip(struct clk_mgr *clk_mgr_base, enum clo
*/
static struct clk_mgr_funcs dcn42b_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dp_ref_clk_frequency = dcn_get_dp_ref_freq_khz,
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn42_update_clocks,
.init_clocks = dcn42b_init_clocks,
@@ -467,7 +467,7 @@ void dcn42b_clk_mgr_construct(
/* Saved clocks configured at boot for debug purposes */
dcn42b_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr);
- dce_clock_read_ss_info(&clk_mgr->base);
+ dcn_clock_read_ss_info(&clk_mgr->base);
/*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/
dcn42b_read_ss_info_from_lut(&clk_mgr->base);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index b970f152d67f..0447137159bf 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -55,11 +55,13 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
#endif
+#if !defined(TRIM_DCE)
#include "dce80/dce80_resource.h"
#include "dce100/dce100_resource.h"
#include "dce110/dce110_resource.h"
#include "dce112/dce112_resource.h"
#include "dce120/dce120_resource.h"
+#endif
#include "dcn10/dcn10_resource.h"
#include "dcn20/dcn20_resource.h"
#include "dcn21/dcn21_resource.h"
@@ -289,6 +291,7 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
init_data->num_virtual_links, dc);
break;
#endif
+#if !defined(TRIM_DCE)
case DCE_VERSION_8_0:
res_pool = dce80_create_resource_pool(
(uint8_t)init_data->num_virtual_links, dc);
@@ -320,6 +323,7 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
res_pool = dce120_create_resource_pool(
(uint8_t)init_data->num_virtual_links, dc);
break;
+#endif
#if defined(CONFIG_DRM_AMD_DC_FP)
case DCN_VERSION_1_0:
@@ -5254,6 +5258,80 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
patch_gamut_packet_checksum(&info->gamut);
}
+/*
+ * In the trimmed build the dce112 resource dir (which owns these) is excluded,
+ * so provide the definitions here. The non-trimmed build uses the originals in
+ * dce112/dce112_resource.c instead.
+ */
+#if defined(TRIM_DCE)
+/*
+ * find_matching_pll - return the PLL clock source dedicated to a stream's
+ * transmitter. clock_sources[] are ordered PLL0..PLL5 across all pools, so
+ * index by transmitter position (UNIPHY_A -> 0 ... UNIPHY_F -> 5).
+ */
+static struct clock_source *find_matching_pll(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ const struct dc_stream_state *const stream)
+{
+ (void)res_ctx;
+ switch (stream->link->link_enc->transmitter) {
+ case TRANSMITTER_UNIPHY_A:
+ return pool->clock_sources[0];
+ case TRANSMITTER_UNIPHY_B:
+ return pool->clock_sources[1];
+ case TRANSMITTER_UNIPHY_C:
+ return pool->clock_sources[2];
+ case TRANSMITTER_UNIPHY_D:
+ return pool->clock_sources[3];
+ case TRANSMITTER_UNIPHY_E:
+ return pool->clock_sources[4];
+ case TRANSMITTER_UNIPHY_F:
+ return pool->clock_sources[5];
+ default:
+ return NULL;
+ }
+}
+
+enum dc_status resource_map_phy_clock_resources(
+ const struct dc *dc,
+ struct dc_state *context,
+ struct dc_stream_state *stream)
+{
+
+ /* acquire new resources */
+ struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
+ &context->res_ctx, stream);
+
+ if (!pipe_ctx)
+ return DC_ERROR_UNEXPECTED;
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal)
+ || dc_is_virtual_signal(pipe_ctx->stream->signal))
+ pipe_ctx->clock_source =
+ dc->res_pool->dp_clock_source;
+ else if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL)
+ pipe_ctx->clock_source =
+ dc->res_pool->dp_clock_source;
+ else {
+ if (stream && stream->link && stream->link->link_enc)
+ pipe_ctx->clock_source = find_matching_pll(
+ &context->res_ctx, dc->res_pool,
+ stream);
+ }
+
+ if (pipe_ctx->clock_source == NULL)
+ return DC_NO_CLOCK_SOURCE_RESOURCE;
+
+ resource_reference_clock_source(
+ &context->res_ctx,
+ dc->res_pool,
+ pipe_ctx->clock_source);
+
+ return DC_OK;
+}
+#endif /* TRIM_DCE */
+
enum dc_status resource_map_clock_resources(
const struct dc *dc,
struct dc_state *context,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
index feb6ca92802c..4298e6d34aa5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
@@ -28,7 +28,7 @@
#include "resource.h"
#include "custom_float.h"
#include "dcn10/dcn10_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dce/dce_hwseq.h"
#include "abm.h"
#include "dmcu.h"
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
index a907f7d0628b..a6c67490dc10 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
@@ -43,9 +43,11 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/hw_factory_dce60.h"
#endif
+#if !defined(TRIM_DCE)
#include "dce80/hw_factory_dce80.h"
#include "dce110/hw_factory_dce110.h"
#include "dce120/hw_factory_dce120.h"
+#endif
#include "dcn10/hw_factory_dcn10.h"
#include "dcn20/hw_factory_dcn20.h"
#include "dcn21/hw_factory_dcn21.h"
@@ -70,6 +72,7 @@ bool dal_hw_factory_init(
dal_hw_factory_dce60_init(factory);
return true;
#endif
+#if !defined(TRIM_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@@ -88,6 +91,7 @@ bool dal_hw_factory_init(
case DCE_VERSION_12_1:
dal_hw_factory_dce120_init(factory);
return true;
+#endif
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
dal_hw_factory_dcn10_init(factory);
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
index b58af86dee10..debf58e3a3d2 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
@@ -43,9 +43,11 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/hw_translate_dce60.h"
#endif
+#if !defined(TRIM_DCE)
#include "dce80/hw_translate_dce80.h"
#include "dce110/hw_translate_dce110.h"
#include "dce120/hw_translate_dce120.h"
+#endif
#include "dcn10/hw_translate_dcn10.h"
#include "dcn20/hw_translate_dcn20.h"
#include "dcn21/hw_translate_dcn21.h"
@@ -74,6 +76,7 @@ bool dal_hw_translate_init(
dal_hw_translate_dce60_init(translate);
return true;
#endif
+#if !defined(TRIM_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@@ -89,6 +92,7 @@ bool dal_hw_translate_init(
case DCE_VERSION_12_1:
dal_hw_translate_dce120_init(translate);
return true;
+#endif
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
dal_hw_translate_dcn10_init(translate);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h
index 9c032e449481..390fd7b92234 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h
@@ -87,6 +87,9 @@ void dce110_edp_wait_for_hpd_ready(
struct dc_link *link,
bool power_up);
+void dce110_edp_wait_for_T12(
+ struct dc_link *link);
+
bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx,
struct set_backlight_level_params *params);
void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 3be0bde5aea1..234f786d49c0 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -58,6 +58,23 @@
#include "dce/dmub_outbox.h"
#include "link_service.h"
#include "dc_state_priv.h"
+/* Headers required by the sequencer functions folded in from dce110_hwseq.c */
+#include "dc.h"
+#include "dc_bios_types.h"
+#include "core_status.h"
+#include "dm_helpers.h"
+#include "gpio_service_interface.h"
+#include "bios/bios_parser_helper.h"
+#include "mem_input.h"
+#include "transform.h"
+#include "stream_encoder.h"
+#include "link_encoder.h"
+#include "link_enc_cfg.h"
+#include "clock_source.h"
+#include "audio.h"
+#include "panel_cntl.h"
+#include "dc_dp_types.h"
+#include "atomfirmware.h"
#define DC_LOGGER \
dc_ctx->logger
@@ -82,6 +99,48 @@
#define PGFSM_POWER_ON 0
#define PGFSM_POWER_OFF 2
+/* Timeouts/delays moved from dce110_hwseq.c with the folded functions */
+#define PANEL_POWER_UP_TIMEOUT 300
+#define PANEL_POWER_DOWN_TIMEOUT 500
+#define HPD_CHECK_INTERVAL 10
+#define OLED_POST_T7_DELAY 100
+#define OLED_PRE_T11_DELAY 150
+
+/* Forward declarations for file-local helpers moved from dce110_hwseq.c */
+static void enable_display_pipe_clock_gating(
+ struct dc_context *ctx,
+ bool clock_gating);
+static enum bp_result link_transmitter_control(
+ struct dc_bios *bios,
+ struct bp_transmitter_control *cntl);
+static void power_down_encoders(struct dc *dc);
+static void power_down_controllers(struct dc *dc);
+static void power_down_clock_sources(struct dc *dc);
+static void power_down_all_hw_blocks(struct dc *dc);
+static void disable_vga_and_power_gate_all_controllers(
+ struct dc *dc);
+static void get_edp_streams(struct dc_state *context,
+ struct dc_stream_state **edp_streams,
+ int *edp_stream_num);
+static void get_edp_links_with_sink(
+ struct dc *dc,
+ struct dc_link **edp_links_with_sink,
+ int *edp_with_sink_num);
+static void clean_up_dsc_blocks(struct dc *dc);
+static void dc_hwss_enable_otg_pwa(
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx);
+static bool should_enable_fbc(struct dc *dc,
+ struct dc_state *context,
+ uint32_t *pipe_idx);
+static void
+dcn10_external_encoder_control(enum bp_external_encoder_control_action action,
+ struct dc_link *link,
+ struct dc_crtc_timing *timing);
+static void dcn10_setup_audio_dto(
+ struct dc *dc,
+ struct dc_state *context);
+
static void print_microsec(struct dc_context *dc_ctx,
struct dc_log_buffer_ctx *log_ctx,
uint32_t ref_cycle)
@@ -4211,3 +4270,1902 @@ void dcn10_reset_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx,
&plane_state->address,
true);
}
+
+/*======================================================================================
+ * The following functions were folded into dcn10_hwseq.c and renamed to dcn10_;
+ * four generic helpers were given a dcn10_ prefix to avoid link collisions with
+ * dce110_hwseq.c on Linux builds.
+ *====================================================================================*/
+static void enable_display_pipe_clock_gating(
+ struct dc_context *ctx,
+ bool clock_gating)
+{
+ (void)ctx;
+ (void)clock_gating;
+ /*TODO*/
+}
+
+void dcn10_update_info_frame(struct pipe_ctx *pipe_ctx)
+{
+ bool is_hdmi_tmds;
+ bool is_dp;
+
+ ASSERT(pipe_ctx->stream);
+
+ if (pipe_ctx->stream_res.stream_enc == NULL)
+ return; /* this is not root pipe */
+
+ is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
+ is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
+
+ if (!is_hdmi_tmds && !is_dp)
+ return;
+
+ if (is_hdmi_tmds)
+ pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
+ pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+ else {
+ if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+ pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+ pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+
+ pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
+ pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+ }
+}
+
+static void
+dcn10_external_encoder_control(enum bp_external_encoder_control_action action,
+ struct dc_link *link,
+ struct dc_crtc_timing *timing)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dc_bios *bios = link->ctx->dc_bios;
+ const struct dc_link_settings *link_settings = &link->cur_link_settings;
+ enum bp_result bp_result = BP_RESULT_OK;
+ struct bp_external_encoder_control ext_cntl = {
+ .action = action,
+ .connector_obj_id = link->link_enc->connector,
+ .encoder_id = link->ext_enc_id,
+ .lanes_number = link_settings->lane_count,
+ .link_rate = link_settings->link_rate,
+
+ /* Use signal type of the real link encoder, ie. DP */
+ .signal = link->connector_signal,
+
+ /* We don't know the timing yet when executing the SETUP action,
+ * so use a reasonably high default value. It seems that ENABLE
+ * can change the actual pixel clock but doesn't work with higher
+ * pixel clocks than what SETUP was called with.
+ */
+ .pixel_clock = timing ? timing->pix_clk_100hz / 10 : 300000,
+ .color_depth = timing ? timing->display_color_depth : COLOR_DEPTH_888,
+ };
+ DC_LOGGER_INIT(dc->ctx);
+
+ bp_result = bios->funcs->external_encoder_control(bios, &ext_cntl);
+
+ if (bp_result != BP_RESULT_OK)
+ DC_LOG_ERROR("Failed to execute external encoder action: 0x%x\n", action);
+}
+
+void dcn10_enable_stream(struct pipe_ctx *pipe_ctx)
+{
+ enum dc_lane_count lane_count =
+ pipe_ctx->stream->link->cur_link_settings.lane_count;
+ struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
+ struct dc_link *link = pipe_ctx->stream->link;
+ const struct dc *dc = link->dc;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ uint32_t active_total_with_borders;
+ uint32_t early_control = 0;
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
+
+ link_hwss->setup_stream_encoder(pipe_ctx);
+
+ dc->hwss.update_info_frame(pipe_ctx);
+
+ /* enable early control to avoid corruption on DP monitor*/
+ active_total_with_borders =
+ timing->h_addressable
+ + timing->h_border_left
+ + timing->h_border_right;
+
+ if (lane_count != 0)
+ early_control = active_total_with_borders % lane_count;
+
+ if (early_control == 0)
+ early_control = lane_count;
+
+ tg->funcs->set_early_control(tg, early_control);
+
+ if (link->ext_enc_id.id)
+ dcn10_external_encoder_control(EXTERNAL_ENCODER_CONTROL_ENABLE, link, timing);
+}
+
+static enum bp_result link_transmitter_control(
+ struct dc_bios *bios,
+ struct bp_transmitter_control *cntl)
+{
+ enum bp_result result;
+
+ result = bios->funcs->transmitter_control(bios, cntl);
+
+ return result;
+}
+
+void dcn10_edp_wait_for_hpd_ready(
+ struct dc_link *link,
+ bool power_up)
+{
+ struct graphics_object_id connector = link->link_enc->connector;
+ bool edp_hpd_high = false;
+ uint32_t time_elapsed = 0;
+ uint32_t timeout = power_up ?
+ PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
+
+ DC_LOGGER_INIT(link->ctx);
+
+ if (dal_graphics_object_id_get_connector_id(connector)
+ != CONNECTOR_ID_EDP) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ if (!power_up)
+ /*
+ * From KV, we will not HPD low after turning off VCC -
+ * instead, we will check the SW timer in power_up().
+ */
+ return;
+
+ /*
+ * When we power on/off the eDP panel,
+ * we need to wait until SENSE bit is high/low.
+ */
+
+ if (link->panel_config.pps.extra_t3_ms > 0) {
+ int extra_t3_in_ms = link->panel_config.pps.extra_t3_ms;
+
+ msleep(extra_t3_in_ms);
+ }
+
+ /* wait until timeout or panel detected */
+
+ do {
+ if (!(link->dc->link_srv->get_hpd_state(link) ^ power_up)) {
+ edp_hpd_high = true;
+ break;
+ }
+
+ msleep(HPD_CHECK_INTERVAL);
+
+ time_elapsed += HPD_CHECK_INTERVAL;
+ } while (time_elapsed < timeout);
+
+ /* ensure that the panel is detected */
+ if (!edp_hpd_high)
+ DC_LOG_DC("%s: wait timed out!\n", __func__);
+}
+
+void dcn10_edp_power_control(
+ struct dc_link *link,
+ bool power_up)
+{
+ struct dc_context *ctx = link->ctx;
+ struct bp_transmitter_control cntl = { 0 };
+ enum bp_result bp_result;
+ uint8_t pwrseq_instance;
+
+ DC_LOGGER_INIT(ctx);
+
+ if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
+ != CONNECTOR_ID_EDP) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ if (!link->panel_cntl)
+ return;
+ if (power_up !=
+ link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl)) {
+
+ unsigned long long current_ts = dm_get_timestamp(ctx);
+ unsigned long long time_since_edp_poweroff_ms =
+ div64_u64(dm_get_elapse_time_in_ns(
+ ctx,
+ current_ts,
+ ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
+ unsigned long long time_since_edp_poweron_ms =
+ div64_u64(dm_get_elapse_time_in_ns(
+ ctx,
+ current_ts,
+ ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link)), 1000000);
+ DC_LOG_HW_RESUME_S3(
+ "%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu",
+ __func__,
+ power_up,
+ current_ts,
+ ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link),
+ ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link),
+ time_since_edp_poweroff_ms,
+ time_since_edp_poweron_ms);
+
+ /* Send VBIOS command to prompt eDP panel power */
+ if (power_up) {
+ /* edp requires a min of 500ms from LCDVDD off to on */
+ unsigned long long remaining_min_edp_poweroff_time_ms = 500;
+
+ /* add time defined by a patch, if any (usually patch extra_t12_ms is 0) */
+ if (link->local_sink != NULL)
+ remaining_min_edp_poweroff_time_ms +=
+ link->panel_config.pps.extra_t12_ms;
+
+ /* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */
+ if (ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) {
+ if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms)
+ remaining_min_edp_poweroff_time_ms =
+ remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms;
+ else
+ remaining_min_edp_poweroff_time_ms = 0;
+ }
+
+ if (remaining_min_edp_poweroff_time_ms) {
+ DC_LOG_HW_RESUME_S3(
+ "%s: remaining_min_edp_poweroff_time_ms=%llu: begin wait.\n",
+ __func__, remaining_min_edp_poweroff_time_ms);
+ msleep((unsigned int)remaining_min_edp_poweroff_time_ms);
+ DC_LOG_HW_RESUME_S3(
+ "%s: remaining_min_edp_poweroff_time_ms=%llu: end wait.\n",
+ __func__, remaining_min_edp_poweroff_time_ms);
+ dm_output_to_console("%s: wait %lld ms to power on eDP.\n",
+ __func__, remaining_min_edp_poweroff_time_ms);
+ } else {
+ DC_LOG_HW_RESUME_S3(
+ "%s: remaining_min_edp_poweroff_time_ms=%llu: no wait required.\n",
+ __func__, remaining_min_edp_poweroff_time_ms);
+ }
+ }
+
+ DC_LOG_HW_RESUME_S3(
+ "%s: BEGIN: Panel Power action: %s\n",
+ __func__, (power_up ? "On":"Off"));
+
+ cntl.action = power_up ?
+ TRANSMITTER_CONTROL_POWER_ON :
+ TRANSMITTER_CONTROL_POWER_OFF;
+ cntl.transmitter = link->link_enc->transmitter;
+ cntl.connector_obj_id = link->link_enc->connector;
+ cntl.coherent = false;
+ cntl.lanes_number = LANE_COUNT_FOUR;
+ cntl.hpd_sel = link->link_enc->hpd_source;
+ pwrseq_instance = (uint8_t)link->panel_cntl->pwrseq_inst;
+
+ if (ctx->dc->ctx->dmub_srv &&
+ ctx->dc->debug.dmub_command_table) {
+
+ if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) {
+ bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+ LVTMA_CONTROL_POWER_ON,
+ pwrseq_instance, link->link_powered_externally);
+ } else {
+ bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+ LVTMA_CONTROL_POWER_OFF,
+ pwrseq_instance, link->link_powered_externally);
+ }
+ }
+
+ bp_result = link_transmitter_control(ctx->dc_bios, &cntl);
+
+ DC_LOG_HW_RESUME_S3(
+ "%s: END: Panel Power action: %s bp_result=%u\n",
+ __func__, (power_up ? "On":"Off"),
+ bp_result);
+
+ ctx->dc->link_srv->dp_trace_set_edp_power_timestamp(link, power_up);
+
+ DC_LOG_HW_RESUME_S3(
+ "%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n",
+ __func__,
+ ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link),
+ ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link));
+
+ if (bp_result != BP_RESULT_OK)
+ DC_LOG_ERROR(
+ "%s: Panel Power bp_result: %d\n",
+ __func__, bp_result);
+ } else {
+ DC_LOG_HW_RESUME_S3(
+ "%s: Skipping Panel Power action: %s\n",
+ __func__, (power_up ? "On":"Off"));
+ }
+}
+
+void dcn10_edp_wait_for_T12(
+ struct dc_link *link)
+{
+ struct dc_context *ctx = link->ctx;
+
+ if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
+ != CONNECTOR_ID_EDP) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ if (!link->panel_cntl)
+ return;
+
+ if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) &&
+ ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) {
+ unsigned int t12_duration = 500; // Default T12 as per spec
+ unsigned long long current_ts = dm_get_timestamp(ctx);
+ unsigned long long time_since_edp_poweroff_ms =
+ div64_u64(dm_get_elapse_time_in_ns(
+ ctx,
+ current_ts,
+ ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
+
+ t12_duration += link->panel_config.pps.extra_t12_ms; // Add extra T12
+
+ if (time_since_edp_poweroff_ms < t12_duration)
+ msleep((unsigned int)(t12_duration - time_since_edp_poweroff_ms));
+ }
+}
+
+void dcn10_edp_backlight_control(
+ struct dc_link *link,
+ bool enable)
+{
+ struct dc_context *ctx = link->ctx;
+ struct bp_transmitter_control cntl = { 0 };
+ uint8_t pwrseq_instance = 0;
+ unsigned int pre_T11_delay = (link->dpcd_sink_ext_caps.bits.oled ? OLED_PRE_T11_DELAY : 0);
+ unsigned int post_T7_delay = (link->dpcd_sink_ext_caps.bits.oled ? OLED_POST_T7_DELAY : 0);
+
+ DC_LOGGER_INIT(ctx);
+
+ if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
+ != CONNECTOR_ID_EDP) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ if (link->panel_cntl && !(link->dpcd_sink_ext_caps.bits.oled ||
+ link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
+ link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)) {
+ bool is_backlight_on = link->panel_cntl->funcs->is_panel_backlight_on(link->panel_cntl);
+
+ if ((enable && is_backlight_on) || (!enable && !is_backlight_on)) {
+ DC_LOG_HW_RESUME_S3(
+ "%s: panel already powered up/off. Do nothing.\n",
+ __func__);
+ return;
+ }
+ }
+
+ /* Send VBIOS command to control eDP panel backlight */
+
+ DC_LOG_HW_RESUME_S3(
+ "%s: backlight action: %s\n",
+ __func__, (enable ? "On":"Off"));
+
+ cntl.action = enable ?
+ TRANSMITTER_CONTROL_BACKLIGHT_ON :
+ TRANSMITTER_CONTROL_BACKLIGHT_OFF;
+
+ /*cntl.engine_id = ctx->engine;*/
+ cntl.transmitter = link->link_enc->transmitter;
+ cntl.connector_obj_id = link->link_enc->connector;
+ /*todo: unhardcode*/
+ cntl.lanes_number = LANE_COUNT_FOUR;
+ cntl.hpd_sel = link->link_enc->hpd_source;
+ cntl.signal = SIGNAL_TYPE_EDP;
+
+ /* For eDP, the following delays might need to be considered
+ * after link training completed:
+ * idle period - min. accounts for required BS-Idle pattern,
+ * max. allows for source frame synchronization);
+ * 50 msec max. delay from valid video data from source
+ * to video on dislpay or backlight enable.
+ *
+ * Disable the delay for now.
+ * Enable it in the future if necessary.
+ */
+ /* dc_service_sleep_in_milliseconds(50); */
+ /*edp 1.2*/
+ if (link->panel_cntl) {
+ pwrseq_instance = (uint8_t)link->panel_cntl->pwrseq_inst;
+ }
+
+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) {
+ if (!link->dc->config.edp_no_power_sequencing)
+ /*
+ * Sometimes, DP receiver chip power-controlled externally by an
+ * Embedded Controller could be treated and used as eDP,
+ * if it drives mobile display. In this case,
+ * we shouldn't be doing power-sequencing, hence we can skip
+ * waiting for T7-ready.
+ */
+ ctx->dc->link_srv->edp_receiver_ready_T7(link);
+ else
+ DC_LOG_DC("edp_receiver_ready_T7 skipped\n");
+ }
+
+ /* Setting link_powered_externally will bypass delays in the backlight
+ * as they are not required if the link is being powered by a different
+ * source.
+ */
+ if (ctx->dc->ctx->dmub_srv &&
+ ctx->dc->debug.dmub_command_table) {
+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
+ ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+ LVTMA_CONTROL_LCD_BLON,
+ pwrseq_instance, link->link_powered_externally);
+ else
+ ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+ LVTMA_CONTROL_LCD_BLOFF,
+ pwrseq_instance, link->link_powered_externally);
+ }
+
+ link_transmitter_control(ctx->dc_bios, &cntl);
+
+ if (enable && link->dpcd_sink_ext_caps.bits.oled &&
+ !link->dc->config.edp_no_power_sequencing &&
+ !link->local_sink->edid_caps.panel_patch.oled_optimize_display_on) {
+ post_T7_delay += link->panel_config.pps.extra_post_t7_ms;
+ msleep(post_T7_delay);
+ }
+
+ if (link->dpcd_sink_ext_caps.bits.oled ||
+ link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
+ link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)
+ ctx->dc->link_srv->edp_backlight_enable_aux(link, enable);
+
+ /*edp 1.2*/
+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) {
+ if (!link->dc->config.edp_no_power_sequencing)
+ /*
+ * Sometimes, DP receiver chip power-controlled externally by an
+ * Embedded Controller could be treated and used as eDP,
+ * if it drives mobile display. In this case,
+ * we shouldn't be doing power-sequencing, hence we can skip
+ * waiting for T9-ready.
+ */
+ ctx->dc->link_srv->edp_add_delay_for_T9(link);
+ else
+ DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
+ }
+
+ if (!enable) {
+ /*follow oem panel config's requirement*/
+ pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms;
+ if (pre_T11_delay)
+ msleep(pre_T11_delay);
+ }
+}
+
+void dcn10_enable_audio_stream(struct pipe_ctx *pipe_ctx)
+{
+ /* notify audio driver for audio modes of monitor */
+ struct dc *dc;
+ struct clk_mgr *clk_mgr;
+ unsigned int i, num_audio = 1;
+ const struct link_hwss *link_hwss;
+
+ if (!pipe_ctx->stream)
+ return;
+
+ if (dc_is_rgb_signal(pipe_ctx->stream->signal))
+ return;
+
+ dc = pipe_ctx->stream->ctx->dc;
+ clk_mgr = dc->clk_mgr;
+ link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res);
+
+ if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true)
+ return;
+
+ if (pipe_ctx->stream_res.audio) {
+ for (i = 0; i < MAX_PIPES; i++) {
+ /*current_state not updated yet*/
+ if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL)
+ num_audio++;
+ }
+ if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) {
+ /*wake AZ from D3 first before access az endpoint*/
+ clk_mgr->funcs->enable_pme_wa(clk_mgr);
+ }
+
+ pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio);
+
+ link_hwss->enable_audio_packet(pipe_ctx);
+
+ if (pipe_ctx->stream_res.audio)
+ pipe_ctx->stream_res.audio->enabled = true;
+ }
+}
+
+void dcn10_disable_audio_stream(struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc;
+ struct clk_mgr *clk_mgr;
+ const struct link_hwss *link_hwss;
+
+ if (!pipe_ctx || !pipe_ctx->stream)
+ return;
+
+ if (dc_is_rgb_signal(pipe_ctx->stream->signal))
+ return;
+
+ dc = pipe_ctx->stream->ctx->dc;
+ clk_mgr = dc->clk_mgr;
+ link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res);
+
+ if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false)
+ return;
+
+ link_hwss->disable_audio_packet(pipe_ctx);
+
+ if (pipe_ctx->stream_res.audio) {
+ pipe_ctx->stream_res.audio->enabled = false;
+
+ if (clk_mgr->funcs->enable_pme_wa)
+ /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
+ clk_mgr->funcs->enable_pme_wa(clk_mgr);
+
+ /* TODO: notify audio driver for if audio modes list changed
+ * add audio mode list change flag */
+ /* dal_audio_disable_azalia_audio_jack_presence(stream->audio,
+ * stream->stream_engine_id);
+ */
+ }
+}
+
+void dcn10_disable_stream(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ struct dccg *dccg = dc->res_pool->dccg;
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
+ struct dtbclk_dto_params dto_params = {0};
+ int dp_hpo_inst;
+ struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
+ struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+
+ if (!dc->config.unify_link_enc_assignment)
+ link_enc = link_enc_cfg_get_link_enc(link);
+
+ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) {
+ pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets(
+ pipe_ctx->stream_res.stream_enc);
+ pipe_ctx->stream_res.stream_enc->funcs->hdmi_reset_stream_attribute(
+ pipe_ctx->stream_res.stream_enc);
+ }
+
+ if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->stop_hdmi_info_packets(
+ pipe_ctx->stream_res.hpo_frl_stream_enc);
+ if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets(
+ pipe_ctx->stream_res.stream_enc);
+
+ dc->hwss.disable_audio_stream(pipe_ctx);
+
+ link_hwss->reset_stream_encoder(pipe_ctx);
+
+ if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) && dccg) {
+ dto_params.otg_inst = tg->inst;
+ dto_params.timing = &pipe_ctx->stream->timing;
+ dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
+ if (dccg) {
+ dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
+ dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst);
+ if (!(dc->ctx->dce_version >= DCN_VERSION_3_5)) {
+ if (dccg && dccg->funcs->set_dtbclk_dto)
+ dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+ }
+ }
+ } else if (dccg && dccg->funcs->disable_symclk_se) {
+ if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_FRL)
+ dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst,
+ link_enc->transmitter - TRANSMITTER_UNIPHY_A);
+ }
+
+ if (link->ext_enc_id.id)
+ dcn10_external_encoder_control(EXTERNAL_ENCODER_CONTROL_DISABLE, link, NULL);
+}
+
+void dcn10_blank_stream(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct dce_hwseq *hws = link->dc->hwseq;
+
+ if (hws && hws->wa_state.skip_blank_stream)
+ return;
+
+ if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
+ if (!link->skip_implict_edp_power_control && hws)
+ hws->funcs.edp_backlight_control(link, false);
+ link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
+ }
+
+ if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+ /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
+
+ if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) {
+ /*
+ * After output is idle pattern some sinks need time to recognize the stream
+ * has changed or they enter protection state and hang.
+ */
+ msleep(60);
+ }
+ }
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+ !link->dc->config.edp_no_power_sequencing) {
+ /*
+ * Sometimes, DP receiver chip power-controlled externally by an
+ * Embedded Controller could be treated and used as eDP,
+ * if it drives mobile display. In this case,
+ * we shouldn't be doing power-sequencing, hence we can skip
+ * waiting for T9-ready.
+ */
+ link->dc->link_srv->edp_receiver_ready_T9(link);
+ }
+
+ if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)) {
+ pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_blank(pipe_ctx->stream_res.hpo_frl_stream_enc);
+
+ /* Set HDMISTREAMCLK source to REFCLK */
+ if (link->dc->res_pool->dccg &&
+ link->dc->res_pool->dccg->funcs->set_hdmistreamclk) {
+ link->dc->res_pool->dccg->funcs->set_hdmistreamclk(
+ link->dc->res_pool->dccg,
+ REFCLK,
+ pipe_ctx->stream_res.tg->inst);
+ }
+ }
+}
+
+void dcn10_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ if (pipe_ctx != NULL && pipe_ctx->stream_res.stream_enc != NULL)
+ pipe_ctx->stream_res.stream_enc->funcs->set_avmute(pipe_ctx->stream_res.stream_enc, enable);
+}
+
+enum audio_dto_source dcn10_translate_to_dto_source(enum controller_id crtc_id)
+{
+ switch (crtc_id) {
+ case CONTROLLER_ID_D0:
+ return DTO_SOURCE_ID0;
+ case CONTROLLER_ID_D1:
+ return DTO_SOURCE_ID1;
+ case CONTROLLER_ID_D2:
+ return DTO_SOURCE_ID2;
+ case CONTROLLER_ID_D3:
+ return DTO_SOURCE_ID3;
+ case CONTROLLER_ID_D4:
+ return DTO_SOURCE_ID4;
+ case CONTROLLER_ID_D5:
+ return DTO_SOURCE_ID5;
+ default:
+ return DTO_SOURCE_UNKNOWN;
+ }
+}
+
+void dcn10_populate_audio_dp_link_info(
+ const struct pipe_ctx *pipe_ctx,
+ struct audio_dp_link_info *dp_link_info)
+{
+ const struct dc_stream_state *stream = pipe_ctx->stream;
+ const struct dc_link *link = stream->link;
+ struct fixed31_32 link_bw_kbps;
+
+ dp_link_info->encoding = link->dc->link_srv->dp_get_encoding_format(
+ &pipe_ctx->link_config.dp_link_settings);
+ dp_link_info->is_mst = (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST);
+ dp_link_info->lane_count = pipe_ctx->link_config.dp_link_settings.lane_count;
+ dp_link_info->link_rate = pipe_ctx->link_config.dp_link_settings.link_rate;
+
+ link_bw_kbps = dc_fixpt_from_int(dc_link_bandwidth_kbps(link,
+ &pipe_ctx->link_config.dp_link_settings));
+
+ /* For audio stream calculations, the video stream should not include FEC or SSC
+ * in order to get the most pessimistic values.
+ */
+ if (dp_link_info->encoding == DP_8b_10b_ENCODING &&
+ link->dc->link_srv->dp_is_fec_supported(link)) {
+ link_bw_kbps = dc_fixpt_mul(link_bw_kbps,
+ dc_fixpt_from_fraction(100, DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100));
+ } else if (dp_link_info->encoding == DP_128b_132b_ENCODING) {
+ link_bw_kbps = dc_fixpt_mul(link_bw_kbps,
+ dc_fixpt_from_fraction(10000, 9975)); /* 99.75% SSC overhead*/
+ }
+
+ dp_link_info->link_bandwidth_kbps = dc_fixpt_floor(link_bw_kbps);
+
+ /* Calculates hblank_min_symbol_width for 128b/132b
+ * Corresponding HBLANK_MIN_SYMBOL_WIDTH register is calculated as:
+ * floor(h_blank * bits_per_pixel / 128)
+ */
+ if (dp_link_info->encoding == DP_128b_132b_ENCODING) {
+ struct dc_crtc_timing *crtc_timing = &pipe_ctx->stream->timing;
+
+ uint32_t h_active = crtc_timing->h_addressable + crtc_timing->h_border_left
+ + crtc_timing->h_border_right;
+ uint32_t h_blank = crtc_timing->h_total - h_active;
+
+ uint32_t bpp;
+
+ if (crtc_timing->flags.DSC) {
+ bpp = crtc_timing->dsc_cfg.bits_per_pixel;
+ } else {
+ /* When the timing is using DSC, dsc_cfg.bits_per_pixel is in 16th bits.
+ * The bpp in this path is scaled to 16th bits so the final calculation
+ * is correct for both cases.
+ */
+ bpp = 16;
+ switch (crtc_timing->display_color_depth) {
+ case COLOR_DEPTH_666:
+ bpp *= 18;
+ break;
+ case COLOR_DEPTH_888:
+ bpp *= 24;
+ break;
+ case COLOR_DEPTH_101010:
+ bpp *= 30;
+ break;
+ case COLOR_DEPTH_121212:
+ bpp *= 36;
+ break;
+ default:
+ bpp = 0;
+ break;
+ }
+
+ switch (crtc_timing->pixel_encoding) {
+ case PIXEL_ENCODING_YCBCR422:
+ bpp = bpp * 2 / 3;
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ bpp /= 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Min symbol width = floor(h_blank * (bpp/16) / 128) */
+ dp_link_info->hblank_min_symbol_width = dc_fixpt_floor(
+ dc_fixpt_div(dc_fixpt_from_int(h_blank * bpp),
+ dc_fixpt_from_int(128 / 16)));
+
+ } else {
+ dp_link_info->hblank_min_symbol_width = 0;
+ }
+}
+
+void dcn10_build_audio_output(
+ struct dc_state *state,
+ const struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output)
+{
+ const struct dc_stream_state *stream = pipe_ctx->stream;
+ audio_output->engine_id = pipe_ctx->stream_res.stream_enc->id;
+
+ audio_output->signal = pipe_ctx->stream->signal;
+
+ /* audio_crtc_info */
+
+ audio_output->crtc_info.h_total =
+ stream->timing.h_total;
+
+ /*
+ * Audio packets are sent during actual CRTC blank physical signal, we
+ * need to specify actual active signal portion
+ */
+ audio_output->crtc_info.h_active =
+ stream->timing.h_addressable
+ + stream->timing.h_border_left
+ + stream->timing.h_border_right;
+
+ audio_output->crtc_info.v_active =
+ stream->timing.v_addressable
+ + stream->timing.v_border_top
+ + stream->timing.v_border_bottom;
+
+ audio_output->crtc_info.pixel_repetition = 1;
+
+ audio_output->crtc_info.interlaced =
+ (stream->timing.flags.INTERLACE != 0);
+
+ audio_output->crtc_info.refresh_rate =
+ (uint16_t)((stream->timing.pix_clk_100hz*100)/
+ (stream->timing.h_total*stream->timing.v_total));
+
+ audio_output->crtc_info.color_depth =
+ stream->timing.display_color_depth;
+
+ audio_output->crtc_info.requested_pixel_clock_100Hz =
+ pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz;
+
+ audio_output->crtc_info.calculated_pixel_clock_100Hz =
+ pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz;
+
+ audio_output->crtc_info.pixel_encoding =
+ stream->timing.pixel_encoding;
+
+ audio_output->crtc_info.dsc_bits_per_pixel =
+ stream->timing.dsc_cfg.bits_per_pixel;
+
+ audio_output->crtc_info.dsc_num_slices =
+ stream->timing.dsc_cfg.num_slices_h;
+
+/*for HDMI, audio ACR is with deep color ratio factor*/
+ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) &&
+ audio_output->crtc_info.requested_pixel_clock_100Hz ==
+ (stream->timing.pix_clk_100hz)) {
+ if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+ audio_output->crtc_info.requested_pixel_clock_100Hz =
+ audio_output->crtc_info.requested_pixel_clock_100Hz/2;
+ audio_output->crtc_info.calculated_pixel_clock_100Hz =
+ pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2;
+
+ }
+ }
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+ switch (pipe_ctx->stream->link->frl_link_settings.frl_link_rate) {
+ case HDMI_FRL_LINK_RATE_3GBPS:
+ audio_output->crtc_info.frl_character_clock_kHz = 166667;
+ break;
+ case HDMI_FRL_LINK_RATE_6GBPS:
+ case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+ audio_output->crtc_info.frl_character_clock_kHz = 333333;
+ break;
+ case HDMI_FRL_LINK_RATE_8GBPS:
+ audio_output->crtc_info.frl_character_clock_kHz = 444444;
+ break;
+ case HDMI_FRL_LINK_RATE_10GBPS:
+ audio_output->crtc_info.frl_character_clock_kHz = 555555;
+ break;
+ case HDMI_FRL_LINK_RATE_12GBPS:
+ default:
+ audio_output->crtc_info.frl_character_clock_kHz = 666667;
+ break;
+ }
+ } else
+ audio_output->crtc_info.frl_character_clock_kHz = 0;
+
+ if (state->clk_mgr &&
+ (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
+ pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL ||
+ pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) {
+ audio_output->pll_info.audio_dto_source_clock_in_khz =
+ state->clk_mgr->funcs->get_dp_ref_clk_frequency(
+ state->clk_mgr);
+ }
+
+ audio_output->pll_info.dto_source =
+ dcn10_translate_to_dto_source(
+ pipe_ctx->stream_res.tg->inst + 1);
+
+ /* TODO hard code to enable for now. Need get from stream */
+ audio_output->pll_info.ss_enabled = true;
+
+ audio_output->pll_info.ss_percentage =
+ pipe_ctx->pll_settings.ss_percentage;
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ dcn10_populate_audio_dp_link_info(pipe_ctx, &audio_output->dp_link_info);
+ }
+}
+
+enum dc_status dcn10_apply_single_controller_ctx_to_hw(
+ struct pipe_ctx *pipe_ctx,
+ struct dc_state *context,
+ struct dc *dc)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct drr_params params = {0};
+ unsigned int event_triggers = 0;
+ struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
+ struct dce_hwseq *hws = dc->hwseq;
+ const struct link_hwss *link_hwss = get_link_hwss(
+ link, &pipe_ctx->link_res);
+
+
+ if (hws->funcs.disable_stream_gating) {
+ hws->funcs.disable_stream_gating(dc, pipe_ctx);
+ }
+
+ if (pipe_ctx->stream_res.audio != NULL) {
+ struct audio_output audio_output = {0};
+
+ dcn10_build_audio_output(context, pipe_ctx, &audio_output);
+
+ link_hwss->setup_audio_output(pipe_ctx, &audio_output,
+ pipe_ctx->stream_res.audio->inst);
+
+ pipe_ctx->stream_res.audio->funcs->az_configure(
+ pipe_ctx->stream_res.audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &pipe_ctx->stream->audio_info,
+ &audio_output.dp_link_info);
+
+ if (dc->config.disable_hbr_audio_dp2)
+ if (pipe_ctx->stream_res.audio->funcs->az_disable_hbr_audio &&
+ dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.audio->funcs->az_disable_hbr_audio(pipe_ctx->stream_res.audio);
+ }
+
+ /* make sure no pipes syncd to the pipe being enabled */
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
+ check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
+
+ pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
+ pipe_ctx->stream_res.opp,
+ &stream->bit_depth_params,
+ &stream->clamping);
+
+ pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
+ pipe_ctx->stream_res.opp,
+ COLOR_SPACE_YCBCR601,
+ stream->timing.display_color_depth,
+ stream->signal);
+
+ while (odm_pipe) {
+ odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
+ odm_pipe->stream_res.opp,
+ COLOR_SPACE_YCBCR601,
+ stream->timing.display_color_depth,
+ stream->signal);
+
+ odm_pipe->stream_res.opp->funcs->opp_program_fmt(
+ odm_pipe->stream_res.opp,
+ &stream->bit_depth_params,
+ &stream->clamping);
+ odm_pipe = odm_pipe->next_odm_pipe;
+ }
+
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (!(hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)))
+ /* */
+ /* Do not touch stream timing on seamless boot optimization. */
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
+ hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
+
+ if (hws->funcs.setup_vupdate_interrupt)
+ hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
+
+ params.vertical_total_min = stream->adjust.v_total_min;
+ params.vertical_total_max = stream->adjust.v_total_max;
+ set_drr_and_clear_adjust_pending(pipe_ctx, stream, ¶ms);
+
+ // DRR should set trigger event to monitor surface update event
+ if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
+ event_triggers = 0x80;
+ /* Event triggers and num frames initialized for DRR, but can be
+ * later updated for PSR use. Note DRR trigger events are generated
+ * regardless of whether num frames met.
+ */
+ if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
+ pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
+ pipe_ctx->stream_res.tg, event_triggers, 2);
+
+ if (!dc_is_virtual_signal(pipe_ctx->stream->signal) &&
+ !dc_is_rgb_signal(pipe_ctx->stream->signal) &&
+ !dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.tg->inst);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
+
+ /* Temporary workaround to perform DSC programming ahead of stream enablement
+ * for smartmux/SPRS
+ * TODO: Remove SmartMux/SPRS checks once movement of DSC programming is generalized
+ */
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if ((pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+ ((link->dc->config.smart_mux_version && link->dc->is_switch_in_progress_dest)
+ || link->is_dds || link->skip_implict_edp_power_control)) &&
+ (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal)))
+ dc->link_srv->set_dsc_enable(pipe_ctx, true);
+ }
+
+ if (!stream->dpms_off)
+ dc->link_srv->set_dpms_on(context, pipe_ctx);
+
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
+ hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
+ }
+
+ pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
+
+ /* Phantom and main stream share the same link (because the stream
+ * is constructed with the same sink). Make sure not to override
+ * and link programming on the main.
+ */
+ if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) {
+ pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
+ pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false;
+ }
+ return DC_OK;
+}
+
+static void power_down_encoders(struct dc *dc)
+{
+ int i;
+
+ for (i = 0; i < dc->link_count; i++) {
+ struct dc_link *link = dc->links[i];
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+ enum signal_type signal = link->connector_signal;
+
+ dc->link_srv->blank_dp_stream(link, false);
+ if (signal != SIGNAL_TYPE_EDP)
+ signal = SIGNAL_TYPE_NONE;
+
+ if (link->ep_type == DISPLAY_ENDPOINT_PHY && link_enc)
+ link_enc->funcs->disable_output(link_enc, signal);
+
+ if (link->fec_state == dc_link_fec_enabled) {
+ if (link_enc && link_enc->funcs->fec_set_enable && link_enc->funcs->fec_set_ready) {
+ link_enc->funcs->fec_set_enable(link_enc, false);
+ link_enc->funcs->fec_set_ready(link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
+ }
+ }
+
+ link->link_status.link_active = false;
+ memset(&link->cur_link_settings, 0, sizeof(link->cur_link_settings));
+ }
+}
+
+static void power_down_controllers(struct dc *dc)
+{
+ unsigned int i;
+
+ for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
+ dc->res_pool->timing_generators[i]->funcs->disable_crtc(
+ dc->res_pool->timing_generators[i]);
+ }
+}
+
+static void power_down_clock_sources(struct dc *dc)
+{
+ unsigned int i;
+
+ if (dc->res_pool->dp_clock_source->funcs->cs_power_down(
+ dc->res_pool->dp_clock_source) == false)
+ dm_error("Failed to power down pll! (dp clk src)\n");
+
+ for (i = 0; i < dc->res_pool->clk_src_count; i++) {
+ if (dc->res_pool->clock_sources[i]->funcs->cs_power_down(
+ dc->res_pool->clock_sources[i]) == false)
+ dm_error("Failed to power down pll! (clk src index=%u)\n", i);
+ }
+}
+
+static void power_down_all_hw_blocks(struct dc *dc)
+{
+ power_down_encoders(dc);
+
+ power_down_controllers(dc);
+
+ power_down_clock_sources(dc);
+
+ if (dc->fbc_compressor)
+ dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
+}
+
+static void disable_vga_and_power_gate_all_controllers(
+ struct dc *dc)
+{
+ uint8_t i;
+ struct timing_generator *tg;
+ struct dc_context *ctx = dc->ctx;
+
+ if (dc->caps.ips_support)
+ return;
+
+ for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
+ tg = dc->res_pool->timing_generators[i];
+
+ if (tg->funcs->disable_vga)
+ tg->funcs->disable_vga(tg);
+ }
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ /* Enable CLOCK gating for each pipe BEFORE controller
+ * powergating. */
+ enable_display_pipe_clock_gating(ctx,
+ true);
+
+ dc->current_state->res_ctx.pipe_ctx[i].pipe_idx = i;
+ dc->hwss.disable_plane(dc, dc->current_state,
+ &dc->current_state->res_ctx.pipe_ctx[i]);
+ }
+}
+
+static void get_edp_streams(struct dc_state *context,
+ struct dc_stream_state **edp_streams,
+ int *edp_stream_num)
+{
+ uint8_t i;
+
+ *edp_stream_num = 0;
+ for (i = 0; i < context->stream_count; i++) {
+ if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
+ edp_streams[*edp_stream_num] = context->streams[i];
+ if (++(*edp_stream_num) == MAX_NUM_EDP)
+ return;
+ }
+ }
+}
+
+static void get_edp_links_with_sink(
+ struct dc *dc,
+ struct dc_link **edp_links_with_sink,
+ int *edp_with_sink_num)
+{
+ int i;
+
+ /* check if there is an eDP panel not in use */
+ *edp_with_sink_num = 0;
+ for (i = 0; i < dc->link_count; i++) {
+ if (dc->links[i]->local_sink &&
+ dc->links[i]->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
+ edp_links_with_sink[*edp_with_sink_num] = dc->links[i];
+ if (++(*edp_with_sink_num) == MAX_NUM_EDP)
+ return;
+ }
+ }
+}
+
+static void clean_up_dsc_blocks(struct dc *dc)
+{
+ struct display_stream_compressor *dsc = NULL;
+ struct timing_generator *tg = NULL;
+ struct stream_encoder *se = NULL;
+ struct dccg *dccg = dc->res_pool->dccg;
+ struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;
+ unsigned int i;
+
+ if (!dc->caps.is_apu ||
+ dc->ctx->dce_version < DCN_VERSION_3_15)
+ return;
+ /*VBIOS supports dsc starts from dcn315*/
+ for (i = 0; i < (unsigned int)dc->res_pool->res_cap->num_dsc; i++) {
+ struct dcn_dsc_state s = {0};
+
+ dsc = dc->res_pool->dscs[i];
+ dsc->funcs->dsc_read_state(dsc, &s);
+ if (s.dsc_fw_en) {
+ /* disable DSC in OPTC */
+ if (i < dc->res_pool->timing_generator_count) {
+ tg = dc->res_pool->timing_generators[i];
+ if (tg->funcs->set_dsc_config)
+ tg->funcs->set_dsc_config(tg, OPTC_DSC_DISABLED, 0, 0);
+ }
+ /* disable DSC in stream encoder */
+ if (i < dc->res_pool->stream_enc_count) {
+ se = dc->res_pool->stream_enc[i];
+ if (se->funcs->dp_set_dsc_config)
+ se->funcs->dp_set_dsc_config(se, OPTC_DSC_DISABLED, 0, 0);
+ if (se->funcs->dp_set_dsc_pps_info_packet)
+ se->funcs->dp_set_dsc_pps_info_packet(se, false, NULL, true);
+ }
+ /* disable DSC block */
+ if (dccg->funcs->set_ref_dscclk)
+ dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
+ dsc->funcs->dsc_disable(dsc);
+
+ /* power down DSC */
+ if (pg_cntl != NULL)
+ pg_cntl->funcs->dsc_pg_control(pg_cntl, dsc->inst, false);
+ }
+ }
+}
+
+static void dc_hwss_enable_otg_pwa(
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ struct timing_generator *tg = NULL;
+
+ if (dc->debug.enable_otg_frame_sync_pwa == 0)
+ return;
+
+ if (pipe_ctx == NULL || pipe_ctx->stream_res.tg == NULL)
+ return;
+ tg = pipe_ctx->stream_res.tg;
+
+ /*only enable this if one active*/
+ if (tg->funcs->enable_otg_pwa) {
+ struct otc_pwa_frame_sync pwa_param = {0};
+
+ DC_LOGGER_INIT(dc->ctx);
+ /* mode 1 to choose generate pwa sync signal on line 0 counting
+ * from vstartup at very beginning of the frame
+ */
+ pwa_param.pwa_frame_sync_line_offset = 0;
+ pwa_param.pwa_sync_mode = DC_OTG_PWA_FRAME_SYNC_MODE_VSTARTUP;
+ /*frame sync line for generating high frame sync*/
+ tg->funcs->enable_otg_pwa(tg, &pwa_param);
+ DC_LOG_DC("Enable OTG PWA frame sync on TG %d\n", tg->inst);
+ }
+}
+
+void dcn10_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
+{
+ struct dc_link *edp_links_with_sink[MAX_NUM_EDP];
+ struct dc_link *edp_links[MAX_NUM_EDP];
+ struct dc_stream_state *edp_streams[MAX_NUM_EDP];
+ struct dc_link *edp_link_with_sink = NULL;
+ struct dc_link *edp_link = NULL;
+ struct pipe_ctx *pipe_ctx = NULL;
+ struct dce_hwseq *hws = dc->hwseq;
+ int edp_with_sink_num;
+ unsigned int j, edp_num;
+ int edp_stream_num;
+ int i;
+ bool can_apply_edp_fast_boot = false;
+ bool can_apply_seamless_boot = false;
+ bool keep_edp_vdd_on = false;
+ bool should_clean_dsc_block = true;
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+ DC_LOGGER_INIT(dc->ctx);
+
+ get_edp_links_with_sink(dc, edp_links_with_sink, &edp_with_sink_num);
+ dc_get_edp_links(dc, edp_links, &edp_num);
+
+ if (hws->funcs.init_pipes)
+ hws->funcs.init_pipes(dc, context);
+
+ get_edp_streams(context, edp_streams, &edp_stream_num);
+
+ /* Check fastboot support, disable on DCE 6-8-10 because of blank screens */
+ if (edp_num && edp_stream_num && dc->ctx->dce_version > DCE_VERSION_10_0) {
+ for (j = 0; j < edp_num; j++) {
+ edp_link = edp_links[j];
+ if (edp_link != edp_streams[0]->link)
+ continue;
+ // enable fastboot if backend is enabled on eDP
+ if (edp_link->link_enc->funcs->is_dig_enabled &&
+ edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
+ edp_link->link_status.link_active) {
+ struct dc_stream_state *edp_stream = edp_streams[0];
+
+ can_apply_edp_fast_boot = dc_validate_boot_timing(dc,
+ edp_stream->sink, &edp_stream->timing);
+
+ // For Mux-platform, the default value is false.
+ // Disable fast boot during mux switching.
+ // The flag would be clean after switching done.
+ if (dc->is_switch_in_progress_dest && edp_link->is_dds)
+ can_apply_edp_fast_boot = false;
+
+ edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot;
+ if (can_apply_edp_fast_boot) {
+ DC_LOG_EVENT_LINK_TRAINING("eDP fast boot Enable\n");
+
+ // Vbios & Driver support different pixel rate div policy.
+ pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, edp_stream);
+ if (pipe_ctx &&
+ hws->funcs.is_dp_dig_pixel_rate_div_policy &&
+ hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx)) {
+ // Get Vbios div factor from register
+ dc->res_pool->dccg->funcs->get_pixel_rate_div(
+ dc->res_pool->dccg,
+ pipe_ctx->stream_res.tg->inst,
+ &pipe_ctx->pixel_rate_divider.div_factor1,
+ &pipe_ctx->pixel_rate_divider.div_factor2);
+
+ // VBios doesn't support pixel rate div, so force it.
+ // If VBios supports it, we check it from reigster or other flags.
+ pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle = 1;
+ }
+ dc_hwss_enable_otg_pwa(dc, pipe_ctx);
+ }
+ break;
+ }
+ }
+ // We are trying to enable eDP, don't power down VDD
+ if (can_apply_edp_fast_boot)
+ keep_edp_vdd_on = true;
+ }
+
+ // Check seamless boot support
+ for (i = 0; i < context->stream_count; i++) {
+ if (context->streams[i]->apply_seamless_boot_optimization) {
+ can_apply_seamless_boot = true;
+ break;
+ }
+ }
+
+ /* eDP should not have stream in resume from S4 and so even with VBios post
+ * it should get turned off
+ */
+ if (edp_with_sink_num)
+ edp_link_with_sink = edp_links_with_sink[0];
+
+ // During a mux switch, powering down the HW blocks and then enabling
+ // the link via a DPCD SET_POWER write causes a brief flash
+ keep_edp_vdd_on |= dc->is_switch_in_progress_dest;
+
+ if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) {
+ if (edp_link_with_sink && !keep_edp_vdd_on) {
+ /*turn off backlight before DP_blank and encoder powered down*/
+ hws->funcs.edp_backlight_control(edp_link_with_sink, false);
+ }
+ /*resume from S3, no vbios posting, no need to power down again*/
+ if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
+ clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
+
+ power_down_all_hw_blocks(dc);
+
+ /* DSC could be enabled on eDP during VBIOS post.
+ * To clean up dsc blocks if all eDP dpms_off is true.
+ */
+ for (i = 0; i < edp_stream_num; i++) {
+ if (!edp_streams[i]->dpms_off) {
+ should_clean_dsc_block = false;
+ }
+ }
+
+ if (should_clean_dsc_block)
+ clean_up_dsc_blocks(dc);
+
+ disable_vga_and_power_gate_all_controllers(dc);
+ if (edp_link_with_sink && !keep_edp_vdd_on)
+ dc->hwss.edp_power_control(edp_link_with_sink, false);
+ if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
+ clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
+ }
+ bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1);
+}
+
+static bool should_enable_fbc(struct dc *dc,
+ struct dc_state *context,
+ uint32_t *pipe_idx)
+{
+ uint32_t i;
+ struct pipe_ctx *pipe_ctx = NULL;
+ struct resource_context *res_ctx = &context->res_ctx;
+ unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
+
+
+ ASSERT(dc->fbc_compressor);
+
+ /* FBC memory should be allocated */
+ if (!dc->ctx->fbc_gpu_addr)
+ return false;
+
+ /* Only supports single display */
+ if (context->stream_count != 1)
+ return false;
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ if (res_ctx->pipe_ctx[i].stream) {
+
+ pipe_ctx = &res_ctx->pipe_ctx[i];
+
+ /* fbc not applicable on underlay pipe */
+ if (pipe_ctx->pipe_idx != underlay_idx) {
+ *pipe_idx = i;
+ break;
+ }
+ }
+ }
+
+ if (i == dc->res_pool->pipe_count)
+ return false;
+
+ if (!pipe_ctx->stream->link)
+ return false;
+
+ /* Only supports eDP */
+ if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP)
+ return false;
+
+ /* PSR should not be enabled */
+ if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled)
+ return false;
+
+ /* Replay should not be enabled */
+ if (pipe_ctx->stream->link->replay_settings.replay_feature_enabled)
+ return false;
+
+ /* Nothing to compress */
+ if (!pipe_ctx->plane_state)
+ return false;
+
+ /* Only for non-linear tiling */
+ if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL)
+ return false;
+
+ return true;
+}
+
+void dcn10_enable_fbc(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ uint32_t pipe_idx = 0;
+
+ if (should_enable_fbc(dc, context, &pipe_idx)) {
+ /* Program GRPH COMPRESSED ADDRESS and PITCH */
+ struct compr_addr_and_pitch_params params = {0, 0, 0};
+ struct compressor *compr = dc->fbc_compressor;
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
+
+ params.source_view_width = pipe_ctx->stream->timing.h_addressable;
+ params.source_view_height = pipe_ctx->stream->timing.v_addressable;
+ params.inst = pipe_ctx->stream_res.tg->inst;
+ compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr;
+
+ compr->funcs->surface_address_and_pitch(compr, ¶ms);
+ compr->funcs->set_fbc_invalidation_triggers(compr, 1);
+
+ compr->funcs->enable_fbc(compr, ¶ms);
+ }
+}
+
+static void dcn10_setup_audio_dto(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ unsigned int i;
+
+ /* program audio wall clock. use HDMI as clock source if HDMI
+ * audio active. Otherwise, use DP as clock source
+ * first, loop to find any HDMI audio, if not, loop find DP audio
+ */
+ /* Setup audio rate clock source */
+ /* Issue:
+ * Audio lag happened on DP monitor when unplug a HDMI monitor
+ *
+ * Cause:
+ * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL
+ * is set to either dto0 or dto1, audio should work fine.
+ * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1,
+ * set to dto0 will cause audio lag.
+ *
+ * Solution:
+ * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx,
+ * find first available pipe with audio, setup audio wall DTO per topology
+ * instead of per pipe.
+ */
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ if (pipe_ctx->top_pipe)
+ continue;
+ if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A &&
+ pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_FRL)
+ continue;
+ if (pipe_ctx->stream_res.audio != NULL) {
+ struct audio_output audio_output;
+
+ dcn10_build_audio_output(context, pipe_ctx, &audio_output);
+
+ if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
+ struct dtbclk_dto_params dto_params = {0};
+ dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+ /* For DCN3.1, audio to HPO FRL encoder is using audio DTBCLK DTO */
+ /* set audio DTBCLK DTO to 24MHz */
+ dto_params.req_audio_dtbclk_khz = 24000;
+ dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+ dc->res_pool->dccg,
+ &dto_params);
+ } else {
+ /* Audio DTBCLK params default to disabled */
+ dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+ dc->res_pool->dccg,
+ &dto_params);
+
+ pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+ pipe_ctx->stream_res.audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &audio_output.pll_info);
+ }
+ } else
+ pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+ pipe_ctx->stream_res.audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &audio_output.pll_info);
+ break;
+ }
+ }
+
+ /* no HDMI audio is found, try DP audio */
+ if (i == dc->res_pool->pipe_count) {
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ if (pipe_ctx->top_pipe)
+ continue;
+
+ if (!dc_is_dp_signal(pipe_ctx->stream->signal))
+ continue;
+
+ if (pipe_ctx->stream_res.audio != NULL) {
+ struct audio_output audio_output = {0};
+
+ dcn10_build_audio_output(context, pipe_ctx, &audio_output);
+
+ /* Audio to HPO DP encoder is using audio DTBCLK DTO */
+ if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
+ struct dtbclk_dto_params dto_params = {0};
+ dto_params.ref_dtbclk_khz =
+ dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
+
+ if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+ /* set audio DTBCLK DTO to 24MHz */
+ dto_params.req_audio_dtbclk_khz = 24000;
+ dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+ dc->res_pool->dccg,
+ &dto_params);
+ } else {
+ /* Audio DTBCLK params default to disabled */
+ dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+ dc->res_pool->dccg,
+ &dto_params);
+
+ pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+ pipe_ctx->stream_res.audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &audio_output.pll_info);
+ }
+ } else {
+ pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+ pipe_ctx->stream_res.audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &audio_output.pll_info);
+ }
+ break;
+ }
+ }
+ }
+}
+
+enum dc_status dcn10_apply_ctx_to_hw(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ struct dce_hwseq *hws = dc->hwseq;
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+ enum dc_status status;
+ unsigned int i;
+ bool was_hpo_acquired = resource_is_hpo_acquired(dc->current_state);
+ bool is_hpo_acquired = resource_is_hpo_acquired(context);
+
+ /* reset syncd pipes from disabled pipes */
+ if (dc->config.use_pipe_ctx_sync_logic)
+ reset_syncd_pipes_from_disabled_pipes(dc, context);
+
+ /* Reset old context */
+ /* look up the targets that have been removed since last commit */
+ hws->funcs.reset_hw_ctx_wrap(dc, context);
+
+ /* Skip applying if no targets */
+ if (context->stream_count <= 0)
+ return DC_OK;
+
+ /* Apply new context */
+ dcb->funcs->set_scratch_critical_state(dcb, true);
+
+ /* below is for real asic only */
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_state->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
+ continue;
+
+ if (pipe_ctx->stream == pipe_ctx_old->stream) {
+ if (pipe_ctx_old->clock_source != pipe_ctx->clock_source)
+ dce_crtc_switch_to_clk_src(dc->hwseq,
+ pipe_ctx->clock_source, i);
+ continue;
+ }
+
+ hws->funcs.enable_display_power_gating(
+ dc, (uint8_t)i, dc->ctx->dc_bios,
+ PIPE_GATING_CONTROL_DISABLE);
+ }
+
+ if (dc->fbc_compressor)
+ dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
+
+ dcn10_setup_audio_dto(dc, context);
+
+ if (dc->hwseq->funcs.setup_hpo_hw_control && was_hpo_acquired != is_hpo_acquired) {
+ dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, is_hpo_acquired);
+ }
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_state->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ if (pipe_ctx->stream == pipe_ctx_old->stream &&
+ pipe_ctx->stream->link->link_state_valid) {
+ continue;
+ }
+
+ if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
+ continue;
+
+ if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
+ continue;
+
+ status = dcn10_apply_single_controller_ctx_to_hw(
+ pipe_ctx,
+ context,
+ dc);
+
+ if (DC_OK != status)
+ return status;
+
+#ifdef CONFIG_DRM_AMD_DC_FP
+ if (hws->funcs.resync_fifo_dccg_dio)
+ hws->funcs.resync_fifo_dccg_dio(hws, dc, context, i);
+#endif
+ }
+
+
+ if (dc->debug.enable_otg_frame_sync_pwa && context->stream_count == 1) {
+ /* only enable this on one OTG*/
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx && pipe_ctx->stream != NULL) {
+ dc_hwss_enable_otg_pwa(dc, pipe_ctx);
+ break;
+ }
+ }
+ }
+ if (dc->fbc_compressor)
+ dcn10_enable_fbc(dc, dc->current_state);
+
+ dcb->funcs->set_scratch_critical_state(dcb, false);
+
+ return DC_OK;
+}
+
+void dcn10_power_down(struct dc *dc)
+{
+ power_down_all_hw_blocks(dc);
+ disable_vga_and_power_gate_all_controllers(dc);
+}
+
+bool dcn10_set_backlight_level(struct pipe_ctx *pipe_ctx,
+ struct set_backlight_level_params *backlight_level_params)
+{
+ uint32_t backlight_pwm_u16_16 = backlight_level_params->backlight_pwm_u16_16;
+ uint32_t frame_ramp = backlight_level_params->frame_ramp;
+ struct dc_link *link = pipe_ctx->stream->link;
+ struct dc *dc = link->ctx->dc;
+ struct abm *abm = pipe_ctx->stream_res.abm;
+ struct panel_cntl *panel_cntl = link->panel_cntl;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ bool fw_set_brightness = true;
+ /* DMCU -1 for all controller id values,
+ * therefore +1 here
+ */
+ uint32_t controller_id = pipe_ctx->stream_res.tg->inst + 1;
+
+ if (abm == NULL || panel_cntl == NULL || (abm->funcs->set_backlight_level_pwm == NULL))
+ return false;
+
+ if (dmcu)
+ fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
+
+ if (!fw_set_brightness && panel_cntl->funcs->driver_set_backlight)
+ panel_cntl->funcs->driver_set_backlight(panel_cntl, backlight_pwm_u16_16);
+ else
+ abm->funcs->set_backlight_level_pwm(
+ abm,
+ backlight_pwm_u16_16,
+ frame_ramp,
+ controller_id,
+ link->panel_cntl->inst);
+
+ return true;
+}
+
+void dcn10_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx)
+{
+ struct abm *abm = pipe_ctx->stream_res.abm;
+ struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
+
+ if (abm)
+ abm->funcs->set_abm_immediate_disable(abm,
+ pipe_ctx->stream->link->panel_cntl->inst);
+
+ if (panel_cntl)
+ panel_cntl->funcs->store_backlight_level(panel_cntl);
+}
+
+void dcn10_set_pipe(struct pipe_ctx *pipe_ctx)
+{
+ struct abm *abm = pipe_ctx->stream_res.abm;
+ struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
+ uint32_t otg_inst = pipe_ctx->stream_res.tg->inst + 1;
+
+ if (abm && panel_cntl)
+ abm->funcs->set_pipe(abm, otg_inst, panel_cntl->inst);
+}
+
+void dcn10_enable_lvds_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum clock_source_id clock_source,
+ uint32_t pixel_clock)
+{
+ (void)link_res;
+ link->link_enc->funcs->enable_lvds_output(
+ link->link_enc,
+ clock_source,
+ pixel_clock);
+ link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
+}
+
+void dcn10_enable_tmds_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ enum dc_color_depth color_depth,
+ uint32_t pixel_clock)
+{
+ (void)link_res;
+ link->link_enc->funcs->enable_tmds_output(
+ link->link_enc,
+ clock_source,
+ color_depth,
+ signal,
+ pixel_clock);
+ link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
+}
+
+void dcn10_enable_dp_link_output(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ struct pipe_ctx *pipes =
+ link->dc->current_state->res_ctx.pipe_ctx;
+ struct clock_source *dp_cs =
+ link->dc->res_pool->dp_clock_source;
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ unsigned int i;
+
+ /*
+ * Add the logic to extract BOTH power up and power down sequences
+ * from enable/disable link output and only call edp panel control
+ * in enable_link_dp and disable_link_dp once.
+ */
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+ }
+
+ /* If the current pixel clock source is not DTO(happens after
+ * switching from HDMI passive dongle to DP on the same connector),
+ * switch the pixel clock source to DTO.
+ */
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (pipes[i].stream != NULL &&
+ pipes[i].stream->link == link) {
+ if (pipes[i].clock_source != NULL &&
+ pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
+ pipes[i].clock_source = dp_cs;
+ pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz =
+ pipes[i].stream->timing.pix_clk_100hz;
+ pipes[i].clock_source->funcs->program_pix_clk(
+ pipes[i].clock_source,
+ &pipes[i].stream_res.pix_clk_params,
+ dc->link_srv->dp_get_encoding_format(link_settings),
+ &pipes[i].pll_settings);
+ }
+ }
+ }
+
+ if (link->ext_enc_id.id) {
+ dcn10_external_encoder_control(EXTERNAL_ENCODER_CONTROL_INIT, link, NULL);
+ dcn10_external_encoder_control(EXTERNAL_ENCODER_CONTROL_SETUP, link, NULL);
+ }
+
+ if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
+ if (dc->clk_mgr->funcs->notify_link_rate_change)
+ dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
+ }
+
+ if (dmcu != NULL && dmcu->funcs->lock_phy)
+ dmcu->funcs->lock_phy(dmcu);
+
+ if (link_hwss->ext.enable_dp_link_output)
+ link_hwss->ext.enable_dp_link_output(link, link_res, signal,
+ clock_source, link_settings);
+
+ link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
+
+ if (dmcu != NULL && dmcu->funcs->unlock_phy)
+ dmcu->funcs->unlock_phy(dmcu);
+
+ dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
+}
+
+void dcn10_disable_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct dc *dc = link->ctx->dc;
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+
+ if (signal == SIGNAL_TYPE_EDP &&
+ link->dc->hwss.edp_backlight_control &&
+ !link->skip_implict_edp_power_control)
+ link->dc->hwss.edp_backlight_control(link, false);
+ else if (dmcu != NULL && dmcu->funcs->lock_phy)
+ dmcu->funcs->lock_phy(dmcu);
+
+ link_hwss->disable_link_output(link, link_res, signal);
+ link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+ /*
+ * Add the logic to extract BOTH power up and power down sequences
+ * from enable/disable link output and only call edp panel control
+ * in enable_link_dp and disable_link_dp once.
+ */
+ if (dmcu != NULL && dmcu->funcs->unlock_phy)
+ dmcu->funcs->unlock_phy(dmcu);
+ dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
index 2cb674ba54e1..2484707757d7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
@@ -111,7 +111,7 @@ void dcn10_program_gamut_remap(struct program_gamut_remap_params *params);
void dcn10_init_hw(struct dc *dc);
void dcn10_init_pipes(struct dc *dc, struct dc_state *context);
void dcn10_power_down_on_boot(struct dc *dc);
-enum dc_status dce110_apply_ctx_to_hw(
+enum dc_status dcn10_apply_ctx_to_hw(
struct dc *dc,
struct dc_state *context);
void dcn10_plane_atomic_disconnect(struct dc *dc,
@@ -119,8 +119,8 @@ void dcn10_plane_atomic_disconnect(struct dc *dc,
struct pipe_ctx *pipe_ctx);
void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data);
void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx);
-void dce110_power_down(struct dc *dc);
-void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context);
+void dcn10_power_down(struct dc *dc);
+void dcn10_enable_accelerated_mode(struct dc *dc, struct dc_state *context);
void dcn10_enable_timing_synchronization(
struct dc *dc,
struct dc_state *state,
@@ -136,13 +136,13 @@ void dcn10_enable_per_frame_crtc_position_reset(
struct dc *dc,
int group_size,
struct pipe_ctx *grouped_pipes[]);
-void dce110_update_info_frame(struct pipe_ctx *pipe_ctx);
+void dcn10_update_info_frame(struct pipe_ctx *pipe_ctx);
void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx,
const uint8_t *custom_sdp_message,
unsigned int sdp_message_size);
-void dce110_blank_stream(struct pipe_ctx *pipe_ctx);
-void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx);
-void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx);
+void dcn10_blank_stream(struct pipe_ctx *pipe_ctx);
+void dcn10_enable_audio_stream(struct pipe_ctx *pipe_ctx);
+void dcn10_disable_audio_stream(struct pipe_ctx *pipe_ctx);
bool dcn10_dummy_display_power_gating(
struct dc *dc,
uint8_t controller_id,
@@ -156,7 +156,7 @@ void dcn10_get_position(struct pipe_ctx **pipe_ctx,
void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx,
int num_pipes, const struct dc_static_screen_params *params);
void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc);
-void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
+void dcn10_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
void dcn10_log_hw_state(struct dc *dc,
struct dc_log_buffer_ctx *log_ctx);
void dcn10_get_hw_state(struct dc *dc,
@@ -168,15 +168,15 @@ void dcn10_wait_for_mpcc_disconnect(
struct dc *dc,
struct resource_pool *res_pool,
struct pipe_ctx *pipe_ctx);
-void dce110_edp_backlight_control(
+void dcn10_edp_backlight_control(
struct dc_link *link,
bool enable);
-void dce110_edp_wait_for_T12(
+void dcn10_edp_wait_for_T12(
struct dc_link *link);
-void dce110_edp_power_control(
+void dcn10_edp_power_control(
struct dc_link *link,
bool power_up);
-void dce110_edp_wait_for_hpd_ready(
+void dcn10_edp_wait_for_hpd_ready(
struct dc_link *link,
bool power_up);
void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx);
@@ -219,4 +219,46 @@ void dcn10_reset_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx,
void dcn10_config_stereo_parameters(
struct dc_stream_state *stream, struct crtc_stereo_flags *flags);
+/* Declarations for sequencer functions folded in from dce110_hwseq.c */
+void dcn10_enable_stream(struct pipe_ctx *pipe_ctx);
+void dcn10_disable_stream(struct pipe_ctx *pipe_ctx);
+enum audio_dto_source dcn10_translate_to_dto_source(enum controller_id crtc_id);
+void dcn10_populate_audio_dp_link_info(
+ const struct pipe_ctx *pipe_ctx,
+ struct audio_dp_link_info *dp_link_info);
+void dcn10_build_audio_output(
+ struct dc_state *state,
+ const struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output);
+enum dc_status dcn10_apply_single_controller_ctx_to_hw(
+ struct pipe_ctx *pipe_ctx,
+ struct dc_state *context,
+ struct dc *dc);
+void dcn10_enable_fbc(
+ struct dc *dc,
+ struct dc_state *context);
+bool dcn10_set_backlight_level(struct pipe_ctx *pipe_ctx,
+ struct set_backlight_level_params *backlight_level_params);
+void dcn10_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx);
+void dcn10_set_pipe(struct pipe_ctx *pipe_ctx);
+void dcn10_enable_lvds_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum clock_source_id clock_source,
+ uint32_t pixel_clock);
+void dcn10_enable_tmds_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ enum dc_color_depth color_depth,
+ uint32_t pixel_clock);
+void dcn10_enable_dp_link_output(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings);
+void dcn10_disable_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal);
+
#endif /* __DC_HWSS_DCN10_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
index b5e82e190124..b91256c6f88c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
@@ -24,7 +24,7 @@
*/
#include "hw_sequencer_private.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
@@ -32,7 +32,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap,
.init_hw = dcn10_init_hw,
.power_down_on_boot = dcn10_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.post_unlock_program_front_end = dcn10_post_unlock_program_front_end,
@@ -42,17 +42,17 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.update_pending_status = dcn10_update_pending_status,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
.program_output_csc = dcn10_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
- .update_info_frame = dce110_update_info_frame,
+ .update_info_frame = dcn10_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
- .enable_stream = dce110_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .enable_stream = dcn10_enable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn10_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn10_disable_plane,
.pipe_control_lock = dcn10_pipe_control_lock,
.cursor_lock = dcn10_cursor_lock,
@@ -63,14 +63,14 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.get_position = dcn10_get_position,
.set_static_screen_control = dcn10_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
- .set_avmute = dce110_set_avmute,
+ .set_avmute = dcn10_set_avmute,
.log_hw_state = dcn10_log_hw_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -79,13 +79,13 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.get_clock = dcn10_get_clock,
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
- .set_backlight_level = dce110_set_backlight_level,
- .set_abm_immediate_disable = dce110_set_abm_immediate_disable,
- .set_pipe = dce110_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .set_backlight_level = dcn10_set_backlight_level,
+ .set_abm_immediate_disable = dcn10_set_abm_immediate_disable,
+ .set_pipe = dcn10_set_pipe,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
};
@@ -97,12 +97,12 @@ static const struct hwseq_private_funcs dcn10_private_funcs = {
.update_mpcc = dcn10_update_mpcc,
.set_input_transfer_func = dcn10_set_input_transfer_func,
.set_output_transfer_func = dcn10_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn10_blank_pixel_data,
.reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap,
.enable_stream_timing = dcn10_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = NULL,
.enable_stream_gating = NULL,
.setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
index 1797a91b0186..3cc65e2678b3 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
@@ -33,7 +33,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap,
.init_hw = dcn10_init_hw,
.power_down_on_boot = dcn10_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -43,18 +43,18 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_vblanks_synchronization = dcn10_enable_vblanks_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
- .update_info_frame = dce110_update_info_frame,
+ .update_info_frame = dcn10_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn20_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.pipe_control_lock = dcn20_pipe_control_lock,
.interdependent_update_lock = dcn10_lock_all_pipes,
@@ -66,15 +66,15 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.get_position = dcn10_get_position,
.set_static_screen_control = dcn10_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
- .set_avmute = dce110_set_avmute,
+ .set_avmute = dcn10_set_avmute,
.log_hw_state = dcn10_log_hw_state,
.log_color_state = dcn20_log_color_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -92,13 +92,13 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.set_flip_control_gsl = dcn20_set_flip_control_gsl,
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
- .set_backlight_level = dce110_set_backlight_level,
- .set_abm_immediate_disable = dce110_set_abm_immediate_disable,
- .set_pipe = dce110_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .set_backlight_level = dcn10_set_backlight_level,
+ .set_abm_immediate_disable = dcn10_set_abm_immediate_disable,
+ .set_pipe = dcn10_set_pipe,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.set_disp_pattern_generator = dcn20_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
@@ -110,12 +110,12 @@ static const struct hwseq_private_funcs dcn20_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn20_set_input_transfer_func,
.set_output_transfer_func = dcn20_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
index dec57fb4c05c..fb45235f0e34 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn201/dcn201_hwseq.h"
@@ -33,7 +33,7 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap,
.init_hw = dcn201_init_hw,
.power_down_on_boot = NULL,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -43,17 +43,17 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
- .update_info_frame = dce110_update_info_frame,
+ .update_info_frame = dcn10_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
- .enable_stream = dce110_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .enable_stream = dcn10_enable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn201_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn10_disable_plane,
.pipe_control_lock = dcn201_pipe_control_lock,
.interdependent_update_lock = dcn10_lock_all_pipes,
@@ -65,14 +65,14 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
.get_position = dcn10_get_position,
.set_static_screen_control = dcn10_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
- .set_avmute = dce110_set_avmute,
+ .set_avmute = dcn10_set_avmute,
.log_hw_state = dcn10_log_hw_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.setup_periodic_interrupt = dcn10_setup_periodic_interrupt,
.set_clock = dcn10_set_clock,
.get_clock = dcn10_get_clock,
@@ -84,13 +84,13 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn201_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
- .set_backlight_level = dce110_set_backlight_level,
- .set_abm_immediate_disable = dce110_set_abm_immediate_disable,
- .set_pipe = dce110_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .set_backlight_level = dcn10_set_backlight_level,
+ .set_abm_immediate_disable = dcn10_set_abm_immediate_disable,
+ .set_pipe = dcn10_set_pipe,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.set_disp_pattern_generator = dcn20_set_disp_pattern_generator,
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
};
@@ -102,12 +102,12 @@ static const struct hwseq_private_funcs dcn201_private_funcs = {
.update_mpcc = dcn201_update_mpcc,
.set_input_transfer_func = dcn20_set_input_transfer_func,
.set_output_transfer_func = dcn20_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = NULL,
.enable_stream_gating = NULL,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
index 2be68f8dd0fc..2fae6161b3a1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
@@ -28,7 +28,7 @@
#include "core_types.h"
#include "resource.h"
#include "dce/dce_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn21_hwseq.h"
#include "vmid.h"
#include "reg_helper.h"
@@ -211,7 +211,7 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx)
}
if (dmcu) {
- dce110_set_abm_immediate_disable(pipe_ctx);
+ dcn10_set_abm_immediate_disable(pipe_ctx);
return;
}
@@ -248,7 +248,7 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx)
otg_inst = tg->inst;
if (dmcu) {
- dce110_set_pipe(pipe_ctx);
+ dcn10_set_pipe(pipe_ctx);
return;
}
@@ -289,7 +289,7 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx,
otg_inst = tg->inst;
if (dc->dc->res_pool->dmcu) {
- dce110_set_backlight_level(pipe_ctx, backlight_level_params);
+ dcn10_set_backlight_level(pipe_ctx, backlight_level_params);
return true;
}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
index c7701a8b574a..f90c88ace2a1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -34,7 +34,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap,
.init_hw = dcn10_init_hw,
.power_down_on_boot = dcn10_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -44,17 +44,17 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
- .update_info_frame = dce110_update_info_frame,
+ .update_info_frame = dcn10_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn20_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.pipe_control_lock = dcn20_pipe_control_lock,
.interdependent_update_lock = dcn10_lock_all_pipes,
@@ -66,15 +66,15 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
.get_position = dcn10_get_position,
.set_static_screen_control = dcn10_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
- .set_avmute = dce110_set_avmute,
+ .set_avmute = dcn10_set_avmute,
.log_hw_state = dcn10_log_hw_state,
.get_hw_state = dcn10_get_hw_state,
.log_color_state = dcn20_log_color_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -97,10 +97,10 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.is_abm_supported = dcn21_is_abm_supported,
.set_disp_pattern_generator = dcn20_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
@@ -113,12 +113,12 @@ static const struct hwseq_private_funcs dcn21_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn20_set_input_transfer_func,
.set_output_transfer_func = dcn20_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
index d5aa58462855..7965285b587b 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -34,7 +34,7 @@
static const struct hw_sequencer_funcs dcn30_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn30_init_hw,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -44,17 +44,17 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn30_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn20_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.disable_pixel_data = dcn20_disable_pixel_data,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -73,10 +73,10 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -101,10 +101,10 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.hardware_release = dcn30_hardware_release,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
@@ -120,12 +120,12 @@ static const struct hwseq_private_funcs dcn30_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn30_set_input_transfer_func,
.set_output_transfer_func = dcn30_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
index a570333aeac1..cd083fadc6bd 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -36,7 +36,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn10_init_hw,
.power_down_on_boot = dcn10_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -46,17 +46,17 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn30_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn20_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.pipe_control_lock = dcn20_pipe_control_lock,
.interdependent_update_lock = dcn10_lock_all_pipes,
@@ -74,9 +74,9 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -98,10 +98,10 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
.optimize_pwr_state = dcn21_optimize_pwr_state,
@@ -116,12 +116,12 @@ static const struct hwseq_private_funcs dcn301_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn30_set_input_transfer_func,
.set_output_transfer_func = dcn30_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
index 7197414e5bd6..9ffe03bf21d5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -37,7 +37,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn31_init_hw,
.power_down_on_boot = dcn10_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -47,17 +47,17 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn20_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.disable_pixel_data = dcn20_disable_pixel_data,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -76,10 +76,10 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -102,10 +102,10 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dce110_disable_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
+ .disable_link_output = dcn10_disable_link_output,
.z10_restore = dcn31_z10_restore,
.z10_save_init = dcn31_z10_save_init,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
@@ -122,12 +122,12 @@ static const struct hwseq_private_funcs dcn31_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn30_set_input_transfer_func,
.set_output_transfer_func = dcn30_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
index 4966c044a864..53d9097d7ce5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
@@ -24,7 +24,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -39,7 +39,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn31_init_hw,
.power_down_on_boot = dcn10_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -49,17 +49,17 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn20_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.disable_pixel_data = dcn20_disable_pixel_data,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -78,10 +78,10 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.log_color_state = dcn30_log_color_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -104,9 +104,9 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
.disable_link_output = dcn314_disable_link_output,
.z10_restore = dcn31_z10_restore,
.z10_save_init = dcn31_z10_save_init,
@@ -125,12 +125,12 @@ static const struct hwseq_private_funcs dcn314_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn30_set_input_transfer_func,
.set_output_transfer_func = dcn30_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
index 364b4108f5d6..b1e1e74a26b5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -37,7 +37,7 @@
static const struct hw_sequencer_funcs dcn32_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn32_init_hw,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -47,17 +47,17 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn32_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.disable_pixel_data = dcn20_disable_pixel_data,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -75,10 +75,10 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -105,9 +105,9 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.hardware_release = dcn30_hardware_release,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
.disable_link_output = dcn32_disable_link_output,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
@@ -133,12 +133,12 @@ static const struct hwseq_private_funcs dcn32_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn32_set_input_transfer_func,
.set_output_transfer_func = dcn32_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.disable_stream_gating = dcn20_disable_stream_gating,
.enable_stream_gating = dcn20_enable_stream_gating,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
@@ -164,7 +164,7 @@ static const struct hwseq_private_funcs dcn32_private_funcs = {
.calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
.resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio,
.is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy,
- .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
+ .apply_single_controller_ctx_to_hw = dcn10_apply_single_controller_ctx_to_hw,
.reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe,
.wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
.set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index fc18d2207711..8cdbbe92e398 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -24,7 +24,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -41,7 +41,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn35_init_hw,
.power_down_on_boot = dcn35_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -51,17 +51,17 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn32_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn35_disable_plane,
.disable_pixel_data = dcn20_disable_pixel_data,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -79,10 +79,10 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -111,9 +111,9 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.set_backlight_level = dcn31_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
.disable_link_output = dcn35_disable_link_output,
.z10_restore = dcn35_z10_restore,
.z10_save_init = dcn31_z10_save_init,
@@ -143,12 +143,12 @@ static const struct hwseq_private_funcs dcn35_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn32_set_input_transfer_func,
.set_output_transfer_func = dcn32_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
.did_underflow_occur = dcn10_did_underflow_occur,
.init_blank = dcn20_init_blank,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
index 19ec5b4edfdc..e51bd356849d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
@@ -23,7 +23,7 @@
*
*/
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -40,7 +40,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.program_gamut_remap = dcn30_program_gamut_remap,
.init_hw = dcn35_init_hw,
.power_down_on_boot = dcn35_power_down_on_boot,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -50,17 +50,17 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn20_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn32_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn35_disable_plane,
.disable_pixel_data = dcn20_disable_pixel_data,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -78,10 +78,10 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
.set_cursor_position = dcn10_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -104,9 +104,9 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.set_backlight_level = dcn31_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
.disable_link_output = dcn32_disable_link_output,
.z10_restore = dcn35_z10_restore,
.z10_save_init = dcn31_z10_save_init,
@@ -132,12 +132,12 @@ static const struct hwseq_private_funcs dcn351_private_funcs = {
.update_mpcc = dcn20_update_mpcc,
.set_input_transfer_func = dcn32_set_input_transfer_func,
.set_output_transfer_func = dcn32_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap,
.enable_stream_timing = dcn20_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
.did_underflow_occur = dcn10_did_underflow_occur,
.init_blank = dcn20_init_blank,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
index f206e221f926..99bec66322a4 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
@@ -2,7 +2,7 @@
//
// Copyright 2024 Advanced Micro Devices, Inc.
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -16,7 +16,7 @@
static const struct hw_sequencer_funcs dcn401_funcs = {
.program_gamut_remap = dcn401_program_gamut_remap,
.init_hw = dcn401_init_hw,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn401_program_front_end_for_ctx,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
@@ -27,17 +27,17 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
.trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn401_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn401_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.disable_plane_sequence = dcn401_disable_plane_sequence,
.pipe_control_lock = dcn20_pipe_control_lock,
@@ -58,10 +58,10 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
.wait_for_mpcc_disconnect_sequence = dcn401_wait_for_mpcc_disconnect_sequence,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
.set_cursor_position = dcn401_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -93,9 +93,9 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.hardware_release = dcn401_hardware_release,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
.disable_link_output = dcn401_disable_link_output,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
@@ -130,13 +130,13 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
.update_mpcc_sequence = dcn401_update_mpcc_sequence,
.set_input_transfer_func = dcn32_set_input_transfer_func,
.set_output_transfer_func = dcn401_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.blank_pixel_data_sequence = dcn401_blank_pixel_data_sequence,
.reset_hw_ctx_wrap = dcn401_reset_hw_ctx_wrap,
.enable_stream_timing = dcn401_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
.setup_vupdate_interrupt_sequence = dcn401_setup_vupdate_interrupt_sequence,
.did_underflow_occur = dcn10_did_underflow_occur,
@@ -164,7 +164,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
.program_mall_pipe_config_sequence = dcn401_program_mall_pipe_config_sequence,
.update_mall_sel = dcn32_update_mall_sel,
.calculate_dccg_k1_k2_values = NULL,
- .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
+ .apply_single_controller_ctx_to_hw = dcn10_apply_single_controller_ctx_to_hw,
.reset_back_end_for_pipe = dcn401_reset_back_end_for_pipe,
.populate_mcm_luts = NULL,
.perform_3dlut_wa_unlock = dcn401_perform_3dlut_wa_unlock,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
index 49c13611a518..3f6be27ce51c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
@@ -2,7 +2,7 @@
//
// Copyright 2026 Advanced Micro Devices, Inc.
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
@@ -18,7 +18,7 @@
static const struct hw_sequencer_funcs dcn42_funcs = {
.program_gamut_remap = dcn401_program_gamut_remap,
.init_hw = dcn42_init_hw,
- .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .apply_ctx_to_hw = dcn10_apply_ctx_to_hw,
.power_down_on_boot = dcn42_power_down_on_boot,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn401_program_front_end_for_ctx,
@@ -30,17 +30,17 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
.trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
- .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_accelerated_mode = dcn10_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn401_enable_stream,
- .disable_stream = dce110_disable_stream,
+ .disable_stream = dcn10_disable_stream,
.unblank_stream = dcn401_unblank_stream,
- .blank_stream = dce110_blank_stream,
- .enable_audio_stream = dce110_enable_audio_stream,
- .disable_audio_stream = dce110_disable_audio_stream,
+ .blank_stream = dcn10_blank_stream,
+ .enable_audio_stream = dcn10_enable_audio_stream,
+ .disable_audio_stream = dcn10_disable_audio_stream,
.disable_plane = dcn35_disable_plane,
.pipe_control_lock = dcn20_pipe_control_lock,
.interdependent_update_lock = dcn401_interdependent_update_lock,
@@ -57,10 +57,10 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .edp_backlight_control = dce110_edp_backlight_control,
- .edp_power_control = dce110_edp_power_control,
- .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
- .edp_wait_for_T12 = dce110_edp_wait_for_T12,
+ .edp_backlight_control = dcn10_edp_backlight_control,
+ .edp_power_control = dcn10_edp_power_control,
+ .edp_wait_for_hpd_ready = dcn10_edp_wait_for_hpd_ready,
+ .edp_wait_for_T12 = dcn10_edp_wait_for_T12,
.set_cursor_position = dcn401_set_cursor_position,
.set_cursor_attribute = dcn10_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
@@ -92,9 +92,9 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.hardware_release = dcn42_hardware_release,
.set_pipe = dcn21_set_pipe,
- .enable_lvds_link_output = dce110_enable_lvds_link_output,
- .enable_tmds_link_output = dce110_enable_tmds_link_output,
- .enable_dp_link_output = dce110_enable_dp_link_output,
+ .enable_lvds_link_output = dcn10_enable_lvds_link_output,
+ .enable_tmds_link_output = dcn10_enable_tmds_link_output,
+ .enable_dp_link_output = dcn10_enable_dp_link_output,
.disable_link_output = dcn401_disable_link_output,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.optimize_pwr_state = dcn21_optimize_pwr_state,
@@ -132,12 +132,12 @@ static const struct hwseq_private_funcs dcn42_private_funcs = {
.update_mpcc = dcn42_update_mpcc,
.set_input_transfer_func = dcn32_set_input_transfer_func,
.set_output_transfer_func = dcn401_set_output_transfer_func,
- .power_down = dce110_power_down,
+ .power_down = dcn10_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.reset_hw_ctx_wrap = dcn401_reset_hw_ctx_wrap,
.enable_stream_timing = dcn401_enable_stream_timing,
- .edp_backlight_control = dce110_edp_backlight_control,
+ .edp_backlight_control = dcn10_edp_backlight_control,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
.did_underflow_occur = dcn10_did_underflow_occur,
.init_blank = dcn32_init_blank,
@@ -153,7 +153,7 @@ static const struct hwseq_private_funcs dcn42_private_funcs = {
.program_mall_pipe_config = dcn32_program_mall_pipe_config,
.update_mall_sel = dcn32_update_mall_sel,
.calculate_dccg_k1_k2_values = NULL,
- .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
+ .apply_single_controller_ctx_to_hw = dcn10_apply_single_controller_ctx_to_hw,
.reset_back_end_for_pipe = dcn401_reset_back_end_for_pipe,
.populate_mcm_luts = NULL,
.perform_3dlut_wa_unlock = dcn401_perform_3dlut_wa_unlock,
diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
index b595a11c5eaf..f8ae3b2669d2 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
@@ -28,14 +28,18 @@
#include "include/irq_service_interface.h"
#include "include/logger_interface.h"
+#if !defined(TRIM_DCE)
#include "dce110/irq_service_dce110.h"
+#endif
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/irq_service_dce60.h"
#endif
+#if !defined(TRIM_DCE)
#include "dce80/irq_service_dce80.h"
#include "dce120/irq_service_dce120.h"
+#endif
#include "dcn10/irq_service_dcn10.h"
#include "reg_helper.h"
@@ -92,6 +96,33 @@ static const struct irq_source_info *find_irq_source_info(
return &irq_service->info[source];
}
+/*
+ * In the trimmed build the dce110 irq dir (which owns these dummy handlers)
+ * is excluded, so provide the definitions here. In the non-trimmed build the
+ * originals in dce110/irq_service_dce110.c are used instead.
+ */
+#if defined(TRIM_DCE)
+bool dal_irq_service_dummy_set(struct irq_service *irq_service,
+ const struct irq_source_info *info,
+ bool enable)
+{
+ (void)enable;
+ DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
+ __func__, info->src_id, info->ext_id);
+
+ return false;
+}
+
+bool dal_irq_service_dummy_ack(struct irq_service *irq_service,
+ const struct irq_source_info *info)
+{
+ DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
+ __func__, info->src_id, info->ext_id);
+
+ return false;
+}
+#endif /* TRIM_DCE */
+
void dal_irq_service_set_generic(
struct irq_service *irq_service,
const struct irq_source_info *info,
diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
index bbcef3d2fe33..8b6a842f38cc 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
+++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
@@ -82,6 +82,15 @@ void dal_irq_service_set_generic(
const struct irq_source_info *info,
bool enable);
+bool dal_irq_service_dummy_set(
+ struct irq_service *irq_service,
+ const struct irq_source_info *info,
+ bool enable);
+
+bool dal_irq_service_dummy_ack(
+ struct irq_service *irq_service,
+ const struct irq_source_info *info);
+
bool hpd0_ack(
struct irq_service *irq_service,
const struct irq_source_info *info);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c
index 214461f5d2f2..5975432c174c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c
@@ -41,7 +41,7 @@
#include "dcn10/dcn10_dpp.h"
#include "dcn10/dcn10_optc.h"
#include "dcn10/dcn10_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_opp.h"
#include "dcn10/dcn10_link_encoder.h"
#include "dcn10/dcn10_stream_encoder.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
index 2cfe69708bf6..9e7839032b81 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
@@ -44,7 +44,7 @@
#include "dcn20/dcn20_dpp.h"
#include "dcn20/dcn20_optc.h"
#include "dcn20/dcn20_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn10/dcn10_resource.h"
#include "dcn20/dcn20_opp.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
index 447f61965295..72164140bdec 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
@@ -44,7 +44,7 @@
#include "dcn201/dcn201_dccg.h"
#include "dcn201/dcn201_optc.h"
#include "dcn201/dcn201_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn201/dcn201_opp.h"
#include "dcn201/dcn201_link_encoder.h"
#include "dcn20/dcn20_stream_encoder.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
index 0ee386c3bc23..6707a7062955 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
@@ -49,7 +49,7 @@
#include "dcn20/dcn20_dpp.h"
#include "dcn20/dcn20_optc.h"
#include "dcn21/dcn21_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn21/dcn21_link_encoder.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
index ec74538472ee..57fb333beee8 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
@@ -44,7 +44,7 @@
#include "dcn30/dcn30_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c
index 77f9e371f48e..263722ee6a5c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c
@@ -45,7 +45,7 @@
#include "dcn301/dcn301_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
index e6d7da830440..45e2c348e251 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
@@ -48,7 +48,7 @@
#include "dcn31/dcn31_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
@@ -2442,7 +2442,7 @@ enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link,
// Setup audio
if (pipes[i].stream_res.audio != NULL)
- build_audio_output(state, &pipes[i], &audio_output[i]);
+ dcn10_build_audio_output(state, &pipes[i], &audio_output[i]);
}
#else
/* This DCN requires rate divider updates and audio reprogramming to allow DP1<-->DP2 link rate switching,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
index ef2038efbfc2..1bcd9ffbbab8 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
@@ -50,7 +50,7 @@
#include "dcn314/dcn314_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
index dbf9cb934c76..71b9aa1ca757 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
@@ -47,7 +47,7 @@
#include "dcn31/dcn31_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
index 3a776959767c..2aca863e5269 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
@@ -47,7 +47,7 @@
#include "dcn31/dcn31_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index 697463622a10..bbd98a29b35c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -48,7 +48,7 @@
#include "dcn32/dcn32_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
index 6ebab0f185c9..4991ddea6b53 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
@@ -50,7 +50,7 @@
#include "dcn32/dcn32_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn30/dcn30_opp.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
index 800a030990bd..563e6001a03c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
@@ -51,7 +51,7 @@
#include "dcn35/dcn35_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn35/dcn35_opp.h"
#include "dcn35/dcn35_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
index 8e276c333dbe..aebf48e4e182 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
@@ -29,7 +29,7 @@
#include "dcn35/dcn35_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn35/dcn35_opp.h"
#include "dcn35/dcn35_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
index e2368a5c1eed..f8cc20ed1264 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
@@ -30,7 +30,7 @@
#include "dcn35/dcn35_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn35/dcn35_opp.h"
#include "dcn35/dcn35_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
index 302c1f4bc7bc..25b0ab401a98 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
@@ -27,7 +27,7 @@
#include "dcn401/dcn401_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_opp.h"
#include "dcn401/dcn401_dsc.h"
#include "dcn30/dcn30_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
index 547a0b816539..99e6be1423cd 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
@@ -34,7 +34,7 @@
#include "dcn42/dcn42_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn35/dcn35_opp.h"
#include "dcn30/dcn30_vpg.h"
#include "dcn31/dcn31_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index 2334bc5b75b8..0698e68a0b09 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@ -38,7 +38,7 @@
#include "dcn42/dcn42_optc.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
-#include "dce110/dce110_hwseq.h"
+#include "dcn10/dcn10_hwseq.h"
#include "dcn35/dcn35_opp.h"
#include "dcn30/dcn30_vpg.h"
#include "dcn31/dcn31_vpg.h"
diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
index da74ed66c8f9..7c691dda8aac 100644
--- a/drivers/gpu/drm/amd/display/include/link_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
@@ -202,13 +202,13 @@ enum dpcd_source_sequence {
DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE, /*done in perform_link_training_with_retries/dcn20_enable_stream */
DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY, /*done in dp_enable_link_phy */
DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN, /*done in dp_set_hw_test_pattern */
- DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM, /*done in dce110_enable_audio_stream */
+ DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM, /*done in dcn10_enable_audio_stream */
DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM, /*done in enc1_stream_encoder_dp_unblank */
DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM, /*done in enc1_stream_encoder_dp_blank */
DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET, /*done in enc1_stream_encoder_dp_blank */
- DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM, /*done in dce110_disable_audio_stream */
+ DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM, /*done in dcn10_disable_audio_stream */
DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY, /*done in dp_disable_link_phy */
- DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE, /*done in dce110_disable_stream */
+ DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE, /*done in dcn10_disable_stream */
};
/* DPCD_ADDR_TRAINING_LANEx_SET registers value */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 64/70] drm/amd/display: hide Apple Studio Display secondary tile
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (62 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 63/70] drm/amd/display: Trim DCE from DCN-only builds Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 65/70] drm/amd/display: Reduce DML reinitialization when params don't change Wayne Lin
` (5 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Mario Limonciello
From: Jerry Zuo <jerry.zuo@amd.com>
The Apple Studio Display exposes a 2x1 tiled panel over two SST DP
links. The primary tile advertises the full 5120x2880 mode (with DSC on
the bandwidth-sufficient link) while the secondary carries a per-tile
2560x2880 timing on a link without sufficient bandwidth. Report the
non-primary tile connector as disconnected during detect so compositors
only see the primary DP link and configure a single 5K mode instead of
driving both tiled streams independently.
Drive the behaviour from an EDID quirk: add a disable_second_tile panel
patch that apply_edid_quirks() sets for the affected Apple Studio
Display panel IDs (0xAE3A, 0xAE42, 0xAE46), and have detect() hide the
secondary tile when the sink carries that quirk.
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Sun peng Li <sunpeng.li@amd.com>
Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 36 +++++++++++++++++++
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 11 ++++++
drivers/gpu/drm/amd/display/dc/dc_types.h | 1 +
3 files changed, 48 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index da6ec75bb0f9..c30e341c0f37 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1605,6 +1605,39 @@ amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
}
EXPORT_IF_KUNIT(amdgpu_dm_connector_poll);
+/*
+ * Apple Studio Display exposes two SST DP links for a 2x1 tiled panel.
+ * The primary tile advertises the full 5120x2880 mode (with DSC on the
+ * bandwidth-sufficient link) while the secondary carries a per-tile
+ * 2560x2880 timing on a insufficient bandwidth link. Hide the secondary
+ * connector from userspace so compositors configure a single 5K stream
+ * on the primary link only.
+ */
+static bool amdgpu_dm_hide_secondary_tile_from_userspace(struct drm_connector *connector)
+{
+ struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+
+ if (!aconnector->dc_sink)
+ return false;
+
+ if (!aconnector->dc_sink->edid_caps.panel_patch.disable_second_tile)
+ return false;
+
+ drm_edid_connector_update(connector, aconnector->drm_edid);
+
+ if (!connector->has_tile)
+ return false;
+
+ if (!connector->tile_h_loc && !connector->tile_v_loc)
+ return false;
+
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] hiding secondary Apple Studio Display tile from userspace\n",
+ connector->base.id, connector->name);
+
+ return true;
+}
+
/**
* amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display
*
@@ -1648,6 +1681,9 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
(!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog))
return amdgpu_dm_connector_poll(aconnector, force);
+ if (amdgpu_dm_hide_secondary_tile_from_userspace(connector))
+ return connector_status_disconnected;
+
return (aconnector->dc_sink ? connector_status_connected :
connector_status_disconnected);
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index c172bb76bcda..42f5673acb4d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -136,6 +136,17 @@ STATIC_IFN_KUNIT void apply_edid_quirks(struct dc_link *link, struct edid *edid,
drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
link->wa_flags.skip_phy_ssc_reduction = true;
break;
+ /*
+ * Workaround for Apple Studio Display which exposes a 2x1 tiled panel
+ * over two SST DP links. Hide the secondary tile from userspace so
+ * compositors drive a single 5K stream on the primary link only.
+ */
+ case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE3A):
+ case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE42):
+ case drm_edid_encode_panel_id('A', 'P', 'P', 0xAE46):
+ drm_dbg_driver(dev, "Hiding secondary tile on panel id %X\n", panel_id);
+ edid_caps->panel_patch.disable_second_tile = true;
+ break;
default:
return;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index fccf9cb359f0..3edeb94fba23 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -188,6 +188,7 @@ struct dc_panel_patch {
unsigned int skip_audio_sab_check;
unsigned int mst_start_top_delay;
unsigned int remove_sink_ext_caps;
+ bool disable_second_tile;
unsigned int disable_colorimetry;
uint8_t blankstream_before_otg_off;
bool oled_optimize_display_on;
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 65/70] drm/amd/display: Reduce DML reinitialization when params don't change
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (63 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 64/70] drm/amd/display: hide Apple Studio Display secondary tile Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 66/70] drm/amd/display: Add DCHUBBUB_HW_DEBUG offset/mask Wayne Lin
` (4 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Clara Wong, Austin Zheng,
Taimur Hassan
From: Clara Wong <Clara.Wong@amd.com>
[WHY]
Reinitializing DML causes an extra ~8s delay in gaming mode preset switches on some systems
[HOW]
Don't reinitialize DML unless params/caps have changed
Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Reviewed-by: Taimur Hassan <syed.hassan@amd.com>
Signed-off-by: Clara Wong <Clara.Wong@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../display/dc/dml2_0/dml21/dml21_wrapper_fpu.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
index a975d36ce15d..4e3d54c92e32 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
@@ -45,7 +45,22 @@ void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const stru
void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config)
{
- dml21_init(in_dc, dml_ctx, config);
+ struct dml2_instance *dml2 = dml_ctx->v21.dml_init.dml2_instance;
+
+ dml21_populate_configuration_options(in_dc, dml_ctx, config);
+
+ dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, &dml_ctx->config, in_dc);
+
+ // Skip full re-initialization if soc_bb, ip_caps and pmo_options are unchanged
+ if (memcmp(&dml2->soc_bbox, &dml_ctx->v21.dml_init.soc_bb,
+ sizeof(struct dml2_soc_bb)) == 0 &&
+ memcmp(&dml2->ip_caps, &dml_ctx->v21.dml_init.ip_caps,
+ sizeof(struct dml2_ip_capabilities)) == 0 &&
+ memcmp(&dml2->pmo_options, &dml_ctx->v21.dml_init.options.pmo_options,
+ sizeof(struct dml2_pmo_options)) == 0)
+ return;
+
+ dml2_initialize_instance(&dml_ctx->v21.dml_init);
}
static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state,
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 66/70] drm/amd/display: Add DCHUBBUB_HW_DEBUG offset/mask
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (64 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 65/70] drm/amd/display: Reduce DML reinitialization when params don't change Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 67/70] drm/amd/display: Fix missing dc_3dlut forward declaration Wayne Lin
` (3 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Matthew Stewart, Ovidiu Bunea
From: Matthew Stewart <Matthew.Stewart2@amd.com>
Add missing register defines for DCN42B.
Reviewed-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Matthew Stewart <Matthew.Stewart2@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.h b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.h
index 5ae9fb76c675..ddc614c98234 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.h
@@ -340,7 +340,12 @@
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_CSTATE_DEEPSLEEP_LEGACY_MODE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_HOSTVM_CNTL, DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, mask_sh),\
- HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, mask_sh)
+ HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, mask_sh), \
+ HUBBUB_SF(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, mask_sh)
+
+#define DCHUBBUB_CTRL_STATUS__DCHUBBUB_HW_DEBUG__SHIFT 0x4
+
+#define DCHUBBUB_CTRL_STATUS__DCHUBBUB_HW_DEBUG_MASK 0x3FFFFFF0L
void hubbub35_construct(struct dcn20_hubbub *hubbub2,
struct dc_context *ctx,
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 67/70] drm/amd/display: Fix missing dc_3dlut forward declaration
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (65 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 66/70] drm/amd/display: Add DCHUBBUB_HW_DEBUG offset/mask Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 68/70] drm/amd/display: Flush IRQ workqueue in schedule-work tests Wayne Lin
` (2 subsequent siblings)
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHY]
The __set_colorop_3dlut() prototype in the KUnit-test section of
amdgpu_dm_color.h references struct dc_3dlut, but no forward
declaration for that struct exists in the header.
The forward declaration was originally present but was repurposed
into struct dc_plane_cm when the adjacent amdgpu_dm_atomic_lut3d()
prototype was updated, leaving __set_colorop_3dlut() without a
declaration for struct dc_3dlut.
[HOW]
Add back forward declaration of struct dc_3dlut alongside the other
forward declarations at the top of the header.
Fixes: 67b15f11ae60 ("drm/amd/display: Fix conflicting types for dc_plane_cm functions")
Cc: Alex Hung <alex.hung@amd.com>
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
index 1a8b06bdaf44..cec23a020c3d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
@@ -44,6 +44,7 @@ struct dc_plane_state;
struct fixed31_32;
struct tetrahedral_params;
struct dc_transfer_func;
+struct dc_3dlut;
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 68/70] drm/amd/display: Flush IRQ workqueue in schedule-work tests
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (66 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 67/70] drm/amd/display: Fix missing dc_3dlut forward declaration Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 15:38 ` McRae, Geoffrey
2026-07-15 13:38 ` [PATCH 69/70] drm/amd/display: Add SPL UPSP upsampling and YUV422 scaling support Wayne Lin
2026-07-15 13:38 ` [PATCH 70/70] drm/amd/display: Promote DC to 3.2.390 Wayne Lin
69 siblings, 1 reply; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Geoffrey McRae,
Bhawanpreet Lakha
From: Alex Hung <alex.hung@amd.com>
[WHAT]
The tests dm_test_irq_schedule_work_queues_handler,
dm_test_irq_schedule_work_requeue_fallback, and
dm_test_irq_handler_dispatches_work relied on amdgpu_dm_irq_fini()
running each pending low-context work item before freeing the
handlers, and only checked the handler counts afterwards.
amdgpu_dm_irq_fini() now cancels pending work with
cancel_work_sync() instead of flushing it, so work that has not yet
started never runs and the counts stay below the expected values,
failing the tests.
Flush the private DM IRQ workqueue (adev->dm.irq_wq) so the
scheduled handlers complete, check the counts, then tear down.
Flushing this driver-owned workqueue is allowed, unlike the
system-wide workqueues.
Fixes: 258df8e4f860 ("drm/amd/display: Fix DM IRQ teardown races")
Cc: Geoffrey McRae <geoffrey.mcrae@amd.com>
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 31 +++++++++++++------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
index ed20e278742d..dc7ef0523b8f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
@@ -1842,12 +1842,15 @@ static void dm_test_irq_schedule_work_queues_handler(struct kunit *test)
amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
/*
- * Low-context work runs asynchronously on system_highpri_wq.
- * amdgpu_dm_irq_fini() flushes each pending work item before freeing
- * the handlers, so the handler is guaranteed to have run afterwards.
+ * Low-context work runs asynchronously on the DM IRQ workqueue.
+ * Flush it so the handler completes before we check the count;
+ * amdgpu_dm_irq_fini() cancels (rather than runs) any work that is
+ * still pending, so the flush must happen first.
*/
- amdgpu_dm_irq_fini(adev);
+ flush_workqueue(adev->dm.irq_wq);
KUNIT_EXPECT_EQ(test, count, 1);
+
+ amdgpu_dm_irq_fini(adev);
}
/**
@@ -1858,7 +1861,7 @@ static void dm_test_irq_schedule_work_queues_handler(struct kunit *test)
* schedule before the work has run makes queue_work() fail for the
* still-pending item, forcing amdgpu_dm_irq_schedule_work() into the fallback
* that allocates and queues a fresh handler copy. Both work items run when
- * amdgpu_dm_irq_fini() flushes the queue, so the handler fires twice.
+ * the DM IRQ workqueue is flushed, so the handler fires twice.
*/
static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test)
{
@@ -1880,8 +1883,15 @@ static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test)
amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
- amdgpu_dm_irq_fini(adev);
+ /*
+ * Flush the DM IRQ workqueue so both work items run before we check
+ * the count; amdgpu_dm_irq_fini() would cancel any still-pending work
+ * instead of running it.
+ */
+ flush_workqueue(adev->dm.irq_wq);
KUNIT_EXPECT_EQ(test, count, 2);
+
+ amdgpu_dm_irq_fini(adev);
}
/* Tests for amdgpu_dm_set_hpd_irq_state() */
@@ -3855,11 +3865,14 @@ static void dm_test_irq_handler_dispatches_work(struct kunit *test)
KUNIT_EXPECT_EQ(test, high_count, 1);
/*
- * Low-context work runs asynchronously; amdgpu_dm_irq_fini() flushes
- * each pending work item before freeing, so it has run afterwards.
+ * Low-context work runs asynchronously; flush the DM IRQ workqueue so
+ * it completes before we check the count. amdgpu_dm_irq_fini() cancels
+ * any still-pending work rather than running it.
*/
- amdgpu_dm_irq_fini(adev);
+ flush_workqueue(adev->dm.irq_wq);
KUNIT_EXPECT_EQ(test, low_count, 1);
+
+ amdgpu_dm_irq_fini(adev);
}
/* Tests for dm_handle_vmin_vmax_update() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* Re: [PATCH 68/70] drm/amd/display: Flush IRQ workqueue in schedule-work tests
2026-07-15 13:38 ` [PATCH 68/70] drm/amd/display: Flush IRQ workqueue in schedule-work tests Wayne Lin
@ 2026-07-15 15:38 ` McRae, Geoffrey
0 siblings, 0 replies; 72+ messages in thread
From: McRae, Geoffrey @ 2026-07-15 15:38 UTC (permalink / raw)
To: Lin, Wayne, amd-gfx@lists.freedesktop.org
Cc: Wentland, Harry, Li, Sun peng (Leo), Pillai, Aurabindo, Li, Roman,
Chung, ChiaHsuan (Tom), Zuo, Jerry, Wheeler, Daniel, Wu, Ray,
LIPSKI, IVAN, Hung, Alex, Lin, Ping Lei, Chen, Chen-Yu,
Lakha, Bhawanpreet
LGTM
________________________________________
From: Wayne Lin <Wayne.Lin@amd.com>
Sent: Wednesday, 15 July 2026 11:38 PM
To: amd-gfx@lists.freedesktop.org
Cc: Wentland, Harry; Li, Sun peng (Leo); Pillai, Aurabindo; Li, Roman; Lin, Wayne; Chung, ChiaHsuan (Tom); Zuo, Jerry; Wheeler, Daniel; Wu, Ray; LIPSKI, IVAN; Hung, Alex; Lin, Ping Lei; Chen, Chen-Yu; McRae, Geoffrey; Lakha, Bhawanpreet
Subject: [PATCH 68/70] drm/amd/display: Flush IRQ workqueue in schedule-work tests
From: Alex Hung <alex.hung@amd.com>
[WHAT]
The tests dm_test_irq_schedule_work_queues_handler,
dm_test_irq_schedule_work_requeue_fallback, and
dm_test_irq_handler_dispatches_work relied on amdgpu_dm_irq_fini()
running each pending low-context work item before freeing the
handlers, and only checked the handler counts afterwards.
amdgpu_dm_irq_fini() now cancels pending work with
cancel_work_sync() instead of flushing it, so work that has not yet
started never runs and the counts stay below the expected values,
failing the tests.
Flush the private DM IRQ workqueue (adev->dm.irq_wq) so the
scheduled handlers complete, check the counts, then tear down.
Flushing this driver-owned workqueue is allowed, unlike the
system-wide workqueues.
Fixes: 258df8e4f860 ("drm/amd/display: Fix DM IRQ teardown races")
Cc: Geoffrey McRae <geoffrey.mcrae@amd.com>
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 31 +++++++++++++------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
index ed20e278742d..dc7ef0523b8f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
@@ -1842,12 +1842,15 @@ static void dm_test_irq_schedule_work_queues_handler(struct kunit *test)
amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
/*
- * Low-context work runs asynchronously on system_highpri_wq.
- * amdgpu_dm_irq_fini() flushes each pending work item before freeing
- * the handlers, so the handler is guaranteed to have run afterwards.
+ * Low-context work runs asynchronously on the DM IRQ workqueue.
+ * Flush it so the handler completes before we check the count;
+ * amdgpu_dm_irq_fini() cancels (rather than runs) any work that is
+ * still pending, so the flush must happen first.
*/
- amdgpu_dm_irq_fini(adev);
+ flush_workqueue(adev->dm.irq_wq);
KUNIT_EXPECT_EQ(test, count, 1);
+
+ amdgpu_dm_irq_fini(adev);
}
/**
@@ -1858,7 +1861,7 @@ static void dm_test_irq_schedule_work_queues_handler(struct kunit *test)
* schedule before the work has run makes queue_work() fail for the
* still-pending item, forcing amdgpu_dm_irq_schedule_work() into the fallback
* that allocates and queues a fresh handler copy. Both work items run when
- * amdgpu_dm_irq_fini() flushes the queue, so the handler fires twice.
+ * the DM IRQ workqueue is flushed, so the handler fires twice.
*/
static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test)
{
@@ -1880,8 +1883,15 @@ static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test)
amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
- amdgpu_dm_irq_fini(adev);
+ /*
+ * Flush the DM IRQ workqueue so both work items run before we check
+ * the count; amdgpu_dm_irq_fini() would cancel any still-pending work
+ * instead of running it.
+ */
+ flush_workqueue(adev->dm.irq_wq);
KUNIT_EXPECT_EQ(test, count, 2);
+
+ amdgpu_dm_irq_fini(adev);
}
/* Tests for amdgpu_dm_set_hpd_irq_state() */
@@ -3855,11 +3865,14 @@ static void dm_test_irq_handler_dispatches_work(struct kunit *test)
KUNIT_EXPECT_EQ(test, high_count, 1);
/*
- * Low-context work runs asynchronously; amdgpu_dm_irq_fini() flushes
- * each pending work item before freeing, so it has run afterwards.
+ * Low-context work runs asynchronously; flush the DM IRQ workqueue so
+ * it completes before we check the count. amdgpu_dm_irq_fini() cancels
+ * any still-pending work rather than running it.
*/
- amdgpu_dm_irq_fini(adev);
+ flush_workqueue(adev->dm.irq_wq);
KUNIT_EXPECT_EQ(test, low_count, 1);
+
+ amdgpu_dm_irq_fini(adev);
}
/* Tests for dm_handle_vmin_vmax_update() */
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 69/70] drm/amd/display: Add SPL UPSP upsampling and YUV422 scaling support
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (67 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 68/70] drm/amd/display: Flush IRQ workqueue in schedule-work tests Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
2026-07-15 13:38 ` [PATCH 70/70] drm/amd/display: Promote DC to 3.2.390 Wayne Lin
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wayne Lin
- Add YUV422/YUV444 pixel format definitions
- Handle YUV422 chroma scaling ratios
- Use separate horizontal and vertical viewport divisors
- Add UPSP upsampling register programming
- Refine tap selection for horizontally and vertically subsampled formats
Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c | 202 ++++++++++++++++--
.../drm/amd/display/dc/sspl/dc_spl_types.h | 58 ++++-
2 files changed, 234 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c
index d8aebaff7c3f..1f1318769d5b 100644
--- a/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c
+++ b/drivers/gpu/drm/amd/display/dc/sspl/dc_spl.c
@@ -9,7 +9,6 @@
#define IDENTITY_RATIO(ratio) (SPL_NAMESPACE(spl_fixpt_u3d19(ratio)) == (1 << 19))
#define MIN_VIEWPORT_SIZE 12
-
static bool spl_is_yuv420(enum spl_pixel_format format)
{
if ((format >= SPL_PIXEL_FORMAT_420BPP8) &&
@@ -19,6 +18,15 @@ static bool spl_is_yuv420(enum spl_pixel_format format)
return false;
}
+static bool spl_is_yuv422(enum spl_pixel_format format)
+{
+ if ((format >= SPL_PIXEL_FORMAT_422BPP8) &&
+ (format <= SPL_PIXEL_FORMAT_422BPP12))
+ return true;
+
+ return false;
+}
+
static bool spl_is_rgb8(enum spl_pixel_format format)
{
if (format == SPL_PIXEL_FORMAT_ARGB8888)
@@ -468,6 +476,12 @@ static void spl_calculate_scaling_ratios(struct spl_in *spl_in,
if (spl_is_yuv420(spl_in->basic_in.format)) {
spl_scratch->scl_data.ratios.horz_c.value /= 2;
spl_scratch->scl_data.ratios.vert_c.value /= 2;
+ } else if (spl_is_yuv422(spl_in->basic_in.format)) {
+ if (spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_90 ||
+ spl_in->basic_in.rotation == SPL_ROTATION_ANGLE_270)
+ spl_scratch->scl_data.ratios.vert_c.value /= 2;
+ else
+ spl_scratch->scl_data.ratios.horz_c.value /= 2;
}
spl_scratch->scl_data.ratios.horz = spl_fixpt_truncate(
spl_scratch->scl_data.ratios.horz, 19);
@@ -612,7 +626,8 @@ static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,
struct spl_rect recout_clip_in_recout_dst;
struct spl_rect overlap_in_active_timing;
struct spl_rect odm_slice = calculate_odm_slice_in_timing_active(spl_in);
- int vpc_div = spl_is_subsampled_format(spl_in->basic_in.format) ? 2 : 1;
+ int vp_hc_div = spl_is_subsampled_format(spl_in->basic_in.format) ? 2 : 1;
+ int vp_vc_div = spl_is_yuv420(spl_in->basic_in.format) ? 2 : 1;
bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
struct spl_fixed31_32 init_adj_h = spl_fixpt_zero;
struct spl_fixed31_32 init_adj_v = spl_fixpt_zero;
@@ -667,6 +682,7 @@ static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,
if (orthogonal_rotation) {
spl_swap(src.width, src.height);
spl_swap(flip_vert_scan_dir, flip_horz_scan_dir);
+ spl_swap(vp_hc_div, vp_vc_div);
spl_swap(init_adj_h, init_adj_v);
}
@@ -685,7 +701,7 @@ static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,
flip_horz_scan_dir,
recout_clip_in_recout_dst.x,
spl_scratch->scl_data.recout.width,
- src.width / vpc_div,
+ src.width / vp_hc_div,
spl_scratch->scl_data.taps.h_taps_c,
spl_scratch->scl_data.ratios.horz_c,
init_adj_h,
@@ -707,7 +723,7 @@ static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,
flip_vert_scan_dir,
recout_clip_in_recout_dst.y,
spl_scratch->scl_data.recout.height,
- src.height / vpc_div,
+ src.height / vp_vc_div,
spl_scratch->scl_data.taps.v_taps_c,
spl_scratch->scl_data.ratios.vert_c,
init_adj_v,
@@ -719,12 +735,13 @@ static void spl_calculate_inits_and_viewports(struct spl_in *spl_in,
spl_swap(spl_scratch->scl_data.viewport.width, spl_scratch->scl_data.viewport.height);
spl_swap(spl_scratch->scl_data.viewport_c.x, spl_scratch->scl_data.viewport_c.y);
spl_swap(spl_scratch->scl_data.viewport_c.width, spl_scratch->scl_data.viewport_c.height);
+ spl_swap(vp_hc_div, vp_vc_div);
}
spl_scratch->scl_data.viewport.x += src.x;
spl_scratch->scl_data.viewport.y += src.y;
- SPL_ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
- spl_scratch->scl_data.viewport_c.x += src.x / vpc_div;
- spl_scratch->scl_data.viewport_c.y += src.y / vpc_div;
+ SPL_ASSERT(src.x % vp_hc_div == 0 && src.y % vp_vc_div == 0);
+ spl_scratch->scl_data.viewport_c.x += src.x / vp_hc_div;
+ spl_scratch->scl_data.viewport_c.y += src.y / vp_vc_div;
}
static void spl_handle_3d_recout(struct spl_in *spl_in, struct spl_rect *recout)
@@ -760,6 +777,7 @@ static enum scl_mode spl_get_dscl_mode(const struct spl_in *spl_in,
const struct spl_scaler_data *data,
bool enable_isharp, bool enable_easf)
{
+ (void)enable_easf;
const long long one = spl_fixpt_one.value;
enum spl_pixel_format pixel_format = spl_in->basic_in.format;
@@ -894,7 +912,8 @@ static bool spl_get_isharp_en(struct spl_in *spl_in,
static void spl_get_taps_non_adaptive_scaler(
struct spl_scratch *spl_scratch,
const struct spl_taps *in_taps,
- bool is_subsampled)
+ bool is_horz_subsampled,
+ bool is_vert_subsampled)
{
bool check_max_downscale = false;
@@ -959,11 +978,10 @@ static void spl_get_taps_non_adaptive_scaler(
spl_scratch->scl_data.taps.h_taps = 1;
if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))
spl_scratch->scl_data.taps.v_taps = 1;
- if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c) && !is_subsampled)
+ if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c) && !is_horz_subsampled)
spl_scratch->scl_data.taps.h_taps_c = 1;
- if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c) && !is_subsampled)
+ if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c) && !is_vert_subsampled)
spl_scratch->scl_data.taps.v_taps_c = 1;
-
}
/* Calculate optimal number of taps */
@@ -977,12 +995,13 @@ static bool spl_get_optimal_number_of_taps(
unsigned int min_taps_y, min_taps_c;
enum lb_memory_config lb_config;
bool skip_easf = false;
- bool is_subsampled = spl_is_subsampled_format(spl_in->basic_in.format);
+ bool is_horz_subsampled = spl_is_subsampled_format(spl_in->basic_in.format);
+ bool is_vert_subsampled = spl_is_yuv420(spl_in->basic_in.format);
if (spl_scratch->scl_data.viewport.width > spl_scratch->scl_data.h_active &&
max_downscale_src_width != 0 &&
spl_scratch->scl_data.viewport.width > max_downscale_src_width) {
- spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps, is_subsampled);
+ spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps, is_horz_subsampled, is_vert_subsampled);
*enable_easf_v = false;
*enable_easf_h = false;
*enable_isharp = false;
@@ -991,7 +1010,7 @@ static bool spl_get_optimal_number_of_taps(
/* Disable adaptive scaler and sharpener when integer scaling is enabled */
if (spl_in->scaling_quality.integer_scaling) {
- spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps, is_subsampled);
+ spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps, is_horz_subsampled, is_vert_subsampled);
*enable_easf_v = false;
*enable_easf_h = false;
*enable_isharp = false;
@@ -1007,15 +1026,15 @@ static bool spl_get_optimal_number_of_taps(
* taps = 4 for upscaling
*/
if (skip_easf) {
- spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps, is_subsampled);
+ spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps, is_horz_subsampled, is_vert_subsampled);
}
else {
- if (spl_is_video_format(spl_in->basic_in.format)) {
+ if (spl_is_subsampled_format(spl_in->basic_in.format)) {
spl_scratch->scl_data.taps.h_taps = 6;
spl_scratch->scl_data.taps.v_taps = 6;
spl_scratch->scl_data.taps.h_taps_c = 4;
spl_scratch->scl_data.taps.v_taps_c = 4;
- } else { /* RGB */
+ } else { /* RGB / YUV444 */
spl_scratch->scl_data.taps.h_taps = 6;
spl_scratch->scl_data.taps.v_taps = 6;
spl_scratch->scl_data.taps.h_taps_c = 6;
@@ -1149,10 +1168,10 @@ static bool spl_get_optimal_number_of_taps(
(IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))) {
spl_scratch->scl_data.taps.h_taps = 1;
spl_scratch->scl_data.taps.v_taps = 1;
- if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c) && !is_subsampled)
+ if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c) && !is_horz_subsampled)
spl_scratch->scl_data.taps.h_taps_c = 1;
- if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c) && !is_subsampled)
+ if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c) && !is_vert_subsampled)
spl_scratch->scl_data.taps.v_taps_c = 1;
*enable_easf_v = false;
@@ -1166,11 +1185,11 @@ static bool spl_get_optimal_number_of_taps(
(IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert)))
spl_scratch->scl_data.taps.v_taps = 1;
- if ((!*enable_easf_h) && !is_subsampled &&
+ if ((!*enable_easf_h) && !is_horz_subsampled &&
(IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c)))
spl_scratch->scl_data.taps.h_taps_c = 1;
- if ((!*enable_easf_v) && !is_subsampled &&
+ if ((!*enable_easf_v) && !is_vert_subsampled &&
(IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c)))
spl_scratch->scl_data.taps.v_taps_c = 1;
@@ -1693,6 +1712,7 @@ static void spl_set_isharp_data(struct dscl_prog_data *dscl_prog_data,
const struct spl_scaler_data *data, struct spl_fixed31_32 ratio,
enum system_setup setup, enum scale_to_sharpness_policy scale_to_sharpness_policy)
{
+ (void)format;
/* Turn off sharpener if not required */
if (!enable_isharp) {
dscl_prog_data->isharp_en = 0;
@@ -1823,6 +1843,144 @@ static void spl_set_isharp_data(struct dscl_prog_data *dscl_prog_data,
SPL_NAMESPACE(spl_set_blur_scale_data(dscl_prog_data, data));
}
+static void determine_upsp_values(struct spl_in *spl_in, struct dscl_prog_data *dscl_prog_data)
+{
+ dscl_prog_data->upsp_mode = spl_in->upsp_mode;
+
+ if (dscl_prog_data->upsp_mode == UPSP_BYPASS) { //Set all UPSP register fields to 0 if bypass
+ dscl_prog_data->upsp_v_num_taps = UPSP_2_TAPS;
+ dscl_prog_data->upsp_h_num_taps = UPSP_2_TAPS;
+ dscl_prog_data->upsp_boundary_mode = UPSP_BOUNDARY_EDGE;
+ dscl_prog_data->upsp_v_init_int = 0x0;
+ dscl_prog_data->upsp_v_init_frac = 0x0;
+ dscl_prog_data->upsp_v_coef_tap0_p0 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap1_p0 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap2_p0 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap3_p0 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap0_p1 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap1_p1 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap2_p1 = 0x0;
+ dscl_prog_data->upsp_v_coef_tap3_p1 = 0x0;
+ dscl_prog_data->upsp_h_init_int = 0x0;
+ dscl_prog_data->upsp_h_init_frac = 0x0;
+ dscl_prog_data->upsp_h_coef_tap0_p0 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap1_p0 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap2_p0 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap3_p0 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap0_p1 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap1_p1 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap2_p1 = 0x0;
+ dscl_prog_data->upsp_h_coef_tap3_p1 = 0x0;
+ dscl_prog_data->upsp_clamp_max = 0x0;
+ dscl_prog_data->upsp_clamp_min = 0x0;
+ } else {
+ dscl_prog_data->upsp_v_num_taps = UPSP_4_TAPS;
+ dscl_prog_data->upsp_h_num_taps = UPSP_4_TAPS;
+ dscl_prog_data->upsp_boundary_mode = UPSP_BOUNDARY_EDGE;
+ dscl_prog_data->upsp_clamp_max = 0xFFF;//4095
+ dscl_prog_data->upsp_clamp_min = 0x0;
+
+ if (spl_in->basic_in.cositing == CHROMA_COSITING_TOPLEFT) { //Vertical Subsampling: Co-sited
+ if (dscl_prog_data->upsp_v_num_taps == UPSP_4_TAPS) {
+ dscl_prog_data->upsp_v_init_int = 0x3;
+ dscl_prog_data->upsp_v_init_frac = 0x0;
+ dscl_prog_data->upsp_v_coef_tap0_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap1_p0 = 0x40;
+ dscl_prog_data->upsp_v_coef_tap2_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap3_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap0_p1 = 0xFC;
+ dscl_prog_data->upsp_v_coef_tap1_p1 = 0x24;
+ dscl_prog_data->upsp_v_coef_tap2_p1 = 0x24;
+ dscl_prog_data->upsp_v_coef_tap3_p1 = 0xFC;
+ } else { //2 taps
+ dscl_prog_data->upsp_v_init_int = 0x2;
+ dscl_prog_data->upsp_v_init_frac = 0x0;
+ dscl_prog_data->upsp_v_coef_tap0_p0 = 0x40;
+ dscl_prog_data->upsp_v_coef_tap1_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap2_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap3_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap0_p1 = 0x20;
+ dscl_prog_data->upsp_v_coef_tap1_p1 = 0x20;
+ dscl_prog_data->upsp_v_coef_tap2_p1 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap3_p1 = 0x00;
+ }
+ } else { //Vertical Subsampling: Interstitial
+ if (dscl_prog_data->upsp_v_num_taps == UPSP_4_TAPS) {
+ dscl_prog_data->upsp_v_init_int = 0x2;
+ dscl_prog_data->upsp_v_init_frac = 0x1;
+ dscl_prog_data->upsp_v_coef_tap0_p0 = 0xFB;
+ dscl_prog_data->upsp_v_coef_tap1_p0 = 0x2F;
+ dscl_prog_data->upsp_v_coef_tap2_p0 = 0x19;
+ dscl_prog_data->upsp_v_coef_tap3_p0 = 0xFD;
+ dscl_prog_data->upsp_v_coef_tap0_p1 = 0xFD;
+ dscl_prog_data->upsp_v_coef_tap1_p1 = 0x19;
+ dscl_prog_data->upsp_v_coef_tap2_p1 = 0x2F;
+ dscl_prog_data->upsp_v_coef_tap3_p1 = 0xFB;
+ } else { //2 taps
+ dscl_prog_data->upsp_v_init_int = 0x1;
+ dscl_prog_data->upsp_v_init_frac = 0x1;
+ dscl_prog_data->upsp_v_coef_tap0_p0 = 0x28;
+ dscl_prog_data->upsp_v_coef_tap1_p0 = 0x18;
+ dscl_prog_data->upsp_v_coef_tap2_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap3_p0 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap0_p1 = 0x18;
+ dscl_prog_data->upsp_v_coef_tap1_p1 = 0x28;
+ dscl_prog_data->upsp_v_coef_tap2_p1 = 0x00;
+ dscl_prog_data->upsp_v_coef_tap3_p1 = 0x00;
+ }
+ }
+ if (spl_in->basic_in.cositing == CHROMA_COSITING_LEFT || spl_in->basic_in.cositing == CHROMA_COSITING_TOPLEFT) { //Horizontal Subsampling: Co-sited
+ if (dscl_prog_data->upsp_h_num_taps == UPSP_4_TAPS) {
+ dscl_prog_data->upsp_h_init_int = 0x3;
+ dscl_prog_data->upsp_h_init_frac = 0x0;
+ dscl_prog_data->upsp_h_coef_tap0_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap1_p0 = 0x40;
+ dscl_prog_data->upsp_h_coef_tap2_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap3_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap0_p1 = 0xFC;
+ dscl_prog_data->upsp_h_coef_tap1_p1 = 0x24;
+ dscl_prog_data->upsp_h_coef_tap2_p1 = 0x24;
+ dscl_prog_data->upsp_h_coef_tap3_p1 = 0xFC;
+ } else { //2 taps
+ dscl_prog_data->upsp_h_init_int = 0x2;
+ dscl_prog_data->upsp_h_init_frac = 0x0;
+ dscl_prog_data->upsp_h_coef_tap0_p0 = 0x40;
+ dscl_prog_data->upsp_h_coef_tap1_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap2_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap3_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap0_p1 = 0x20;
+ dscl_prog_data->upsp_h_coef_tap1_p1 = 0x20;
+ dscl_prog_data->upsp_h_coef_tap2_p1 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap3_p1 = 0x00;
+ }
+ } else { //Horizontal Subsampling: Interstitial
+ if (dscl_prog_data->upsp_h_num_taps == UPSP_4_TAPS) {
+ dscl_prog_data->upsp_h_init_int = 0x2;
+ dscl_prog_data->upsp_h_init_frac = 0x1;
+ dscl_prog_data->upsp_h_coef_tap0_p0 = 0xFB;
+ dscl_prog_data->upsp_h_coef_tap1_p0 = 0x2F;
+ dscl_prog_data->upsp_h_coef_tap2_p0 = 0x19;
+ dscl_prog_data->upsp_h_coef_tap3_p0 = 0xFD;
+ dscl_prog_data->upsp_h_coef_tap0_p1 = 0xFD;
+ dscl_prog_data->upsp_h_coef_tap1_p1 = 0x19;
+ dscl_prog_data->upsp_h_coef_tap2_p1 = 0x2F;
+ dscl_prog_data->upsp_h_coef_tap3_p1 = 0xFB;
+ } else { //2 taps
+ dscl_prog_data->upsp_h_init_int = 0x1;
+ dscl_prog_data->upsp_h_init_frac = 0x1;
+ dscl_prog_data->upsp_h_coef_tap0_p0 = 0x28;
+ dscl_prog_data->upsp_h_coef_tap1_p0 = 0x18;
+ dscl_prog_data->upsp_h_coef_tap2_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap3_p0 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap0_p1 = 0x18;
+ dscl_prog_data->upsp_h_coef_tap1_p1 = 0x28;
+ dscl_prog_data->upsp_h_coef_tap2_p1 = 0x00;
+ dscl_prog_data->upsp_h_coef_tap3_p1 = 0x00;
+ }
+ }
+ }
+}
+
/* Calculate recout, scaling ratio, and viewport, then get optimal number of taps */
static bool spl_calculate_number_of_taps(struct spl_in *spl_in, struct spl_scratch *spl_scratch, struct spl_out *spl_out,
bool *enable_easf_v, bool *enable_easf_h, bool *enable_isharp)
@@ -1865,6 +2023,8 @@ bool SPL_NAMESPACE(spl_calculate_scaler_params(struct spl_in *spl_in, struct spl
bool enable_isharp = false;
const struct spl_scaler_data *data = &spl_scratch.scl_data;
+ determine_upsp_values(spl_in, spl_out->dscl_prog_data);
+
res = spl_calculate_number_of_taps(spl_in, &spl_scratch, spl_out,
&enable_easf_v, &enable_easf_h, &enable_isharp);
diff --git a/drivers/gpu/drm/amd/display/dc/sspl/dc_spl_types.h b/drivers/gpu/drm/amd/display/dc/sspl/dc_spl_types.h
index 20e4e52a77ac..b24f1ef3fe17 100644
--- a/drivers/gpu/drm/amd/display/dc/sspl/dc_spl_types.h
+++ b/drivers/gpu/drm/amd/display/dc/sspl/dc_spl_types.h
@@ -62,17 +62,21 @@ enum spl_pixel_format {
/*video*/
SPL_PIXEL_FORMAT_420BPP8,
SPL_PIXEL_FORMAT_420BPP10,
+ SPL_PIXEL_FORMAT_422BPP8,
+ SPL_PIXEL_FORMAT_422BPP10,
+ SPL_PIXEL_FORMAT_422BPP12,
+ SPL_PIXEL_FORMAT_444BPP8,
+ SPL_PIXEL_FORMAT_444BPP10,
/*end of pixel format definition*/
SPL_PIXEL_FORMAT_GRPH_BEGIN = SPL_PIXEL_FORMAT_INDEX8,
SPL_PIXEL_FORMAT_GRPH_END = SPL_PIXEL_FORMAT_FP16,
SPL_PIXEL_FORMAT_SUBSAMPLED_BEGIN = SPL_PIXEL_FORMAT_420BPP8,
- SPL_PIXEL_FORMAT_SUBSAMPLED_END = SPL_PIXEL_FORMAT_420BPP10,
+ SPL_PIXEL_FORMAT_SUBSAMPLED_END = SPL_PIXEL_FORMAT_422BPP12,
SPL_PIXEL_FORMAT_VIDEO_BEGIN = SPL_PIXEL_FORMAT_420BPP8,
- SPL_PIXEL_FORMAT_VIDEO_END = SPL_PIXEL_FORMAT_420BPP10,
+ SPL_PIXEL_FORMAT_VIDEO_END = SPL_PIXEL_FORMAT_444BPP10,
SPL_PIXEL_FORMAT_INVALID,
SPL_PIXEL_FORMAT_UNKNOWN
};
-
enum lb_memory_config {
/* Enable all 3 pieces of memory */
LB_MEMORY_CONFIG_0 = 0,
@@ -88,7 +92,6 @@ enum lb_memory_config {
*/
LB_MEMORY_CONFIG_3 = 3
};
-
/* Rotation angle */
enum spl_rotation_angle {
SPL_ROTATION_ANGLE_0 = 0,
@@ -128,6 +131,23 @@ enum chroma_cositing {
CHROMA_COSITING_COUNT
};
+enum upsp_mode {
+ UPSP_BYPASS = 0,
+ UPSP_HORIZONTAL_UPSAMPLING_ONLY,
+ UPSP_VERTICAL_UPSAMPLING_ONLY,
+ UPSP_HORIZONTAL_VERTICAL_UPSAMPLING
+};
+
+enum upsp_num_taps {
+ UPSP_2_TAPS,
+ UPSP_4_TAPS
+};
+
+enum upsp_boundary_mode {
+ UPSP_BOUNDARY_EDGE, //Replace out of bound samples with the edge samples
+ UPSP_BOUNDARY_BLACK //Replace out of bound samples with black as 12bpc(0x800)
+};
+
// Scratch space for calculating scaler params
struct spl_scaler_data {
int h_active;
@@ -253,7 +273,7 @@ enum isharp_en {
#define ISHARP_LUT_TABLE_SIZE 32
// Below struct holds values that can be directly used to program
// hardware registers. No conversion/clamping is required
-struct dscl_prog_data {
+struct dscl_prog_data {
struct spl_rect recout; // RECOUT - set based on scl_data.recout
struct mpc_size mpc_size;
uint32_t dscl_mode;
@@ -395,6 +415,33 @@ struct dscl_prog_data {
uint32_t easf_matrix_c1;
uint32_t easf_matrix_c2;
uint32_t easf_matrix_c3;
+ // UPSP registers
+ uint32_t upsp_mode;//UPSP_MODE
+ uint32_t upsp_v_num_taps;
+ uint32_t upsp_v_init_int;
+ uint32_t upsp_v_init_frac;
+ uint32_t upsp_h_num_taps;
+ uint32_t upsp_h_init_int;
+ uint32_t upsp_h_init_frac;
+ uint32_t upsp_boundary_mode;
+ uint32_t upsp_v_coef_tap0_p0;//UPSP_V_COEF_P0
+ uint32_t upsp_v_coef_tap1_p0;
+ uint32_t upsp_v_coef_tap2_p0;
+ uint32_t upsp_v_coef_tap3_p0;
+ uint32_t upsp_v_coef_tap0_p1;//UPSP_V_COEF_P1
+ uint32_t upsp_v_coef_tap1_p1;
+ uint32_t upsp_v_coef_tap2_p1;
+ uint32_t upsp_v_coef_tap3_p1;
+ uint32_t upsp_h_coef_tap0_p0;//UPSP_H_COEF_P0
+ uint32_t upsp_h_coef_tap1_p0;
+ uint32_t upsp_h_coef_tap2_p0;
+ uint32_t upsp_h_coef_tap3_p0;
+ uint32_t upsp_h_coef_tap0_p1;//UPSP_H_COEF_P1
+ uint32_t upsp_h_coef_tap1_p1;
+ uint32_t upsp_h_coef_tap2_p1;
+ uint32_t upsp_h_coef_tap3_p1;
+ uint32_t upsp_clamp_max;//UPSP_CLAMP
+ uint32_t upsp_clamp_min;
// iSharp
uint32_t isharp_en; // ISHARP_EN
struct isharp_noise_det isharp_noise_det; // ISHARP_NOISEDET
@@ -554,6 +601,7 @@ struct spl_in {
int min_viewport_size;
int sdr_white_level_nits;
enum sharpen_policy sharpen_policy;
+ enum upsp_mode upsp_mode;
};
// end of SPL inputs
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread* [PATCH 70/70] drm/amd/display: Promote DC to 3.2.390
2026-07-15 13:37 [PATCH 00/70] DC Patches July 13, 2026 Wayne Lin
` (68 preceding siblings ...)
2026-07-15 13:38 ` [PATCH 69/70] drm/amd/display: Add SPL UPSP upsampling and YUV422 scaling support Wayne Lin
@ 2026-07-15 13:38 ` Wayne Lin
69 siblings, 0 replies; 72+ messages in thread
From: Wayne Lin @ 2026-07-15 13:38 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Taimur Hassan
From: Taimur Hassan <Syed.Hassan@amd.com>
This DC patchset brings improvements in multiple areas. In summary, we have:
* Unified dc_update_state commit interface with dc_probe model,
dc_state_get_status, and perfmon BLS sequence
* DCN42 enhancements including mcache programming, PMFW DF C-state client,
and DCCG clocking fix
* DML2.1 writeback validation plus MCIF ARB and watermark/latency updates
* Color management refactor to dc_plane_cm with plane/CRTC colorop test coverage
* Greatly enhanced KUnit coverage across amdgpu_dm, connector, CRC, DMUB, and
color management
* HDMI AV mute timing, DP link training logging, and Apple Studio Display fixes
* Code cleanup including DCE trim from DCN-only builds and HWSS refactors
* SPL UPSP upsampling and YUV422/YUV444 scaling support
* Fix missing dc_3dlut forward declaration in color management KUnit headers
* Fix DM IRQ schedule-work KUnit tests after cancel_work_sync teardown change
Acked-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Taimur Hassan <Syed.Hassan@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index fcaa17b9ab1a..75c06a1752b5 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -66,7 +66,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
-#define DC_VER "3.2.389"
+#define DC_VER "3.2.390"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
--
2.43.0
^ permalink raw reply related [flat|nested] 72+ messages in thread