From: Wayne Lin <Wayne.Lin@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
Leo Li <sunpeng.li@amd.com>,
Aurabindo Pillai <aurabindo.pillai@amd.com>,
Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
Tom Chung <chiahsuan.chung@amd.com>,
"Fangzhi Zuo" <jerry.zuo@amd.com>,
Dan Wheeler <daniel.wheeler@amd.com>, Ray Wu <Ray.Wu@amd.com>,
Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
James Lin <PingLei.Lin@amd.com>,
Chenyu Chen <Chen-Yu.Chen@amd.com>,
Tony Cheng <tony.cheng@amd.com>, Jun Lei <jun.lei@amd.com>
Subject: [PATCH 28/74] drm/amd/display: Build the dcn401 seamless update in DC2
Date: Wed, 11 Nov 2026 09:28:34 +0800 [thread overview]
Message-ID: <20261111014100.3596072-29-Wayne.Lin@amd.com> (raw)
In-Reply-To: <20261111014100.3596072-1-Wayne.Lin@amd.com>
From: Tony Cheng <tony.cheng@amd.com>
[Why]
With DC2 selected, a full update that adds a plane to a stream has no
DC2 builder. dc_update_planes_and_stream rejects the update, and the
stream stays without a plane. A tail must run on the vsync after the
head, and DC2 has no wait for that vsync.
[How]
DC2 now runs only the head of a commit and rejects a builder that
emits a tail. The update goes through the API shim. DC2 accepts only
a full update on a new context. Add the block calls the plane add
makes, and a dcn401 builder that emits them in one head. The stream
checks reject a virtual signal, so DC2 builds no update yet. The
builder does not call floating-point-only code, and it checks the OTG
master before use.
Cc: Jun Lei <jun.lei@amd.com>
Signed-off-by: Tony Cheng <tony.cheng@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
---
.../amd/display/dc/bls_builder/bls_builder.h | 3 +-
.../dc/bls_builder/bls_builder_internal.h | 1 +
.../bls_builder/bls_builder_private_types.h | 52 +
.../dc/bls_builder/dcn401_commit_builder.c | 1242 ++++++++++++++++-
.../dc/bls_builder/dcn401_init_builder.c | 2 +
.../display/dc/bls_executor/bls_executor.c | 466 +++++++
drivers/gpu/drm/amd/display/dc/core/dc.c | 15 +-
.../gpu/drm/amd/display/dc/core2/dc_core2.c | 204 ++-
.../amd/display/dc/dc_api_dispatch/api_shim.c | 18 +
.../amd/display/dc/dc_api_dispatch/api_shim.h | 4 +
.../drm/amd/display/dc/hwss/hw_sequencer.h | 89 ++
.../amd/display/dc/inc/dc_core_interface.h | 7 +
12 files changed, 2003 insertions(+), 100 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h
index 485e877df5d2..954adc590ed4 100644
--- a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h
@@ -12,7 +12,7 @@
#include "bls_builder/dmub_abi.h"
#include "bls_builder/bls_builder_legacy_init.h"
-#define DC2_BLS_MAX_STEPS 64
+#define DC2_BLS_MAX_STEPS 128
enum bls_builder_result {
BLS_BUILD_SUCCESS,
@@ -25,6 +25,7 @@ enum bls_builder_name {
DCN_DECL_INITIALIZATION,
DCN_DECL_INITIALIZATION_LEGACY,
DCN_DECL_NON_SEAMLESS_COMMIT,
+ DCN_DECL_SEAMLESS_UPDATE,
BLS_BUILDER_NAME_COUNT,
};
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h
index a641941a2f2f..ebf315e31ad8 100644
--- a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h
@@ -10,3 +10,4 @@
const struct bls_builder *dcn401_bls_builder_create(
enum bls_builder_name name);
const struct bls_builder *dcn401_non_seamless_commit_builder(void);
+const struct bls_builder *dcn401_seamless_update_builder(void);
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_private_types.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_private_types.h
index 025b2e3b62ad..2f3cb1457ebe 100644
--- a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_private_types.h
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_private_types.h
@@ -31,7 +31,55 @@ struct dcn401_commit_step_meta {
} hubbub_program_arbiter;
struct {
bool safe_to_lower;
+ /*
+ * Set: program the current state's compbuf size, as
+ * dcn401_program_outstanding_updates does. Clear:
+ * program the new state's size.
+ */
+ bool use_current_state_size;
} hubbub_program_compbuf_segments;
+ struct {
+ bool enable;
+ } hubbub_force_pstate_change_control;
+ struct {
+ bool enable;
+ } hubp_clk_cntl;
+ struct {
+ bool power_on;
+ } hubp_pg_control;
+ struct {
+ bool unblank;
+ } hubp_set_blank;
+ struct {
+ bool enable;
+ } dpp_dppclk_control;
+ struct {
+ bool unblank;
+ } opp_set_disp_pattern_generator;
+ struct {
+ /*
+ * Set: program the pipe's hubp_regs.det_size, which
+ * gives the HUBP its DET segments, as dcn401_program_pipe
+ * does. Clear: program size 0, which releases the
+ * HUBP's segments, as the DC1 plane disable does.
+ */
+ bool allocate;
+ } hubp_program_det_segments;
+ struct {
+ /*
+ * Set: program the MALL selection and cursor caching
+ * that dcn401_program_mall_pipe_config_sequence computes
+ * for the new state. Clear: program no MALL and no
+ * cursor caching, as the DC1 plane disable does.
+ */
+ bool from_new_state;
+ } hubp_update_mall_sel;
+ struct {
+ enum mpcc_gamut_remap_id block_id;
+ } mpc_set_gamut_remap_bypass;
+ struct {
+ enum MCM_LUT_ID id;
+ } mpc_program_lut_mode;
struct {
bool state;
} bios_set_scratch_critical_state;
@@ -63,6 +111,10 @@ struct dcn401_commit_step_meta {
bool stream_mode_unchanged;
/* The new state has a stream. */
bool new_state_has_stream;
+ /* dc->optimized_required is clear. */
+ bool optimized_not_required;
+ /* The plane has no address update, or skips the manual trigger. */
+ bool no_manual_trigger;
} skip_if;
};
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_commit_builder.c b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_commit_builder.c
index 5fe4a1ec7166..b6208a0ad164 100644
--- a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_commit_builder.c
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_commit_builder.c
@@ -5,12 +5,15 @@
#include "dm_services.h"
#include "core_types.h"
+#include "resource.h"
#include "link_encoder.h"
#include "stream_encoder.h"
#include "clk_mgr.h"
#include "dccg.h"
#include "dc_bios_types.h"
#include "dc_dmub_srv.h"
+#include "custom_float.h"
+#include "dcn32/dcn32_resource.h"
#include "bls_builder/bls_builder_internal.h"
#include "bls_builder/dcn401_init_builder.h"
#include "bls_builder/bls_builder_private_types.h"
@@ -23,18 +26,35 @@
* DCN_DECL_NON_SEAMLESS_COMMIT for one virtual stream without planes.
* The new state has no stream, or one stream with no plane; the current
* state has no stream, or one stream with one plane. A plane is added
- * later by commit_planes, not by this commit.
+ * later by DCN_DECL_SEAMLESS_UPDATE, not by this commit.
*
* The sequence follows legacy_commit_state_hw on dcn401: the same leaf
- * calls in the same order, including the calls DC1 repeats. head_sequence
- * holds everything through the ODM double-buffer and blank waits.
- * tail_sequence is the deferred bandwidth lower, and it runs only after
- * that head has finished.
+ * calls in the same order, including the calls DC1 repeats. Everything is
+ * in head_sequence: the ODM double-buffer and blank waits come before the
+ * bandwidth lower, so no tail is needed.
+ *
+ * DCN_DECL_SEAMLESS_UPDATE adds one plane to that stream. The sequence
+ * follows the full update in commit_planes_for_stream on dcn401, all in
+ * head_sequence: the outstanding updates, prepare_bandwidth and the
+ * pending-update waits, then the locked front-end programming and
+ * post_unlock_program_front_end. The bandwidth lower stays with
+ * dc_post_update_surfaces_to_stream.
+ *
+ * Neither builder emits a tail_sequence. A tail runs only after a vsync,
+ * and Core has no wait-for-vsync imperative yet, so Core rejects a tail.
*/
#define DCN401_DPG_POLL_INTERVAL_US 100
#define DCN401_DPG_POLL_TIMEOUT_US 100000
#define DCN401_STATIC_SCREEN_NUM_FRAMES 2
+#define DCN401_PENDING_UPDATE_POLL_INTERVAL_US 1
+#define DCN401_PENDING_UPDATE_TIMEOUT_US 100000
+#define DCN401_FLIP_PENDING_POLL_INTERVAL_US 100
+#define DCN401_PLANE_ENABLE_DELAY_US 500
+/* 1.0 in the HDR multiplier and MPCC gain format. */
+#define DCN401_UNITY_GAIN 0x1f000
+#define DCN401_MALL_SEL_SS 2
+#define DCN401_CACHE_CURSOR_BYTES 16384
/*
* Each helper takes the same arguments. CHECK_CONDITION logs the reason
@@ -308,6 +328,16 @@ static const struct pipe_ctx *dcn401_checked_otg_master(
new_state), ¬_one_pipe);
}
+/* The OTG master of one state, or NULL when that state is not one pipe. */
+static const struct pipe_ctx *dcn401_otg_of(const struct dc_state *state)
+{
+ bool not_one_pipe = false;
+
+ if (!state)
+ return NULL;
+ return dcn401_state_otg_master(state, ¬_one_pipe);
+}
+
static bool check_one_otg_pipe(const struct dc *dc,
const struct dc_state *current_state,
const struct dc_state *new_state)
@@ -457,7 +487,8 @@ static bool check_link_enc_assignment(const struct dc *dc,
pipe->stream->link->link_enc;
}
-static enum bls_builder_result dcn401_check_commit_state_support(
+/* What both builders need of a state's stream, apart from its planes. */
+static enum bls_builder_result dcn401_check_stream_support(
const struct dc *dc, const struct dc_state *current_state,
const struct dc_state *new_state)
{
@@ -480,15 +511,11 @@ static enum bls_builder_result dcn401_check_commit_state_support(
CHECK_CONDITION(no_boot_dpms_writeback,
"seamless boot, dpms, or writeback is set");
CHECK_CONDITION(abm, "ABM level is set");
- CHECK_CONDITION(plane_count, "plane count does not match the state");
CHECK_CONDITION(one_otg_pipe, "stream is not on one pipe");
CHECK_RESOURCE(otg_master_present, "stream has no otg master");
CHECK_CONDITION(odm_combine, "odm is set");
CHECK_CONDITION(mpc_blend, "top or bottom pipe is set");
- CHECK_CONDITION(pipe_plane, "pipe plane does not match the state");
CHECK_RESOURCE(otg_master_blocks, "otg master is missing a block");
- CHECK_RESOURCE(plane_blocks, "plane is missing hubp or dpp");
- CHECK_CONDITION(mpcc_alone, "mpcc is not alone in the opp tree");
CHECK_CONDITION(pipe_audio, "audio is set");
CHECK_CONDITION(pipe_dsc, "dsc is set");
CHECK_CONDITION(pipe_gsl, "gsl is set");
@@ -496,6 +523,25 @@ static enum bls_builder_result dcn401_check_commit_state_support(
return BLS_BUILD_SUCCESS;
}
+static enum bls_builder_result dcn401_check_commit_state_support(
+ const struct dc *dc, const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ enum bls_builder_result result;
+
+ result = dcn401_check_stream_support(dc, current_state, new_state);
+ if (result != BLS_BUILD_SUCCESS ||
+ !dcn401_checked_state(current_state,
+ new_state)->stream_count)
+ return result;
+
+ CHECK_CONDITION(plane_count, "plane count does not match the state");
+ CHECK_CONDITION(pipe_plane, "pipe plane does not match the state");
+ CHECK_RESOURCE(plane_blocks, "plane is missing hubp or dpp");
+ CHECK_CONDITION(mpcc_alone, "mpcc is not alone in the opp tree");
+ return BLS_BUILD_SUCCESS;
+}
+
static bool check_stream_not_kept(const struct dc *dc,
const struct dc_state *current_state,
const struct dc_state *new_state)
@@ -546,6 +592,442 @@ static enum bls_builder_result dcn401_check_non_seamless_commit_support(
return BLS_BUILD_SUCCESS;
}
+/* The seamless update keeps the one stream and only adds its plane. */
+static bool check_stream_kept(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ return current_state->stream_count == 1 &&
+ new_state->stream_count == 1 &&
+ current_state->streams[0] == new_state->streams[0];
+}
+
+static bool check_plane_added(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ return !current_state->stream_status[0].plane_count &&
+ new_state->stream_status[0].plane_count == 1;
+}
+
+static bool check_same_otg_master_blocks(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct pipe_ctx *current_pipe = dcn401_otg_of(current_state);
+ const struct pipe_ctx *new_pipe = dcn401_otg_of(new_state);
+
+ (void)dc;
+ if (!current_pipe || !new_pipe)
+ return false;
+ return current_pipe->stream_res.tg == new_pipe->stream_res.tg &&
+ current_pipe->stream_res.opp == new_pipe->stream_res.opp;
+}
+
+static bool check_new_plane_blocks(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ (void)dc;
+ (void)current_state;
+ return pipe && pipe->plane_state && pipe->plane_res.hubp &&
+ pipe->plane_res.dpp && pipe->plane_res.dpp->funcs;
+}
+
+static bool check_pool_funcs(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)current_state;
+ (void)new_state;
+ return dc->res_pool->funcs && dc->res_pool->hubbub->funcs;
+}
+
+/* DC1 uses the HUBP instance as the MPCC and DPP instance. */
+static bool check_plane_instances(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+ int inst;
+
+ (void)dc;
+ (void)current_state;
+ if (!pipe || !pipe->plane_res.hubp || !pipe->plane_res.dpp)
+ return false;
+ inst = pipe->plane_res.hubp->inst;
+ return inst < MAX_MPCC && pipe->plane_res.mpcc_inst == inst &&
+ pipe->plane_res.dpp->inst == inst;
+}
+
+/* dcn401 programs DET by segments only. */
+static bool check_det_by_segments(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)current_state;
+ (void)new_state;
+ return !dc->res_pool->hubbub->funcs->program_det_size;
+}
+
+/* The update always emits the two triple-buffer calls DC1 makes with it. */
+static bool check_triple_buffer(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)current_state;
+ (void)new_state;
+ return dc->debug.enable_tri_buf;
+}
+
+/* With sanity_checks DC1 adds p-state verification the update lacks. */
+static bool check_no_sanity_checks(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)current_state;
+ (void)new_state;
+ return !dc->debug.sanity_checks;
+}
+
+static bool check_no_pipe_wait(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && !pipe->wait_is_required;
+}
+
+/* dcn20_blank_pixel_data does nothing while a test pattern is on. */
+static bool check_no_test_pattern(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct dc_stream_state *stream = new_state->streams[0];
+
+ (void)dc;
+ (void)current_state;
+ return !stream->link->test_pattern_enabled &&
+ stream->test_pattern.type == DP_TEST_PATTERN_VIDEO_MODE;
+}
+
+/* With force_dpg_enable DC1 unblanks to colour squares, not video. */
+static bool check_no_forced_dpg(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)current_state;
+ (void)new_state;
+ (void)dc;
+ return true;
+}
+
+/* dcn20_blank_pixel_data sets the ABM pipe on unblank when there is one. */
+static bool check_no_abm_pipe(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && !pipe->stream_res.abm;
+}
+
+/* enable_plane programs the system aperture when VM is valid. */
+static bool check_no_vm_aperture(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)current_state;
+ (void)new_state;
+ return !dc->vm_pa_config.valid;
+}
+
+/* enable_plane sets the flip interrupt when the plane asks for one. */
+static bool check_no_flip_int(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && pipe->plane_state &&
+ !pipe->plane_state->flip_int_enabled;
+}
+
+/* With an empty tree, DC1 removes no MPCC before the insert. */
+static bool check_opp_tree_empty(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+ const struct output_pixel_processor *opp;
+ unsigned int i;
+
+ (void)dc;
+ (void)current_state;
+ if (!pipe)
+ return false;
+ opp = pipe->stream_res.opp;
+ if (!opp || opp->mpc_tree_params.opp_list)
+ return false;
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (opp->mpcc_disconnect_pending[i])
+ return false;
+ }
+ return true;
+}
+
+/* The update bypasses the plane gamut remap. */
+static bool check_no_plane_gamut_remap(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ (void)dc;
+ (void)current_state;
+ return pipe && pipe->plane_state &&
+ !pipe->plane_state->gamut_remap_matrix.enable_remap;
+}
+
+/* The update bypasses the stream gamut remap. */
+static bool check_no_stream_gamut_remap(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ return !new_state->streams[0]->gamut_remap_matrix.enable_remap;
+}
+
+/* The update sets the default output CSC. */
+static bool check_no_output_csc(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ return !new_state->streams[0]->csc_color_matrix.enable_adjustment;
+}
+
+/* The update programs the surface and its address without DCC. */
+static bool check_no_dcc(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && pipe->plane_state && !pipe->plane_state->dcc.enable;
+}
+
+/* The update programs a single graphics address, not stereo or video. */
+static bool check_graphics_address(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && pipe->plane_state &&
+ pipe->plane_state->address.type == PLN_ADDR_TYPE_GRAPHICS;
+}
+
+/* DC1 programs triple buffering and the flip only for a queued flip. */
+static bool check_no_immediate_flip(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && pipe->plane_state &&
+ !pipe->plane_state->flip_immediate;
+}
+
+/*
+ * DC1 translates a distributed-points curve into a LUT while it programs
+ * the plane. The update programs only the predefined and bypass curves.
+ */
+static bool check_no_degamma_curve(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && pipe->plane_state &&
+ pipe->plane_state->in_transfer_func.type !=
+ TF_TYPE_DISTRIBUTED_POINTS;
+}
+
+/* dcn32_set_input_transfer_func calls dpp_set_pregam_state if present. */
+static bool check_no_dpp_pregam(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+
+ return pipe && pipe->plane_res.dpp && pipe->plane_res.dpp->funcs &&
+ !pipe->plane_res.dpp->funcs->dpp_set_pregam_state;
+}
+
+/* dcn401_set_mcm_luts then programs every MCM LUT off. */
+static bool check_no_mcm_luts(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct pipe_ctx *pipe = dcn401_otg_of(new_state);
+ const union dc_plane_cm_flags *flags;
+
+ (void)dc;
+ (void)current_state;
+ if (!pipe || !pipe->plane_state)
+ return false;
+ flags = &pipe->plane_state->cm.flags;
+ return !flags->bits.blend_enable && !flags->bits.shaper_enable &&
+ !flags->bits.lut3d_enable && !flags->bits.rmcm_enable;
+}
+
+static bool check_no_shaper_curve(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct dc_transfer_func *shaper = new_state->streams[0]->func_shaper;
+
+ (void)dc;
+ (void)current_state;
+ return !shaper || shaper->type != TF_TYPE_DISTRIBUTED_POINTS;
+}
+
+static bool check_no_stream_3dlut(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ const struct dc_3dlut *lut3d = new_state->streams[0]->lut3d_func;
+
+ (void)dc;
+ (void)current_state;
+ return !lut3d || !lut3d->state.bits.initialized;
+}
+
+static bool check_no_regamma_curve(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ return new_state->streams[0]->out_transfer_func.type !=
+ TF_TYPE_DISTRIBUTED_POINTS;
+}
+
+static bool check_no_cursor(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ return !new_state->streams[0]->cursor_attributes.address.quad_part;
+}
+
+static bool check_no_dsc_change(const struct dc *dc,
+ const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ (void)dc;
+ (void)current_state;
+ return !new_state->streams[0]->update_flags.bits.dsc_changed;
+}
+
+/*
+ * The checks follow the update in the order it programs the pipe. Each one
+ * rejects a state for which DC1 would make a call the update does not emit.
+ */
+static enum bls_builder_result dcn401_check_seamless_update_support(
+ const struct dc *dc, const struct dc_state *current_state,
+ const struct dc_state *new_state)
+{
+ enum bls_builder_result result;
+
+ if (!dc || !current_state || !new_state)
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+
+ CHECK_RESOURCE(dc_resources, "dc resources are missing");
+ CHECK_CONDITION(fams2_debug, "FAMS2 debug is enabled");
+ CHECK_CONDITION(cursor_offload, "cursor offload is enabled");
+ CHECK_CONDITION(dc_mode_softmax, "dc mode softmax is enabled");
+ CHECK_CONDITION(visual_confirm, "visual confirm, dpg, hblank borrow, or frame sync is set");
+ CHECK_CONDITION(dsc_power_gate, "DSC power gate is enabled");
+
+ result = dcn401_check_stream_support(dc, current_state, NULL);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+ result = dcn401_check_stream_support(dc, NULL, new_state);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+
+ /* The transition: one stream, kept, gains one plane on its OTG. */
+ CHECK_CONDITION(stream_kept, "stream is not kept across the update");
+ CHECK_CONDITION(plane_added, "update does not add exactly one plane");
+ CHECK_CONDITION(same_otg_master_blocks, "otg or opp changes");
+ CHECK_RESOURCE(new_plane_blocks, "plane is missing hubp or dpp");
+ CHECK_RESOURCE(pool_funcs, "resource pool or hubbub has no funcs");
+ CHECK_CONDITION(plane_instances, "mpcc or dpp is not the hubp instance");
+ CHECK_CONDITION(det_by_segments, "hubbub programs det size");
+
+ /* Under the lock, before the pipe is programmed. */
+ CHECK_CONDITION(triple_buffer, "triple buffer is disabled");
+ CHECK_CONDITION(no_sanity_checks, "sanity checks are enabled");
+ CHECK_CONDITION(no_pipe_wait, "pipe wait is required");
+
+ /* Unblank. */
+ CHECK_CONDITION(no_test_pattern, "test pattern is set");
+ CHECK_CONDITION(no_forced_dpg, "dpg is forced");
+ CHECK_CONDITION(no_abm_pipe, "abm is set");
+
+ /* enable_plane. */
+ CHECK_CONDITION(no_vm_aperture, "vm system aperture is valid");
+ CHECK_CONDITION(no_flip_int, "flip interrupt is enabled");
+
+ /* update_dchubp_dpp. */
+ CHECK_CONDITION(opp_tree_empty, "opp tree is not empty");
+ CHECK_CONDITION(no_plane_gamut_remap, "plane gamut remap is set");
+ CHECK_CONDITION(no_stream_gamut_remap, "stream gamut remap is set");
+ CHECK_CONDITION(no_output_csc, "output csc is set");
+ CHECK_CONDITION(no_dcc, "dcc is enabled");
+ CHECK_CONDITION(graphics_address, "address is not graphics");
+ CHECK_CONDITION(no_immediate_flip, "flip is immediate");
+
+ /* Input, MCM and output transfer functions. */
+ CHECK_CONDITION(no_degamma_curve, "plane degamma is distributed points");
+ CHECK_CONDITION(no_dpp_pregam, "dpp has a pregam state");
+ CHECK_CONDITION(no_mcm_luts, "an mcm lut is enabled");
+ CHECK_CONDITION(no_shaper_curve, "shaper is distributed points");
+ CHECK_CONDITION(no_stream_3dlut, "stream 3dlut is set");
+ CHECK_CONDITION(no_regamma_curve, "regamma is distributed points");
+
+ /* Not programmed by this update. */
+ CHECK_CONDITION(no_cursor, "cursor is set");
+ CHECK_CONDITION(no_dsc_change, "dsc changes");
+ return BLS_BUILD_SUCCESS;
+}
+
static struct pipe_ctx *get_otg_master_from_state_by_stream(
struct dc_state *state, const struct dc_stream_state *stream)
{
@@ -681,7 +1163,7 @@ static const struct dcn401_commit_step
* the head's double buffering. legacy_commit_state_hw sets up stereo for
* a mode-changed stream, then dc_enable_stereo sets it up again for every
* stream; dcn10_setup_stereo with no 3D format is the two STEREO calls.
- * The deferred tail starts only after these waits.
+ * The bandwidth lower starts only after these waits.
*/
static const struct dcn401_commit_step
bls_head_per_stream_per_otg_master_pipe_new_front_end[] = {
@@ -710,7 +1192,7 @@ static const struct dcn401_commit_step
* Net effect: release the forced p-state when no OTG master did, then
* dcn401_optimize_bandwidth without FAMS2, SubVP or DC-mode softmax.
*/
-static const struct dcn401_commit_step bls_tail_per_state_new[] = {
+static const struct dcn401_commit_step bls_head_per_state_new_postamble[] = {
{ .func = HUBBUB_FORCE_PSTATE_CHANGE_CONTROL,
.meta.skip_if.new_state_has_stream = true },
{ .func = HUBBUB_PROGRAM_WATERMARKS,
@@ -728,21 +1210,187 @@ static const struct dcn401_commit_step bls_tail_per_state_new[] = {
* state, and never one in both.
*/
static_assert(ARRAY_SIZE(bls_head_per_state_new) +
- ARRAY_SIZE(bls_head_per_stream_per_otg_master_pipe_current) <=
+ ARRAY_SIZE(bls_head_per_stream_per_otg_master_pipe_current) +
+ ARRAY_SIZE(bls_head_per_state_new_postamble) <=
DC2_BLS_MAX_STEPS,
"dcn401 commit stream-off head exceeds DC2_BLS_MAX_STEPS");
static_assert(ARRAY_SIZE(bls_head_per_state_new) +
ARRAY_SIZE(bls_head_per_stream_per_otg_master_pipe_new) +
ARRAY_SIZE(
- bls_head_per_stream_per_otg_master_pipe_new_front_end) <=
+ bls_head_per_stream_per_otg_master_pipe_new_front_end) +
+ ARRAY_SIZE(bls_head_per_state_new_postamble) <=
DC2_BLS_MAX_STEPS,
"dcn401 commit enable head exceeds DC2_BLS_MAX_STEPS");
-static_assert(ARRAY_SIZE(bls_tail_per_state_new) <= DC2_BLS_MAX_STEPS,
- "dcn401 commit tail sequence exceeds DC2_BLS_MAX_STEPS");
+
+/*
+ * Net effect: hwss_process_outstanding_hw_updates on the current state,
+ * which commit_planes_for_stream runs while optimized_required is set.
+ * The OTG master has no plane yet, so no MPCC disconnect is pending.
+ */
+static const struct dcn401_commit_step
+ bls_update_head_per_stream_per_otg_master_pipe_preamble[] = {
+ { .func = TG_WAIT_FOR_ALL_PENDING_UPDATES,
+ .meta.skip_if.optimized_not_required = true },
+ { .func = TG_WAIT_ODM_DOUBLEBUFFER_PENDING_CLEAR,
+ .meta.skip_if.optimized_not_required = true },
+ { .func = OPP_WAIT_FOR_BLANK_COMPLETE,
+ .meta.skip_if.optimized_not_required = true },
+};
+
+/* Net effect: dcn401_program_outstanding_updates on the current state. */
+static const struct dcn401_commit_step bls_update_head_global_preamble[] = {
+ { .func = HUBBUB_PROGRAM_COMPBUF_SEGMENTS,
+ .meta.hubbub_program_compbuf_segments.safe_to_lower = true,
+ .meta.hubbub_program_compbuf_segments.use_current_state_size = true,
+ .meta.skip_if.optimized_not_required = true },
+};
+
+/*
+ * Net effect: hwss_wait_for_outstanding_hw_updates on the current state,
+ * which a full update runs before it takes the pipe lock.
+ */
+static const struct dcn401_commit_step
+ bls_update_head_per_stream_per_otg_master_pipe_current_pending[] = {
+ { .func = TG_WAIT_FOR_ALL_PENDING_UPDATES },
+ { .func = TG_WAIT_ODM_DOUBLEBUFFER_PENDING_CLEAR },
+ { .func = OPP_WAIT_FOR_BLANK_COMPLETE },
+};
+
+/*
+ * After the waits, the head adds the plane. Each table runs once per
+ * stream, on the OTG master of the new state, and is named for the DC1
+ * call it replaces in commit_planes_for_stream and dcn401_program_pipe.
+ *
+ * Pipe lock: the two triple-buffer offs, from commit_planes_for_stream and
+ * dcn401_program_front_end_for_ctx, then the forced p-state and delay for
+ * the first HUBP.
+ */
+static const struct dcn401_commit_step bls_update_head_new_lock[] = {
+ { .func = TG_LOCK, .meta.tg_lock.lock = true },
+ { .func = HUBP_PROGRAM_TRIPLEBUFFER },
+ { .func = HUBP_PROGRAM_TRIPLEBUFFER },
+ { .func = HUBBUB_FORCE_PSTATE_CHANGE_CONTROL,
+ .meta.hubbub_force_pstate_change_control.enable = true },
+ { .func = DC_UDELAY },
+};
+
+/* blank_pixel_data (unblank), dcn401_program_tg and update_odm. */
+static const struct dcn401_commit_step bls_update_head_new_stream[] = {
+ { .func = OPP_SET_DISP_PATTERN_GENERATOR,
+ .meta.opp_set_disp_pattern_generator.unblank = true },
+ { .func = TG_PROGRAM_GLOBAL_SYNC },
+ { .func = TG_WAIT_FOR_STATE },
+ { .func = TG_SET_VTG_PARAMS },
+ { .func = TG_SETUP_VERTICAL_INTERRUPT2 },
+ { .func = OPTC_SET_ODM_BYPASS },
+ { .func = OPP_PIPE_CLOCK_CONTROL },
+ { .func = OPP_PROGRAM_LEFT_EDGE_EXTRA_PIXEL },
+};
+
+/* enable_plane, then the watermark propagate and the DET segments. */
+static const struct dcn401_commit_step bls_update_head_new_enable_plane[] = {
+ { .func = DC_IP_REQUEST_CNTL, .meta.dc_ip_request_cntl.enable = true },
+ { .func = HUBP_PG_CONTROL, .meta.hubp_pg_control.power_on = true },
+ { .func = DC_IP_REQUEST_CNTL, .meta.dc_ip_request_cntl.enable = false },
+ { .func = HUBP_CLK_CNTL, .meta.hubp_clk_cntl.enable = true },
+ { .func = HUBP_INIT },
+ { .func = OPP_PIPE_CLOCK_CONTROL },
+ { .func = HUBBUB_FORCE_WM_PROPAGATE_TO_PIPES },
+ { .func = HUBP_PROGRAM_DET_SEGMENTS,
+ .meta.hubp_program_det_segments.allocate = true },
+};
+
+/* update_dchubp_dpp, with the MPC insert from dcn401_update_mpcc. */
+static const struct dcn401_commit_step
+ bls_update_head_new_update_dchubp_dpp[] = {
+ { .func = DPP_DPPCLK_CONTROL, .meta.dpp_dppclk_control.enable = true },
+ { .func = DCCG_UPDATE_DPP_DTO },
+ { .func = HUBP_VTG_SEL },
+ { .func = HUBP_SETUP2 },
+ { .func = HUBP_SET_UNBOUNDED_REQUESTING },
+ { .func = HUBP_SETUP_INTERDEPENDENT2 },
+ { .func = DPP_SETUP_DPP },
+ { .func = DPP_SET_CURSOR_MATRIX },
+ { .func = DPP_PROGRAM_BIAS_AND_SCALE },
+ /* insert_plane programs the blending; no update_blending follows. */
+ { .func = MPC_INSERT_PLANE },
+ { .func = MPC_UPDATE_VISUAL_CONFIRM },
+ { .func = DPP_SET_SCALER },
+ { .func = HUBP_MEM_PROGRAM_VIEWPORT },
+ { .func = HUBP_PROGRAM_MCACHE_ID },
+ { .func = MPC_SET_GAMUT_REMAP_BYPASS,
+ .meta.mpc_set_gamut_remap_bypass.block_id =
+ MPCC_MCM_FIRST_GAMUT_REMAP },
+ { .func = MPC_SET_GAMUT_REMAP_BYPASS,
+ .meta.mpc_set_gamut_remap_bypass.block_id =
+ MPCC_MCM_SECOND_GAMUT_REMAP },
+ { .func = MPC_SET_GAMUT_REMAP_BYPASS,
+ .meta.mpc_set_gamut_remap_bypass.block_id = MPCC_OGAM_GAMUT_REMAP },
+ { .func = MPC_POWER_ON_MPC_MEM_PWR },
+ { .func = MPC_SET_OCSC_DEFAULT },
+ { .func = HUBP_PROGRAM_SURFACE_CONFIG },
+ { .func = HUBP_UPDATE_PLANE_ADDR },
+ { .func = HUBP_SET_BLANK, .meta.hubp_set_blank.unblank = true },
+};
+
+/*
+ * set_hdr_multiplier, the input and MCM transfer functions, the output
+ * transfer function and the OPP format.
+ */
+static const struct dcn401_commit_step
+ bls_update_head_new_transfer_funcs[] = {
+ { .func = DPP_SET_HDR_MULTIPLIER },
+ { .func = DPP_SET_PRE_DEGAM },
+ { .func = DPP_PROGRAM_GAMCOR_LUT },
+ { .func = MPC_SET_MOVABLE_CM_LOCATION },
+ { .func = MPC_PROGRAM_LUT_MODE,
+ .meta.mpc_program_lut_mode.id = MCM_LUT_1DLUT },
+ { .func = MPC_PROGRAM_LUT_MODE,
+ .meta.mpc_program_lut_mode.id = MCM_LUT_SHAPER },
+ { .func = MPC_PROGRAM_LUT_MODE,
+ .meta.mpc_program_lut_mode.id = MCM_LUT_3DLUT },
+ { .func = HUBP_PROGRAM_3DLUT_FL_CONFIG },
+ { .func = HUBP_SET_3DLUT_FL },
+ { .func = MPC_SET_OUTPUT_GAMMA },
+ { .func = OPP_SET_DYN_EXPANSION },
+ { .func = OPP_PROGRAM_FMT },
+};
+
+/*
+ * The pipe unlock, then dcn401_post_unlock_program_front_end: the
+ * flip-pending wait, the p-state release and the MALL selection. Last,
+ * the manual trigger.
+ */
+static const struct dcn401_commit_step bls_update_head_new_unlock[] = {
+ { .func = TG_LOCK, .meta.tg_lock.lock = false },
+ { .func = HUBP_WAIT_FLIP_PENDING },
+ { .func = HUBBUB_FORCE_PSTATE_CHANGE_CONTROL },
+ { .func = HUBP_UPDATE_MALL_SEL,
+ .meta.hubp_update_mall_sel.from_new_state = true },
+ { .func = OPTC_PROGRAM_MANUAL_TRIGGER,
+ .meta.skip_if.no_manual_trigger = true },
+};
+
+/* The support check allows one stream, kept across the update. */
+static_assert(
+ ARRAY_SIZE(
+ bls_update_head_per_stream_per_otg_master_pipe_preamble) +
+ ARRAY_SIZE(bls_update_head_global_preamble) +
+ ARRAY_SIZE(bls_head_per_state_new) +
+ ARRAY_SIZE(
+ bls_update_head_per_stream_per_otg_master_pipe_current_pending) +
+ ARRAY_SIZE(bls_update_head_new_lock) +
+ ARRAY_SIZE(bls_update_head_new_stream) +
+ ARRAY_SIZE(bls_update_head_new_enable_plane) +
+ ARRAY_SIZE(bls_update_head_new_update_dchubp_dpp) +
+ ARRAY_SIZE(bls_update_head_new_transfer_funcs) +
+ ARRAY_SIZE(bls_update_head_new_unlock) <= DC2_BLS_MAX_STEPS,
+ "dcn401 seamless update head exceeds DC2_BLS_MAX_STEPS");
/* pipe is NULL only for the bandwidth and p-state steps. */
struct dcn401_commit_step_args {
struct dc *dc;
+ struct dc_state *current_state;
struct dc_state *new_state;
struct pipe_ctx *pipe;
};
@@ -787,15 +1435,19 @@ static uint32_t dcn401_early_cntl(const struct pipe_ctx *pipe)
return early_cntl ? early_cntl : lane_count;
}
-/* dcn20_blank_pixel_data(blank): sRGB black over the whole OTG. */
+/*
+ * dcn20_blank_pixel_data: sRGB black over the whole OTG, or the video
+ * on unblank.
+ */
static void dcn401_opp_blank_params(const struct dc *dc,
- const struct pipe_ctx *pipe,
+ const struct pipe_ctx *pipe, bool unblank,
struct opp_set_disp_pattern_generator_params *p)
{
const struct dc_crtc_timing *timing = &pipe->stream->timing;
p->opp = pipe->stream_res.opp;
- p->test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
+ p->test_pattern = unblank ? CONTROLLER_DP_TEST_PATTERN_VIDEOMODE :
+ CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
p->color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
p->color_depth = timing->display_color_depth;
p->use_solid_color = true;
@@ -848,6 +1500,111 @@ static void dcn401_update_clocks_params(const struct dc *dc,
context->bw_ctx.bw.dcn.clk.p_state_change_support;
}
+/* dcn401_update_mpcc_sequence's blending for the plane. */
+static void dcn401_blnd_cfg(const struct dc_plane_state *plane,
+ struct mpcc_blnd_cfg *cfg)
+{
+ cfg->overlap_only = false;
+ cfg->global_gain = 0xff;
+ if (plane->per_pixel_alpha) {
+ cfg->pre_multiplied_alpha = plane->pre_multiplied_alpha;
+ if (plane->global_alpha) {
+ cfg->alpha_mode =
+ MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
+ cfg->global_gain = plane->global_alpha_value;
+ } else {
+ cfg->alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
+ }
+ } else {
+ cfg->pre_multiplied_alpha = false;
+ cfg->alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
+ }
+ cfg->global_alpha = plane->global_alpha ?
+ plane->global_alpha_value : 0xff;
+ cfg->background_color_bpc = 4;
+ cfg->bottom_gain_mode = 0;
+ cfg->top_gain = DCN401_UNITY_GAIN;
+ cfg->bottom_inside_gain = DCN401_UNITY_GAIN;
+ cfg->bottom_outside_gain = DCN401_UNITY_GAIN;
+ if (plane->format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
+ cfg->pre_multiplied_alpha = false;
+}
+
+/* dcn401_set_hdr_multiplier_sequence: 1.0 unless the plane sets one. */
+static uint32_t dcn401_hdr_mult(const struct dc_plane_state *plane)
+{
+ struct custom_float_format fmt = {
+ .exponenta_bits = 6,
+ .mantissa_bits = 12,
+ .sign = true,
+ };
+ uint32_t hw_mult = DCN401_UNITY_GAIN;
+
+ if (!dc_fixpt_eq(plane->hdr_mult, dc_fixpt_from_int(0)) &&
+ !convert_to_custom_float_format(plane->hdr_mult, &fmt,
+ &hw_mult))
+ hw_mult = DCN401_UNITY_GAIN;
+ return hw_mult;
+}
+
+/* dcn401_program_mall_pipe_config_sequence for one non-phantom pipe. */
+static void dcn401_mall_sel_params(struct dc *dc, struct dc_state *state,
+ struct pipe_ctx *pipe, struct hubp_update_mall_sel_params *p)
+{
+ const struct hubp *hubp = pipe->plane_res.hubp;
+ const struct dc_plane_address *address = &pipe->plane_state->address;
+ int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
+ uint32_t mall_ss_size_bytes;
+ uint32_t num_ways = 0;
+
+ switch (hubp->curs_attr.color_format) {
+ case CURSOR_MODE_MONO:
+ cursor_size /= 2;
+ break;
+ case CURSOR_MODE_COLOR_1BIT_AND:
+ case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+ case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+ cursor_size *= 4;
+ break;
+ default:
+ cursor_size *= 8;
+ break;
+ }
+
+ /*
+ * dcn401_calculate_cab_allocation also adds the cursor mall bytes.
+ * This builder rejects a cursor, so those bytes are zero. The helper
+ * that computes them is built only with CONFIG_DRM_AMD_DC_FP.
+ */
+ mall_ss_size_bytes = state->bw_ctx.bw.dcn.mall_ss_size_bytes;
+ if (dc->debug.force_mall_ss_num_ways > 0)
+ num_ways = dc->debug.force_mall_ss_num_ways;
+ else if (dc->res_pool->funcs->calculate_mall_ways_from_bytes)
+ num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(
+ dc, mall_ss_size_bytes);
+
+ p->hubp = pipe->plane_res.hubp;
+ p->cache_cursor = cursor_size > DCN401_CACHE_CURSOR_BYTES;
+ p->mall_sel = num_ways <= dc->caps.cache_num_ways &&
+ pipe->stream->link->psr_settings.psr_version ==
+ DC_PSR_VERSION_UNSUPPORTED &&
+ address->type != PLN_ADDR_TYPE_GRPH_STEREO &&
+ !address->tmz_surface ? DCN401_MALL_SEL_SS : 0;
+}
+
+/* dcn401_set_mcm_luts clears the HUBP 3DLUT fast load with this. */
+static const struct dc_3dlut_dma dcn401_3dlut_dma_off = {0};
+
+/* dcn401_set_mcm_luts sizes the off 3DLUT by the plane's LUT. */
+static enum dc_cm_lut_size dcn401_lut_mode_size(
+ const struct dc_plane_state *plane, enum MCM_LUT_ID id)
+{
+ if (id != MCM_LUT_3DLUT)
+ return CM_LUT_SIZE_NONE;
+ return plane->cm.lut3d_func.lut_3d.use_tetrahedral_9 ?
+ CM_LUT_SIZE_999 : CM_LUT_SIZE_171717;
+}
+
/* Writes one entry; build sized every sequence before adding to it. */
static void dcn401_add_step(struct block_sequence_state *sequence,
const struct dcn401_commit_step_args *args,
@@ -858,11 +1615,65 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
union block_sequence_params *p = &entry->params;
struct dc *dc = args->dc;
struct dcn_bw_output *bw = &args->new_state->bw_ctx.bw.dcn;
- struct pipe_ctx *pipe = args->pipe;
+ struct pipe_ctx *pipe;
+ struct dpp *dpp;
+ struct dc_plane_state *plane;
const struct dcn401_commit_step_meta *m = &step->meta;
memset(entry, 0, sizeof(*entry));
entry->func = step->func;
+ /*
+ * Bandwidth and p-state steps have no pipe. Handle them before the
+ * pipe is used, then every later case can use the pipe directly.
+ */
+ if (!args->pipe) {
+ switch (step->func) {
+ case CLK_MGR_UPDATE_CLOCKS_FOR_STATE:
+ dcn401_update_clocks_params(dc, args->new_state,
+ m->clk_mgr_update_clocks_for_state
+ .safe_to_lower,
+ &p->clk_mgr_update_clocks_for_state_params);
+ return;
+ case HUBBUB_PROGRAM_WATERMARKS:
+ p->hubbub_program_watermarks_params =
+ hwss_prepare_hubbub_program_watermarks(dc,
+ dc->res_pool->hubbub, &bw->watermarks,
+ dc->res_pool->ref_clocks.dchub_ref_clock_inKhz /
+ 1000,
+ m->hubbub_program_watermarks.safe_to_lower);
+ return;
+ case HUBBUB_PROGRAM_ARBITER:
+ p->hubbub_program_arbiter_params =
+ hwss_prepare_hubbub_program_arbiter(
+ dc->res_pool->hubbub, &bw->arb_regs,
+ m->hubbub_program_arbiter.safe_to_lower);
+ return;
+ case HUBBUB_PROGRAM_COMPBUF_SEGMENTS:
+ p->hubbub_program_compbuf_segments_params.hubbub =
+ dc->res_pool->hubbub;
+ p->hubbub_program_compbuf_segments_params.compbuf_size =
+ m->hubbub_program_compbuf_segments
+ .use_current_state_size ?
+ args->current_state->bw_ctx.bw.dcn.arb_regs
+ .compbuf_size : bw->arb_regs.compbuf_size;
+ p->hubbub_program_compbuf_segments_params.safe_to_lower =
+ m->hubbub_program_compbuf_segments
+ .safe_to_lower;
+ return;
+ case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL:
+ p->hubbub_force_pstate_change_control_params.hubbub =
+ dc->res_pool->hubbub;
+ p->hubbub_force_pstate_change_control_params.enable =
+ m->hubbub_force_pstate_change_control.enable;
+ return;
+ default:
+ (*sequence->num_steps)--;
+ return;
+ }
+ }
+ pipe = args->pipe;
+ dpp = pipe->plane_res.dpp;
+ plane = pipe->plane_state;
switch (step->func) {
case CLK_MGR_UPDATE_CLOCKS_FOR_STATE:
dcn401_update_clocks_params(dc, args->new_state,
@@ -888,7 +1699,10 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
p->hubbub_program_compbuf_segments_params.hubbub =
dc->res_pool->hubbub;
p->hubbub_program_compbuf_segments_params.compbuf_size =
- bw->arb_regs.compbuf_size;
+ m->hubbub_program_compbuf_segments
+ .use_current_state_size ?
+ args->current_state->bw_ctx.bw.dcn.arb_regs
+ .compbuf_size : bw->arb_regs.compbuf_size;
p->hubbub_program_compbuf_segments_params.safe_to_lower =
m->hubbub_program_compbuf_segments
.safe_to_lower;
@@ -896,6 +1710,8 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL:
p->hubbub_force_pstate_change_control_params.hubbub =
dc->res_pool->hubbub;
+ p->hubbub_force_pstate_change_control_params.enable =
+ m->hubbub_force_pstate_change_control.enable;
break;
case BIOS_SET_SCRATCH_CRITICAL_STATE:
p->bios_set_scratch_critical_state_params.dcb =
@@ -996,6 +1812,7 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
break;
case OPP_SET_DISP_PATTERN_GENERATOR:
dcn401_opp_blank_params(dc, pipe,
+ m->opp_set_disp_pattern_generator.unblank,
&p->opp_set_disp_pattern_generator_params);
break;
case OPP_WAIT_FOR_BLANK_COMPLETE:
@@ -1084,6 +1901,9 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
p->program_det_segments_params.hubbub = dc->res_pool->hubbub;
p->program_det_segments_params.hubp_inst =
pipe->plane_res.hubp->inst;
+ if (m->hubp_program_det_segments.allocate)
+ p->program_det_segments_params.det_size =
+ pipe->hubp_regs.det_size;
break;
case MPC_REMOVE_MPCC:
p->mpc_remove_mpcc_params.mpc = dc->res_pool->mpc;
@@ -1100,19 +1920,27 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
break;
case HUBP_SET_BLANK:
p->hubp_set_blank_params.hubp = pipe->plane_res.hubp;
- p->hubp_set_blank_params.blank = true;
+ p->hubp_set_blank_params.blank = !m->hubp_set_blank.unblank;
break;
case HUBP_UPDATE_MALL_SEL:
- p->hubp_update_mall_sel_params.hubp = pipe->plane_res.hubp;
+ if (m->hubp_update_mall_sel.from_new_state)
+ dcn401_mall_sel_params(dc, args->new_state, pipe,
+ &p->hubp_update_mall_sel_params);
+ else
+ p->hubp_update_mall_sel_params.hubp =
+ pipe->plane_res.hubp;
break;
case HUBP_SET_FLIP_CONTROL_GSL:
p->set_flip_control_gsl_params.hubp = pipe->plane_res.hubp;
break;
case HUBP_CLK_CNTL:
p->hubp_clk_cntl_params.hubp = pipe->plane_res.hubp;
+ p->hubp_clk_cntl_params.enable = m->hubp_clk_cntl.enable;
break;
case DPP_DPPCLK_CONTROL:
- p->dpp_dppclk_control_params.dpp = pipe->plane_res.dpp;
+ p->dpp_dppclk_control_params.dpp = dpp;
+ p->dpp_dppclk_control_params.enable =
+ m->dpp_dppclk_control.enable;
break;
case DC_IP_REQUEST_CNTL:
p->dc_ip_request_cntl_params.hws = dc->hwseq;
@@ -1123,13 +1951,240 @@ static void dcn401_add_step(struct block_sequence_state *sequence,
p->hubp_pg_control_params.hws = dc->hwseq;
p->hubp_pg_control_params.hubp_inst =
pipe->plane_res.hubp->inst;
- p->hubp_pg_control_params.power_on = false;
+ p->hubp_pg_control_params.power_on =
+ m->hubp_pg_control.power_on;
break;
case HUBP_RESET:
p->hubp_reset_params.hubp = pipe->plane_res.hubp;
break;
case DPP_RESET:
- p->dpp_reset_params.dpp = pipe->plane_res.dpp;
+ p->dpp_reset_params.dpp = dpp;
+ break;
+ case TG_WAIT_FOR_ALL_PENDING_UPDATES:
+ p->tg_wait_for_all_pending_updates_params.tg =
+ pipe->stream_res.tg;
+ p->tg_wait_for_all_pending_updates_params.include_pipe_update =
+ plane != NULL;
+ p->tg_wait_for_all_pending_updates_params.polling_interval_us =
+ DCN401_PENDING_UPDATE_POLL_INTERVAL_US;
+ p->tg_wait_for_all_pending_updates_params.timeout_us =
+ DCN401_PENDING_UPDATE_TIMEOUT_US;
+ break;
+ case HUBP_PROGRAM_TRIPLEBUFFER:
+ p->program_triplebuffer_params.hubp = pipe->plane_res.hubp;
+ p->program_triplebuffer_params.enableTripleBuffer =
+ plane->triplebuffer_flips;
+ break;
+ case DC_UDELAY:
+ p->dc_udelay_params.us = DCN401_PLANE_ENABLE_DELAY_US;
+ break;
+ case TG_PROGRAM_GLOBAL_SYNC:
+ p->tg_program_global_sync_params.tg = pipe->stream_res.tg;
+ p->tg_program_global_sync_params.vready_offset =
+ pipe->global_sync.dcn4x.vready_offset_pixels;
+ p->tg_program_global_sync_params.vstartup_lines =
+ pipe->global_sync.dcn4x.vstartup_lines;
+ p->tg_program_global_sync_params.vupdate_offset_pixels =
+ pipe->global_sync.dcn4x.vupdate_offset_pixels;
+ p->tg_program_global_sync_params.vupdate_vupdate_width_pixels =
+ pipe->global_sync.dcn4x
+ .vupdate_vupdate_width_pixels;
+ p->tg_program_global_sync_params.pstate_keepout_start_lines =
+ pipe->global_sync.dcn4x.pstate_keepout_start_lines;
+ break;
+ case TG_WAIT_FOR_STATE:
+ p->tg_wait_for_state_params.tg = pipe->stream_res.tg;
+ p->tg_wait_for_state_params.state = CRTC_STATE_VACTIVE;
+ break;
+ case TG_SET_VTG_PARAMS:
+ p->tg_set_vtg_params_params.tg = pipe->stream_res.tg;
+ p->tg_set_vtg_params_params.timing = &pipe->stream->timing;
+ p->tg_set_vtg_params_params.program_fp2 = true;
+ break;
+ case HUBP_INIT:
+ p->hubp_init_params.hubp = pipe->plane_res.hubp;
+ break;
+ case HUBBUB_FORCE_WM_PROPAGATE_TO_PIPES:
+ p->hubbub_force_wm_propagate_to_pipes_params.hubbub =
+ dc->res_pool->hubbub;
+ break;
+ case DCCG_UPDATE_DPP_DTO:
+ p->dccg_update_dpp_dto_params.dccg = dc->res_pool->dccg;
+ p->dccg_update_dpp_dto_params.dpp_inst = dpp->inst;
+ p->dccg_update_dpp_dto_params.dppclk_khz =
+ pipe->plane_res.bw.dppclk_khz;
+ break;
+ case HUBP_VTG_SEL:
+ p->hubp_vtg_sel_params.hubp = pipe->plane_res.hubp;
+ p->hubp_vtg_sel_params.otg_inst = pipe->stream_res.tg->inst;
+ break;
+ case HUBP_SETUP2:
+ p->hubp_setup2_params.hubp = pipe->plane_res.hubp;
+ p->hubp_setup2_params.hubp_regs = &pipe->hubp_regs;
+ p->hubp_setup2_params.global_sync = &pipe->global_sync;
+ p->hubp_setup2_params.timing = &pipe->stream->timing;
+ break;
+ case HUBP_SET_UNBOUNDED_REQUESTING:
+ p->hubp_set_unbounded_requesting_params.hubp = pipe->plane_res.hubp;
+ p->hubp_set_unbounded_requesting_params.unbounded_req =
+ pipe->unbounded_req;
+ break;
+ case HUBP_SETUP_INTERDEPENDENT2:
+ p->hubp_setup_interdependent2_params.hubp = pipe->plane_res.hubp;
+ p->hubp_setup_interdependent2_params.hubp_regs =
+ &pipe->hubp_regs;
+ break;
+ case DPP_SETUP_DPP:
+ p->setup_dpp_params.dpp = dpp;
+ p->setup_dpp_params.format = plane->format;
+ p->setup_dpp_params.input_csc_color_matrix =
+ plane->input_csc_color_matrix;
+ p->setup_dpp_params.color_space = plane->color_space;
+ p->setup_dpp_params.upsp_mode = resource_is_upsp_required(
+ plane->format, plane->scaling_linearity);
+ break;
+ case DPP_SET_CURSOR_MATRIX:
+ p->dpp_set_cursor_matrix_params.dpp = dpp;
+ p->dpp_set_cursor_matrix_params.color_space =
+ plane->color_space;
+ p->dpp_set_cursor_matrix_params.cursor_csc_color_matrix =
+ &plane->cursor_csc_color_matrix;
+ break;
+ case DPP_PROGRAM_BIAS_AND_SCALE:
+ p->program_bias_and_scale_params.dpp = dpp;
+ p->program_bias_and_scale_params.bias_and_scale =
+ plane->bias_and_scale;
+ break;
+ case MPC_INSERT_PLANE:
+ p->mpc_insert_plane_params.mpc = dc->res_pool->mpc;
+ p->mpc_insert_plane_params.mpc_tree_params =
+ &pipe->stream_res.opp->mpc_tree_params;
+ dcn401_blnd_cfg(plane, &p->mpc_insert_plane_params.blnd_cfg);
+ p->mpc_insert_plane_params.dpp_id = pipe->plane_res.hubp->inst;
+ p->mpc_insert_plane_params.mpcc_id = pipe->plane_res.hubp->inst;
+ break;
+ case MPC_UPDATE_VISUAL_CONFIRM:
+ p->update_visual_confirm_params.mpc = dc->res_pool->mpc;
+ p->update_visual_confirm_params.color =
+ &pipe->visual_confirm_color;
+ p->update_visual_confirm_params.mpcc_id = pipe->plane_res.hubp->inst;
+ break;
+ case DPP_SET_SCALER:
+ p->dpp_set_scaler_params.dpp = dpp;
+ p->dpp_set_scaler_params.scl_data = &pipe->plane_res.scl_data;
+ break;
+ case HUBP_MEM_PROGRAM_VIEWPORT:
+ p->hubp_mem_program_viewport_params.hubp = pipe->plane_res.hubp;
+ p->hubp_mem_program_viewport_params.viewport =
+ &pipe->plane_res.scl_data.viewport;
+ p->hubp_mem_program_viewport_params.viewport_c =
+ &pipe->plane_res.scl_data.viewport_c;
+ break;
+ case HUBP_PROGRAM_MCACHE_ID:
+ p->program_mcache_id_and_split_coordinate.hubp = pipe->plane_res.hubp;
+ p->program_mcache_id_and_split_coordinate.mcache_regs =
+ &pipe->mcache_regs;
+ break;
+ case MPC_SET_GAMUT_REMAP_BYPASS:
+ p->mpc_set_gamut_remap_bypass_params.mpc = dc->res_pool->mpc;
+ p->mpc_set_gamut_remap_bypass_params.mpcc_id =
+ pipe->plane_res.mpcc_inst;
+ p->mpc_set_gamut_remap_bypass_params.block_id =
+ m->mpc_set_gamut_remap_bypass.block_id;
+ break;
+ case MPC_POWER_ON_MPC_MEM_PWR:
+ p->power_on_mpc_mem_pwr_params.mpc = dc->res_pool->mpc;
+ p->power_on_mpc_mem_pwr_params.mpcc_id = pipe->plane_res.hubp->inst;
+ p->power_on_mpc_mem_pwr_params.power_on = true;
+ break;
+ case MPC_SET_OCSC_DEFAULT:
+ p->set_ocsc_default_params.mpc = dc->res_pool->mpc;
+ p->set_ocsc_default_params.opp_id = pipe->stream_res.opp->inst;
+ p->set_ocsc_default_params.color_space =
+ pipe->stream->output_color_space;
+ p->set_ocsc_default_params.ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
+ break;
+ case HUBP_PROGRAM_SURFACE_CONFIG:
+ p->program_surface_config_params.hubp = pipe->plane_res.hubp;
+ p->program_surface_config_params.format = plane->format;
+ p->program_surface_config_params.tiling_info =
+ &plane->tiling_info;
+ p->program_surface_config_params.plane_size =
+ plane->plane_size;
+ p->program_surface_config_params.plane_size.surface_size =
+ pipe->plane_res.scl_data.viewport;
+ p->program_surface_config_params.rotation = plane->rotation;
+ p->program_surface_config_params.dcc = &plane->dcc;
+ p->program_surface_config_params.horizontal_mirror =
+ plane->horizontal_mirror;
+ break;
+ case HUBP_UPDATE_PLANE_ADDR:
+ p->update_plane_addr_params.hubp = pipe->plane_res.hubp;
+ p->update_plane_addr_params.address = plane->address;
+ p->update_plane_addr_params.flip_immediate =
+ plane->flip_immediate;
+ p->update_plane_addr_params.dcc = plane->dcc.enable;
+ break;
+ case DPP_SET_HDR_MULTIPLIER:
+ p->dpp_set_hdr_multiplier_params.dpp = dpp;
+ p->dpp_set_hdr_multiplier_params.hw_mult =
+ dcn401_hdr_mult(plane);
+ break;
+ case DPP_SET_PRE_DEGAM:
+ p->dpp_set_pre_degam_params.dpp = dpp;
+ p->dpp_set_pre_degam_params.in_transfer_func =
+ &plane->in_transfer_func;
+ break;
+ case DPP_PROGRAM_GAMCOR_LUT:
+ p->dpp_program_gamcor_lut_params.dpp = dpp;
+ if (plane->in_transfer_func.type == TF_TYPE_HWPWL)
+ p->dpp_program_gamcor_lut_params.params =
+ &plane->in_transfer_func.pwl;
+ break;
+ case MPC_SET_MOVABLE_CM_LOCATION:
+ p->mpc_set_movable_cm_location_params.mpc = dc->res_pool->mpc;
+ p->mpc_set_movable_cm_location_params.location =
+ MPCC_MOVABLE_CM_LOCATION_BEFORE;
+ p->mpc_set_movable_cm_location_params.mpcc_id =
+ pipe->plane_res.mpcc_inst;
+ break;
+ case MPC_PROGRAM_LUT_MODE:
+ /*
+ * Every LUT is off. DC1 reads the bank back with get_lut_mode;
+ * the build reads no hardware, so it assumes bank A for an
+ * MPCC that held no plane.
+ */
+ p->mpc_program_lut_mode_params.mpc = dc->res_pool->mpc;
+ p->mpc_program_lut_mode_params.id = m->mpc_program_lut_mode.id;
+ p->mpc_program_lut_mode_params.lut_bank_a = true;
+ p->mpc_program_lut_mode_params.size = dcn401_lut_mode_size(
+ plane, m->mpc_program_lut_mode.id);
+ p->mpc_program_lut_mode_params.mpcc_id =
+ pipe->plane_res.mpcc_inst;
+ break;
+ case HUBP_PROGRAM_3DLUT_FL_CONFIG:
+ p->hubp_program_3dlut_fl_config_params.hubp = pipe->plane_res.hubp;
+ p->hubp_program_3dlut_fl_config_params.config =
+ &dcn401_3dlut_dma_off;
+ break;
+ case HUBP_SET_3DLUT_FL:
+ p->hubp_set_3dlut_fl_params.hubp = pipe->plane_res.hubp;
+ break;
+ case MPC_SET_OUTPUT_GAMMA:
+ p->mpc_set_output_gamma_params.mpc = dc->res_pool->mpc;
+ p->mpc_set_output_gamma_params.mpcc_id =
+ pipe->plane_res.mpcc_inst;
+ if (pipe->stream->out_transfer_func.type == TF_TYPE_HWPWL)
+ p->mpc_set_output_gamma_params.params =
+ &pipe->stream->out_transfer_func.pwl;
+ break;
+ case HUBP_WAIT_FLIP_PENDING:
+ p->hubp_wait_flip_pending_params.hubp = pipe->plane_res.hubp;
+ p->hubp_wait_flip_pending_params.polling_interval_us =
+ DCN401_FLIP_PENDING_POLL_INTERVAL_US;
+ break;
+ case OPTC_PROGRAM_MANUAL_TRIGGER:
+ p->program_manual_trigger_params.tg = pipe->stream_res.tg;
break;
default:
/* The step tables use only the funcs above. */
@@ -1147,6 +2202,13 @@ static bool dcn401_skip_step(const struct dcn401_commit_step_args *args,
if (step->meta.skip_if.new_state_has_stream &&
args->new_state->stream_count)
return true;
+ if (step->meta.skip_if.optimized_not_required &&
+ !args->dc->optimized_required)
+ return true;
+ if (step->meta.skip_if.no_manual_trigger &&
+ (!args->pipe->plane_state->update_bits.addr_update ||
+ args->pipe->plane_state->skip_manual_trigger))
+ return true;
return false;
}
@@ -1164,15 +2226,14 @@ static void dcn401_add_steps(struct block_sequence_state *sequence,
/* The support check found an OTG master for each stream of state. */
static void dcn401_add_steps_per_stream_per_otg_master_pipe(
- struct block_sequence_state *sequence, struct dc *dc,
- struct dc_state *new_state, struct dc_state *state,
+ struct block_sequence_state *sequence,
+ const struct dcn401_commit_step_args *state_args,
+ struct dc_state *state,
const struct dcn401_commit_step *steps, unsigned int count)
{
- struct dcn401_commit_step_args args = {0};
+ struct dcn401_commit_step_args args = *state_args;
unsigned int i;
- args.dc = dc;
- args.new_state = new_state;
for (i = 0; i < state->stream_count; i++) {
args.pipe = get_otg_master_from_state_by_stream(state,
state->streams[i]);
@@ -1182,20 +2243,37 @@ static void dcn401_add_steps_per_stream_per_otg_master_pipe(
#define DCN401_ADD_STEPS(sequence, args, steps) \
dcn401_add_steps(sequence, args, steps, ARRAY_SIZE(steps))
-#define DCN401_ADD_STEPS_PER_STREAM(sequence, dc, new_state, state, steps) \
- dcn401_add_steps_per_stream_per_otg_master_pipe(sequence, dc, \
- new_state, state, steps, ARRAY_SIZE(steps))
+#define DCN401_ADD_STEPS_PER_STREAM(sequence, args, state, steps) \
+ dcn401_add_steps_per_stream_per_otg_master_pipe(sequence, args, \
+ state, steps, ARRAY_SIZE(steps))
+
+/*
+ * Points the step arguments at the states and the sequence at
+ * head_sequence, both empty. The entries point into the states; the build
+ * writes neither.
+ */
+static void dcn401_init_and_unpack_params(
+ struct bls_builder_declarative_params *params,
+ struct dcn401_commit_step_args *state_args,
+ struct block_sequence_state *head)
+{
+ state_args->dc = params->dc;
+ state_args->current_state = (struct dc_state *)params->current_state;
+ state_args->new_state = (struct dc_state *)params->new_state;
+ state_args->pipe = NULL;
+
+ params->head_num_steps = 0;
+ params->tail_num_steps = 0;
+ head->steps = params->head_sequence;
+ head->num_steps = ¶ms->head_num_steps;
+}
static enum bls_builder_result dcn401_build_non_seamless_commit(
struct bls_builder_declarative_params *params)
{
- struct dcn401_commit_step_args state_args = {0};
+ struct dcn401_commit_step_args state_args;
struct block_sequence_state head;
- struct block_sequence_state tail;
- struct dc_state *current_state;
- struct dc_state *new_state;
enum bls_builder_result result;
- struct dc *dc;
if (!params)
return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
@@ -1204,28 +2282,58 @@ static enum bls_builder_result dcn401_build_non_seamless_commit(
if (result != BLS_BUILD_SUCCESS)
return result;
- /* The entries point into the states. The build writes neither. */
- dc = params->dc;
- current_state = (struct dc_state *)params->current_state;
- new_state = (struct dc_state *)params->new_state;
- state_args.dc = dc;
- state_args.new_state = new_state;
-
- params->head_num_steps = 0;
- params->tail_num_steps = 0;
- head.steps = params->head_sequence;
- head.num_steps = ¶ms->head_num_steps;
- tail.steps = params->tail_sequence;
- tail.num_steps = ¶ms->tail_num_steps;
-
+ dcn401_init_and_unpack_params(params, &state_args, &head);
DCN401_ADD_STEPS(&head, &state_args, bls_head_per_state_new);
- DCN401_ADD_STEPS_PER_STREAM(&head, dc, new_state, current_state,
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args,
+ state_args.current_state,
bls_head_per_stream_per_otg_master_pipe_current);
- DCN401_ADD_STEPS_PER_STREAM(&head, dc, new_state, new_state,
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
bls_head_per_stream_per_otg_master_pipe_new);
- DCN401_ADD_STEPS_PER_STREAM(&head, dc, new_state, new_state,
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
bls_head_per_stream_per_otg_master_pipe_new_front_end);
- DCN401_ADD_STEPS(&tail, &state_args, bls_tail_per_state_new);
+ DCN401_ADD_STEPS(&head, &state_args, bls_head_per_state_new_postamble);
+
+ return BLS_BUILD_SUCCESS;
+}
+
+static enum bls_builder_result dcn401_build_seamless_update(
+ struct bls_builder_declarative_params *params)
+{
+ struct dcn401_commit_step_args state_args;
+ struct block_sequence_state head;
+ enum bls_builder_result result;
+
+ if (!params)
+ return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE;
+ result = dcn401_check_seamless_update_support(params->dc,
+ params->current_state, params->new_state);
+ if (result != BLS_BUILD_SUCCESS)
+ return result;
+
+ dcn401_init_and_unpack_params(params, &state_args, &head);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args,
+ state_args.current_state,
+ bls_update_head_per_stream_per_otg_master_pipe_preamble);
+ DCN401_ADD_STEPS(&head, &state_args,
+ bls_update_head_global_preamble);
+ DCN401_ADD_STEPS(&head, &state_args, bls_head_per_state_new);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args,
+ state_args.current_state,
+ bls_update_head_per_stream_per_otg_master_pipe_current_pending);
+
+ /* One stream, so adding each table per stream keeps the DC1 order. */
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
+ bls_update_head_new_lock);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
+ bls_update_head_new_stream);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
+ bls_update_head_new_enable_plane);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
+ bls_update_head_new_update_dchubp_dpp);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
+ bls_update_head_new_transfer_funcs);
+ DCN401_ADD_STEPS_PER_STREAM(&head, &state_args, state_args.new_state,
+ bls_update_head_new_unlock);
return BLS_BUILD_SUCCESS;
}
@@ -1249,3 +2357,23 @@ const struct bls_builder *dcn401_non_seamless_commit_builder(void)
return &builder;
}
+
+static bool dcn401_seamless_update_check_capability(
+ const struct bls_builder_check_capability_params *params)
+{
+ return params && dcn401_check_seamless_update_support(params->dc,
+ params->current_state, params->new_state) ==
+ BLS_BUILD_SUCCESS;
+}
+
+const struct bls_builder *dcn401_seamless_update_builder(void)
+{
+ static const struct bls_builder builder = {
+ .name = DCN_DECL_SEAMLESS_UPDATE,
+ .kind = BLS_BUILDER_DECLARATIVE,
+ .check_capability = dcn401_seamless_update_check_capability,
+ .build.declarative = dcn401_build_seamless_update,
+ };
+
+ return &builder;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c
index 4c0043c84907..75fd4be3690a 100644
--- a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c
+++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c
@@ -409,6 +409,8 @@ const struct bls_builder *dcn401_bls_builder_create(
return &legacy_initialization_builder;
case DCN_DECL_NON_SEAMLESS_COMMIT:
return dcn401_non_seamless_commit_builder();
+ case DCN_DECL_SEAMLESS_UPDATE:
+ return dcn401_seamless_update_builder();
default:
return NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c
index 3a80c9261710..6a875add72e2 100644
--- a/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c
+++ b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c
@@ -486,6 +486,151 @@ static noinline_for_stack bool dc2_bls_step_supported(const struct dc2 *dc2,
return mpc && mpc->funcs && mpc->funcs->remove_mpcc &&
step->params.mpc_remove_mpcc_params.mpc_tree_params &&
step->params.mpc_remove_mpcc_params.mpcc_to_remove;
+ case MPC_INSERT_PLANE:
+ mpc = step->params.mpc_insert_plane_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->insert_plane &&
+ step->params.mpc_insert_plane_params.mpc_tree_params;
+ case MPC_UPDATE_BLENDING:
+ mpc = step->params.mpc_update_blending_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->update_blending;
+ case MPC_POWER_ON_MPC_MEM_PWR:
+ mpc = step->params.power_on_mpc_mem_pwr_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->power_on_mpc_mem_pwr;
+ case MPC_SET_OCSC_DEFAULT:
+ mpc = step->params.set_ocsc_default_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->set_ocsc_default;
+ case DPP_SET_SCALER:
+ dpp = step->params.dpp_set_scaler_params.dpp;
+ return dpp && dpp->funcs && dpp->funcs->dpp_set_scaler &&
+ step->params.dpp_set_scaler_params.scl_data;
+ case DPP_PROGRAM_BIAS_AND_SCALE:
+ dpp = step->params.program_bias_and_scale_params.dpp;
+ return dpp && dpp->funcs &&
+ dpp->funcs->dpp_program_bias_and_scale;
+ case DPP_SET_HDR_MULTIPLIER:
+ dpp = step->params.dpp_set_hdr_multiplier_params.dpp;
+ return dpp && dpp->funcs && dpp->funcs->dpp_set_hdr_multiplier;
+ case HUBP_INIT:
+ hubp = step->params.hubp_init_params.hubp;
+ return hubp && hubp->funcs && hubp->funcs->hubp_init;
+ case HUBP_VTG_SEL:
+ hubp = step->params.hubp_vtg_sel_params.hubp;
+ return hubp && hubp->funcs && hubp->funcs->hubp_vtg_sel;
+ case HUBP_SET_UNBOUNDED_REQUESTING:
+ hubp = step->params.hubp_set_unbounded_requesting_params.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->set_unbounded_requesting;
+ case HUBP_MEM_PROGRAM_VIEWPORT:
+ hubp = step->params.hubp_mem_program_viewport_params.hubp;
+ return hubp && hubp->funcs && hubp->funcs->mem_program_viewport &&
+ step->params.hubp_mem_program_viewport_params.viewport;
+ case HUBP_PROGRAM_TRIPLEBUFFER:
+ hubp = step->params.program_triplebuffer_params.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->hubp_enable_tripleBuffer;
+ case OPTC_PROGRAM_MANUAL_TRIGGER:
+ tg = step->params.program_manual_trigger_params.tg;
+ return tg && tg->funcs && tg->funcs->program_manual_trigger;
+ case DCCG_UPDATE_DPP_DTO:
+ dccg = step->params.dccg_update_dpp_dto_params.dccg;
+ return dccg && dccg->funcs && dccg->funcs->update_dpp_dto;
+ case TG_PROGRAM_GLOBAL_SYNC:
+ tg = step->params.tg_program_global_sync_params.tg;
+ return tg && tg->funcs && tg->funcs->program_global_sync;
+ case TG_SET_VTG_PARAMS:
+ tg = step->params.tg_set_vtg_params_params.tg;
+ return tg && tg->funcs && tg->funcs->set_vtg_params &&
+ step->params.tg_set_vtg_params_params.timing;
+ case TG_WAIT_FOR_ALL_PENDING_UPDATES: {
+ const struct tg_wait_for_all_pending_updates_params *p =
+ &step->params.tg_wait_for_all_pending_updates_params;
+
+ return p->tg && p->tg->funcs && p->tg->funcs->is_tg_enabled &&
+ p->polling_interval_us;
+ }
+ case DC_UDELAY:
+ return true;
+ case HUBBUB_FORCE_WM_PROPAGATE_TO_PIPES:
+ hubbub = step->params.hubbub_force_wm_propagate_to_pipes_params
+ .hubbub;
+ return hubbub && hubbub->funcs &&
+ hubbub->funcs->force_wm_propagate_to_pipes;
+ case HUBP_SETUP2: {
+ const struct hubp_setup2_params *p =
+ &step->params.hubp_setup2_params;
+
+ return p->hubp && p->hubp->funcs && p->hubp->funcs->hubp_setup2 &&
+ p->hubp_regs && p->global_sync && p->timing;
+ }
+ case HUBP_SETUP_INTERDEPENDENT2:
+ hubp = step->params.hubp_setup_interdependent2_params.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->hubp_setup_interdependent2 &&
+ step->params.hubp_setup_interdependent2_params
+ .hubp_regs;
+ case HUBP_PROGRAM_MCACHE_ID:
+ hubp = step->params.program_mcache_id_and_split_coordinate.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->hubp_program_mcache_id_and_split_coordinate &&
+ step->params.program_mcache_id_and_split_coordinate
+ .mcache_regs;
+ case HUBP_PROGRAM_SURFACE_CONFIG:
+ hubp = step->params.program_surface_config_params.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->hubp_program_surface_config &&
+ step->params.program_surface_config_params
+ .tiling_info &&
+ step->params.program_surface_config_params.dcc;
+ case HUBP_UPDATE_PLANE_ADDR:
+ hubp = step->params.update_plane_addr_params.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->hubp_program_surface_flip_and_addr;
+ case HUBP_WAIT_FLIP_PENDING:
+ hubp = step->params.hubp_wait_flip_pending_params.hubp;
+ return hubp && hubp->funcs && hubp->funcs->hubp_is_flip_pending &&
+ step->params.hubp_wait_flip_pending_params
+ .polling_interval_us;
+ case HUBP_PROGRAM_3DLUT_FL_CONFIG:
+ hubp = step->params.hubp_program_3dlut_fl_config_params.hubp;
+ return hubp && hubp->funcs &&
+ hubp->funcs->hubp_program_3dlut_fl_config &&
+ step->params.hubp_program_3dlut_fl_config_params
+ .config;
+ case HUBP_SET_3DLUT_FL:
+ hubp = step->params.hubp_set_3dlut_fl_params.hubp;
+ return hubp && hubp->funcs && hubp->funcs->hubp_enable_3dlut_fl;
+ case DPP_SETUP_DPP:
+ dpp = step->params.setup_dpp_params.dpp;
+ return dpp && dpp->funcs && dpp->funcs->dpp_setup;
+ case DPP_SET_CURSOR_MATRIX:
+ dpp = step->params.dpp_set_cursor_matrix_params.dpp;
+ return dpp && dpp->funcs && dpp->funcs->set_cursor_matrix &&
+ step->params.dpp_set_cursor_matrix_params
+ .cursor_csc_color_matrix;
+ case DPP_SET_PRE_DEGAM:
+ dpp = step->params.dpp_set_pre_degam_params.dpp;
+ return dpp && dpp->funcs && dpp->funcs->dpp_set_pre_degam &&
+ step->params.dpp_set_pre_degam_params
+ .in_transfer_func;
+ case DPP_PROGRAM_GAMCOR_LUT:
+ dpp = step->params.dpp_program_gamcor_lut_params.dpp;
+ return dpp && dpp->funcs && dpp->funcs->dpp_program_gamcor_lut;
+ case MPC_UPDATE_VISUAL_CONFIRM:
+ mpc = step->params.update_visual_confirm_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->set_bg_color &&
+ step->params.update_visual_confirm_params.color;
+ case MPC_SET_GAMUT_REMAP_BYPASS:
+ mpc = step->params.mpc_set_gamut_remap_bypass_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->set_gamut_remap;
+ case MPC_SET_MOVABLE_CM_LOCATION:
+ mpc = step->params.mpc_set_movable_cm_location_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->set_movable_cm_location;
+ case MPC_PROGRAM_LUT_MODE:
+ mpc = step->params.mpc_program_lut_mode_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->program_lut_mode;
+ case MPC_SET_OUTPUT_GAMMA:
+ mpc = step->params.mpc_set_output_gamma_params.mpc;
+ return mpc && mpc->funcs && mpc->funcs->set_output_gamma;
default:
return false;
}
@@ -564,6 +709,64 @@ static noinline_for_stack bool dc2_bls_wait_for_blank_complete(
return w->opp->funcs->dpg_is_blanked(w->opp);
}
+static noinline_for_stack void dc2_bls_wait_for_all_pending_updates(
+ const struct tg_wait_for_all_pending_updates_params *w)
+{
+ struct timing_generator *tg = w->tg;
+ unsigned int waited_us;
+ bool pending;
+
+ if (!tg->funcs->is_tg_enabled(tg))
+ return;
+
+ for (waited_us = 0; waited_us < w->timeout_us;
+ waited_us += w->polling_interval_us) {
+ pending = false;
+ if (tg->funcs->get_optc_double_buffer_pending)
+ pending |= tg->funcs->get_optc_double_buffer_pending(tg);
+ if (tg->funcs->get_otg_double_buffer_pending)
+ pending |= tg->funcs->get_otg_double_buffer_pending(tg);
+ if (w->include_pipe_update && tg->funcs->get_pipe_update_pending)
+ pending |= tg->funcs->get_pipe_update_pending(tg);
+ if (!pending)
+ return;
+ udelay(w->polling_interval_us);
+ }
+}
+
+static noinline_for_stack void dc2_bls_wait_flip_pending(
+ const struct hubp_wait_flip_pending_params *w)
+{
+ const unsigned int timeout_us = 100000U;
+ unsigned int j;
+
+ for (j = 0; j < timeout_us / w->polling_interval_us &&
+ w->hubp->funcs->hubp_is_flip_pending(w->hubp); j++)
+ udelay(w->polling_interval_us);
+}
+
+static noinline_for_stack void dc2_bls_set_gamut_remap_bypass(
+ const struct mpc_set_gamut_remap_bypass_params *p)
+{
+ struct mpc_grph_gamut_adjustment adjust = {
+ .gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS,
+ .mpcc_gamut_remap_block_id = p->block_id,
+ };
+
+ p->mpc->funcs->set_gamut_remap(p->mpc, p->mpcc_id, &adjust);
+}
+
+static noinline_for_stack void dc2_bls_program_surface_config(
+ const struct program_surface_config_params *p)
+{
+ struct plane_size size = p->plane_size;
+
+ p->hubp->funcs->hubp_program_surface_config(p->hubp, p->format,
+ p->tiling_info, &size, p->rotation, p->dcc,
+ p->horizontal_mirror, p->compat_level);
+ p->hubp->power_gated = false;
+}
+
enum dc2_bls_exec_result dc2_bls_execute(
struct dc2 *dc2,
const struct block_sequence *steps,
@@ -1278,6 +1481,269 @@ enum dc2_bls_exec_result dc2_bls_execute(
p->mpcc_to_remove);
break;
}
+ case MPC_INSERT_PLANE: {
+ const struct mpc_insert_plane_params *p =
+ &entry->params.mpc_insert_plane_params;
+ struct mpcc_blnd_cfg blnd_cfg = p->blnd_cfg;
+
+ p->mpc->funcs->insert_plane(p->mpc, p->mpc_tree_params,
+ &blnd_cfg, p->sm_cfg, p->insert_above_mpcc,
+ p->dpp_id, p->mpcc_id);
+ break;
+ }
+ case MPC_UPDATE_BLENDING: {
+ const struct mpc_update_blending_params *p =
+ &entry->params.mpc_update_blending_params;
+ struct mpcc_blnd_cfg blnd_cfg = p->blnd_cfg;
+
+ p->mpc->funcs->update_blending(p->mpc, &blnd_cfg,
+ p->mpcc_id);
+ break;
+ }
+ case MPC_POWER_ON_MPC_MEM_PWR: {
+ const struct power_on_mpc_mem_pwr_params *p =
+ &entry->params.power_on_mpc_mem_pwr_params;
+
+ p->mpc->funcs->power_on_mpc_mem_pwr(p->mpc, p->mpcc_id,
+ p->power_on);
+ break;
+ }
+ case MPC_SET_OCSC_DEFAULT: {
+ const struct set_ocsc_default_params *p =
+ &entry->params.set_ocsc_default_params;
+
+ p->mpc->funcs->set_ocsc_default(p->mpc, p->opp_id,
+ p->color_space, p->ocsc_mode);
+ break;
+ }
+ case DPP_SET_SCALER: {
+ const struct dpp_set_scaler_params *p =
+ &entry->params.dpp_set_scaler_params;
+
+ p->dpp->funcs->dpp_set_scaler(p->dpp, p->scl_data);
+ break;
+ }
+ case DPP_PROGRAM_BIAS_AND_SCALE: {
+ const struct program_bias_and_scale_params *p =
+ &entry->params.program_bias_and_scale_params;
+ struct dc_bias_and_scale bias_and_scale = p->bias_and_scale;
+
+ p->dpp->funcs->dpp_program_bias_and_scale(p->dpp,
+ &bias_and_scale);
+ break;
+ }
+ case DPP_SET_HDR_MULTIPLIER: {
+ const struct dpp_set_hdr_multiplier_params *p =
+ &entry->params.dpp_set_hdr_multiplier_params;
+
+ p->dpp->funcs->dpp_set_hdr_multiplier(p->dpp, p->hw_mult);
+ break;
+ }
+ case HUBP_INIT:
+ hubp = entry->params.hubp_init_params.hubp;
+ hubp->funcs->hubp_init(hubp);
+ break;
+ case HUBP_VTG_SEL: {
+ const struct hubp_vtg_sel_params *p =
+ &entry->params.hubp_vtg_sel_params;
+
+ p->hubp->funcs->hubp_vtg_sel(p->hubp, p->otg_inst);
+ break;
+ }
+ case HUBP_SET_UNBOUNDED_REQUESTING: {
+ const struct hubp_set_unbounded_requesting_params *p =
+ &entry->params.hubp_set_unbounded_requesting_params;
+
+ p->hubp->funcs->set_unbounded_requesting(p->hubp,
+ p->unbounded_req);
+ break;
+ }
+ case HUBP_MEM_PROGRAM_VIEWPORT: {
+ const struct hubp_mem_program_viewport_params *p =
+ &entry->params.hubp_mem_program_viewport_params;
+
+ p->hubp->funcs->mem_program_viewport(p->hubp, p->viewport,
+ p->viewport_c);
+ break;
+ }
+ case HUBP_PROGRAM_TRIPLEBUFFER: {
+ const struct program_triplebuffer_params *p =
+ &entry->params.program_triplebuffer_params;
+
+ p->hubp->funcs->hubp_enable_tripleBuffer(p->hubp,
+ p->enableTripleBuffer);
+ break;
+ }
+ case OPTC_PROGRAM_MANUAL_TRIGGER:
+ tg = entry->params.program_manual_trigger_params.tg;
+ tg->funcs->program_manual_trigger(tg);
+ break;
+ case DCCG_UPDATE_DPP_DTO: {
+ const struct dccg_update_dpp_dto_params *p =
+ &entry->params.dccg_update_dpp_dto_params;
+
+ p->dccg->funcs->update_dpp_dto(p->dccg, p->dpp_inst,
+ p->dppclk_khz);
+ break;
+ }
+ case TG_PROGRAM_GLOBAL_SYNC: {
+ const struct tg_program_global_sync_params *p =
+ &entry->params.tg_program_global_sync_params;
+
+ p->tg->funcs->program_global_sync(p->tg, p->vready_offset,
+ p->vstartup_lines, p->vupdate_offset_pixels,
+ p->vupdate_vupdate_width_pixels,
+ p->pstate_keepout_start_lines);
+ break;
+ }
+ case TG_SET_VTG_PARAMS: {
+ const struct tg_set_vtg_params_params *p =
+ &entry->params.tg_set_vtg_params_params;
+
+ p->tg->funcs->set_vtg_params(p->tg, p->timing,
+ p->program_fp2);
+ break;
+ }
+ case TG_WAIT_FOR_ALL_PENDING_UPDATES:
+ dc2_bls_wait_for_all_pending_updates(&entry->params
+ .tg_wait_for_all_pending_updates_params);
+ break;
+ case DC_UDELAY:
+ udelay(entry->params.dc_udelay_params.us);
+ break;
+ case HUBBUB_FORCE_WM_PROPAGATE_TO_PIPES: {
+ struct hubbub *hubbub = entry->params
+ .hubbub_force_wm_propagate_to_pipes_params
+ .hubbub;
+
+ hubbub->funcs->force_wm_propagate_to_pipes(hubbub);
+ break;
+ }
+ case HUBP_SETUP2: {
+ const struct hubp_setup2_params *p =
+ &entry->params.hubp_setup2_params;
+
+ p->hubp->funcs->hubp_setup2(p->hubp, p->hubp_regs,
+ p->global_sync, p->timing);
+ break;
+ }
+ case HUBP_SETUP_INTERDEPENDENT2: {
+ const struct hubp_setup_interdependent2_params *p =
+ &entry->params.hubp_setup_interdependent2_params;
+
+ p->hubp->funcs->hubp_setup_interdependent2(p->hubp,
+ p->hubp_regs);
+ break;
+ }
+ case HUBP_PROGRAM_MCACHE_ID: {
+ const struct program_mcache_id_and_split_coordinate *p =
+ &entry->params
+ .program_mcache_id_and_split_coordinate;
+
+ p->hubp->funcs->hubp_program_mcache_id_and_split_coordinate(
+ p->hubp, p->mcache_regs);
+ break;
+ }
+ case HUBP_PROGRAM_SURFACE_CONFIG:
+ dc2_bls_program_surface_config(&entry->params
+ .program_surface_config_params);
+ break;
+ case HUBP_UPDATE_PLANE_ADDR: {
+ const struct update_plane_addr_params *p =
+ &entry->params.update_plane_addr_params;
+
+ p->hubp->funcs->hubp_program_surface_flip_and_addr(p->hubp,
+ &p->address, p->flip_immediate, p->dcc);
+ break;
+ }
+ case HUBP_WAIT_FLIP_PENDING:
+ dc2_bls_wait_flip_pending(&entry->params
+ .hubp_wait_flip_pending_params);
+ break;
+ case HUBP_PROGRAM_3DLUT_FL_CONFIG: {
+ const struct hubp_program_3dlut_fl_config_params *p =
+ &entry->params
+ .hubp_program_3dlut_fl_config_params;
+
+ p->hubp->funcs->hubp_program_3dlut_fl_config(p->hubp,
+ p->config);
+ break;
+ }
+ case HUBP_SET_3DLUT_FL:
+ hubp = entry->params.hubp_set_3dlut_fl_params.hubp;
+ hubp->funcs->hubp_enable_3dlut_fl(hubp,
+ entry->params.hubp_set_3dlut_fl_params.enable);
+ break;
+ case DPP_SETUP_DPP: {
+ const struct setup_dpp_params *p =
+ &entry->params.setup_dpp_params;
+
+ p->dpp->funcs->dpp_setup(p->dpp, p->format,
+ EXPANSION_MODE_ZERO,
+ p->input_csc_color_matrix, p->color_space,
+ NULL, p->upsp_mode);
+ break;
+ }
+ case DPP_SET_CURSOR_MATRIX: {
+ const struct dpp_set_cursor_matrix_params *p =
+ &entry->params.dpp_set_cursor_matrix_params;
+
+ p->dpp->funcs->set_cursor_matrix(p->dpp, p->color_space,
+ *p->cursor_csc_color_matrix);
+ break;
+ }
+ case DPP_SET_PRE_DEGAM: {
+ const struct dpp_set_pre_degam_params *p =
+ &entry->params.dpp_set_pre_degam_params;
+
+ p->dpp->funcs->dpp_set_pre_degam(p->dpp,
+ p->in_transfer_func->type == TF_TYPE_PREDEFINED ?
+ p->in_transfer_func->tf :
+ TRANSFER_FUNCTION_UNITY);
+ break;
+ }
+ case DPP_PROGRAM_GAMCOR_LUT:
+ dpp = entry->params.dpp_program_gamcor_lut_params.dpp;
+ dpp->funcs->dpp_program_gamcor_lut(dpp,
+ entry->params.dpp_program_gamcor_lut_params
+ .params);
+ break;
+ case MPC_UPDATE_VISUAL_CONFIRM: {
+ const struct update_visual_confirm_params *p =
+ &entry->params.update_visual_confirm_params;
+
+ p->mpc->funcs->set_bg_color(p->mpc, p->color, p->mpcc_id);
+ break;
+ }
+ case MPC_SET_GAMUT_REMAP_BYPASS:
+ dc2_bls_set_gamut_remap_bypass(&entry->params
+ .mpc_set_gamut_remap_bypass_params);
+ break;
+ case MPC_SET_MOVABLE_CM_LOCATION: {
+ const struct mpc_set_movable_cm_location_params *p =
+ &entry->params
+ .mpc_set_movable_cm_location_params;
+
+ p->mpc->funcs->set_movable_cm_location(p->mpc, p->location,
+ p->mpcc_id);
+ break;
+ }
+ case MPC_PROGRAM_LUT_MODE: {
+ const struct mpc_program_lut_mode_params *p =
+ &entry->params.mpc_program_lut_mode_params;
+
+ p->mpc->funcs->program_lut_mode(p->mpc, p->id, p->enable,
+ p->lut_bank_a, p->size, p->mpcc_id);
+ break;
+ }
+ case MPC_SET_OUTPUT_GAMMA: {
+ const struct mpc_set_output_gamma_params *p =
+ &entry->params.mpc_set_output_gamma_params;
+
+ p->mpc->funcs->set_output_gamma(p->mpc, p->mpcc_id,
+ p->params);
+ break;
+ }
default:
ASSERT(false);
return DC2_BLS_EXEC_ERROR;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 464a5b7810d9..85de12c558ad 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -6790,6 +6790,7 @@ static const struct dc2_funcs dc2_legacy_funcs_table = {
.hardware_init = legacy_hardware_init,
.hardware_release = legacy_hardware_release,
.commit_state_hw = legacy_commit_state_hw,
+ .update_state_execute = legacy_update_state_execute,
};
const struct dc2_funcs *dc2_legacy_funcs(void)
@@ -8512,6 +8513,9 @@ bool dc_update_state_prepare(struct dc_update_scratch_space *scratch)
if (!dc_update_probes_prepare(scratch))
goto release_scratch;
+ if (!api_shim_update_state_supported(scratch))
+ goto release_scratch;
+
return true;
release_scratch:
@@ -8520,9 +8524,7 @@ bool dc_update_state_prepare(struct dc_update_scratch_space *scratch)
return false;
}
-void dc_update_state_execute(
- const struct dc_update_scratch_space *scratch
-)
+void legacy_update_state_execute(const struct dc_update_scratch_space *scratch)
{
if (scratch->stream)
scratch->update_v3
@@ -8533,6 +8535,13 @@ void dc_update_state_execute(
dc_update_probes_execute(scratch);
}
+void dc_update_state_execute(
+ const struct dc_update_scratch_space *scratch
+)
+{
+ api_shim_update_state_execute(scratch);
+}
+
bool dc_update_state_cleanup(
struct dc_update_scratch_space *scratch
)
diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2.c b/drivers/gpu/drm/amd/display/dc/core2/dc_core2.c
index 43bb5f461ef2..052f29df1797 100644
--- a/drivers/gpu/drm/amd/display/dc/core2/dc_core2.c
+++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2.c
@@ -7,6 +7,7 @@
#include "dc.h"
#include "core_types.h"
#include "resource.h"
+#include "vm_helper.h"
#include "dc_bios_types.h"
#include "bls_builder/bls_builder.h"
#include "bls_executor/bls_executor.h"
@@ -20,10 +21,17 @@ static void core2_hardware_release(struct dc *dc)
dc2_legacy_funcs()->hardware_release(dc);
}
+static bool core2_update_state_supported(
+ const struct dc_update_scratch_space *scratch);
+static void core2_update_state_execute(
+ const struct dc_update_scratch_space *scratch);
+
static const struct dc2_funcs core2_funcs_table = {
.hardware_init = core2_hardware_init,
.hardware_release = core2_hardware_release,
.commit_state_hw = core2_commit_state_hw,
+ .update_state_supported = core2_update_state_supported,
+ .update_state_execute = core2_update_state_execute,
};
const struct dc2_funcs *core2_funcs(void)
@@ -136,27 +144,69 @@ static void core2_commit_disable_done(struct dc *dc, struct pipe_ctx *pipe)
dc->optimized_required = true;
}
-/* Never falls back to legacy_commit_state_hw: DC2 must not call DC1. */
-enum dc_status core2_commit_state_hw(struct dc *dc, struct dc_state *context)
+/* Builds and runs one declarative builder from dc->current_state to new_state. */
+static enum dc_status core2_build_and_run(struct dc *dc,
+ enum bls_builder_name name, struct dc_state *new_state)
{
- const struct bls_builder *builder =
- TO_DC2(dc)->builders[DCN_DECL_NON_SEAMLESS_COMMIT];
+ const struct bls_builder *builder = TO_DC2(dc)->builders[name];
const struct workaround_manager *wam = dc2_workaround_manager_get();
+ struct bls_builder_declarative_params *params;
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+
+ /* 256 block-sequence entries; keep them off the kernel stack. */
+ params = kvzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return DC_ERROR_UNEXPECTED;
+ params->dc = dc;
+ params->current_state = dc->current_state;
+ params->new_state = new_state;
+
+ /*
+ * A tail runs on the vsync after the head, so Core would have to wait
+ * for that vsync on the stream first. Core has no wait-for-vsync
+ * imperative yet, so a builder that emits a tail is not supported.
+ */
+ if (builder->build.declarative(params) != BLS_BUILD_SUCCESS ||
+ params->tail_num_steps) {
+ status = DC_NOT_SUPPORTED;
+ goto out;
+ }
+ if (!core2_run_commit_sequence(dc, builder, wam,
+ params->head_sequence, ¶ms->head_num_steps))
+ goto out;
+ status = DC_OK;
+
+out:
+ kvfree(params);
+ return status;
+}
+
+static bool core2_builder_supports(struct dc *dc, enum bls_builder_name name,
+ struct dc_state *new_state)
+{
+ const struct bls_builder *builder = TO_DC2(dc)->builders[name];
struct bls_builder_check_capability_params check = {
.dc = dc,
.current_state = dc->current_state,
- .new_state = context,
+ .new_state = new_state,
};
- struct bls_builder_declarative_params *params;
+
+ return builder && builder->check_capability &&
+ builder->kind == BLS_BUILDER_DECLARATIVE &&
+ builder->build.declarative &&
+ dc2_workaround_manager_get() &&
+ builder->check_capability(&check) &&
+ core2_is_accelerated_mode(dc);
+}
+
+/* Never falls back to legacy_commit_state_hw: DC2 must not call DC1. */
+enum dc_status core2_commit_state_hw(struct dc *dc, struct dc_state *context)
+{
struct pipe_ctx *old_pipe;
struct pipe_ctx *new_pipe;
- enum dc_status status = DC_ERROR_UNEXPECTED;
+ enum dc_status status;
- if (!builder || !builder->check_capability ||
- builder->kind != BLS_BUILDER_DECLARATIVE ||
- !builder->build.declarative || !wam ||
- !builder->check_capability(&check) ||
- !core2_is_accelerated_mode(dc))
+ if (!core2_builder_supports(dc, DCN_DECL_NON_SEAMLESS_COMMIT, context))
return DC_NOT_SUPPORTED;
old_pipe = core2_otg_master(dc->current_state);
@@ -170,38 +220,114 @@ enum dc_status core2_commit_state_hw(struct dc *dc, struct dc_state *context)
if (new_pipe)
resource_build_info_frame(new_pipe);
- /* 128 block-sequence entries; keep them off the kernel stack. */
- params = kvzalloc(sizeof(*params), GFP_KERNEL);
- if (!params)
- return DC_ERROR_UNEXPECTED;
- params->dc = dc;
- params->current_state = dc->current_state;
- params->new_state = context;
-
- if (builder->build.declarative(params) != BLS_BUILD_SUCCESS) {
- status = DC_NOT_SUPPORTED;
- goto out;
- }
- if (!core2_run_commit_sequence(dc, builder, wam,
- params->head_sequence, ¶ms->head_num_steps))
- goto out;
- /*
- * The head ends with the ODM double-buffer and blank waits when it
- * programs an OTG. The tail is deferred until that head returns, so
- * it runs after double buffering completes.
- */
- if (!core2_run_commit_sequence(dc, builder, wam,
- params->tail_sequence, ¶ms->tail_num_steps))
- goto out;
+ status = core2_build_and_run(dc, DCN_DECL_NON_SEAMLESS_COMMIT, context);
+ if (status != DC_OK)
+ return status;
core2_commit_prepare_done(dc, context);
if (old_pipe)
core2_commit_disable_done(dc, old_pipe);
if (new_pipe)
core2_commit_enable_done(new_pipe);
- status = DC_OK;
+ return DC_OK;
+}
-out:
- kvfree(params);
- return status;
+/*
+ * The stream update may move the stream's source and destination
+ * rectangles, which the new context already holds. Anything else asks
+ * for stream programming that the full update does not build.
+ */
+static bool core2_stream_update_supported(
+ const struct dc_stream_update *update)
+{
+ if (!update)
+ return true;
+ return !update->hdr_static_metadata && !update->abm_level &&
+ !update->periodic_interrupt &&
+ !update->vrr_infopacket && !update->vsc_infopacket &&
+ !update->vsp_infopacket && !update->hfvsif_infopacket &&
+ !update->vtem_infopacket &&
+ !update->adaptive_sync_infopacket &&
+ !update->avi_infopacket && !update->dpms_off &&
+ !update->gamut_remap && !update->output_color_space &&
+ !update->dither_option &&
+ !update->output_csc_transform && !update->dsc_config &&
+ !update->mst_bw_update && !update->func_shaper &&
+ !update->lut3d_func && !update->pending_test_pattern &&
+ !update->crtc_timing_adjust &&
+ !update->cursor_attributes && !update->cursor_position &&
+ !(update->wb_update && update->wb_update->num_wb_info);
+}
+
+static bool core2_update_state_supported(
+ const struct dc_update_scratch_space *scratch)
+{
+ /* Probes and v2 updates have no DC2 path. */
+ if (!scratch->stream || !scratch->update_v3 || scratch->probe_updates)
+ return false;
+ /*
+ * Only a full update on a new context has a builder. A context-full
+ * flow keeps dc->current_state, so its update type is below FULL.
+ */
+ if (scratch->update_type != UPDATE_TYPE_FULL ||
+ scratch->flow != UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS)
+ return false;
+ /* The full-update builder adds one plane. */
+ if (scratch->surface_count != 1)
+ return false;
+ if (!core2_stream_update_supported(scratch->stream_update))
+ return false;
+ return core2_builder_supports(scratch->dc, DCN_DECL_SEAMLESS_UPDATE,
+ scratch->new_context);
+}
+
+/*
+ * The software state commit_planes_for_stream writes while it programs
+ * the plane. The swap to the new context stays in
+ * dc_update_state_cleanup.
+ */
+static void core2_update_done(struct dc *dc, struct dc_state *context)
+{
+ struct pipe_ctx *pipe = core2_otg_master(context);
+ struct dc_plane_state *plane;
+ struct hubp *hubp;
+
+ if (!pipe || !pipe->plane_state || !pipe->plane_res.hubp ||
+ !pipe->stream_res.opp)
+ return;
+ plane = pipe->plane_state;
+ hubp = pipe->plane_res.hubp;
+
+ vm_helper_mark_vmid_used(dc->vm_helper, plane->address.vmid,
+ (uint8_t)hubp->inst);
+ plane->status.requested_address = plane->address;
+ hubp->opp_id = pipe->stream_res.opp->inst;
+ hubp->mpcc_id = hubp->inst;
+ hubp->power_gated = false;
+ core2_commit_prepare_done(dc, context);
+}
+
+static void core2_update_state_execute(
+ const struct dc_update_scratch_space *scratch)
+{
+ struct dc *dc = scratch->dc;
+ struct dc_state *context = scratch->new_context;
+ struct pipe_ctx *pipe = core2_otg_master(context);
+
+ /*
+ * The values DC1 computes into the context before it programs the
+ * plane. The builder reads them from the context.
+ */
+ if (!pipe || !pipe->plane_state)
+ return;
+ if (dc->res_pool->funcs->prepare_mcache_programming)
+ dc->res_pool->funcs->prepare_mcache_programming(dc, context);
+ pipe->plane_res.scl_data.lb_params.alpha_en =
+ pipe->plane_state->per_pixel_alpha;
+
+ if (core2_build_and_run(dc, DCN_DECL_SEAMLESS_UPDATE, context) != DC_OK) {
+ ASSERT(false);
+ return;
+ }
+ core2_update_done(dc, context);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.c b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.c
index eca9b2de92fa..5d7117501428 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.c
@@ -5,6 +5,7 @@
#include "dm_services.h"
#include "dc.h"
+#include "core_types.h"
#include "dc_api_dispatch/api_shim.h"
#include "core2/dc_core2.h"
#include "inc/dc_core_interface.h"
@@ -37,3 +38,20 @@ enum dc_status api_shim_commit_state_hw(struct dc *dc, struct dc_state *context)
return core2_funcs()->commit_state_hw(dc, context);
return legacy_commit_state_hw(dc, context);
}
+
+bool api_shim_update_state_supported(
+ const struct dc_update_scratch_space *scratch)
+{
+ if (TO_DC2(scratch->dc)->selection == DC2_SELECTION_CORE2)
+ return core2_funcs()->update_state_supported(scratch);
+ return true;
+}
+
+void api_shim_update_state_execute(
+ const struct dc_update_scratch_space *scratch)
+{
+ if (TO_DC2(scratch->dc)->selection == DC2_SELECTION_CORE2)
+ core2_funcs()->update_state_execute(scratch);
+ else
+ legacy_update_state_execute(scratch);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h
index 6d9ad4192296..93dd2d47c8dc 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h
@@ -24,3 +24,7 @@ struct dc2 {
void api_shim_construct(struct dc *dc, const struct dc_init_data *init_params);
enum dc_status api_shim_commit_state_hw(struct dc *dc, struct dc_state *context);
+bool api_shim_update_state_supported(
+ const struct dc_update_scratch_space *scratch);
+void api_shim_update_state_execute(
+ const struct dc_update_scratch_space *scratch);
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 a6c743d0cc58..6996ce12a17d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -423,6 +423,68 @@ struct bios_set_scratch_critical_state_params {
bool state;
};
+struct tg_wait_for_all_pending_updates_params {
+ struct timing_generator *tg;
+ bool include_pipe_update;
+ unsigned int polling_interval_us;
+ unsigned int timeout_us;
+};
+
+struct dc_udelay_params {
+ unsigned int us;
+};
+
+struct hubbub_force_wm_propagate_to_pipes_params {
+ struct hubbub *hubbub;
+};
+
+struct mpc_set_gamut_remap_bypass_params {
+ struct mpc *mpc;
+ int mpcc_id;
+ enum mpcc_gamut_remap_id block_id;
+};
+
+struct mpc_set_movable_cm_location_params {
+ struct mpc *mpc;
+ enum mpcc_movable_cm_location location;
+ int mpcc_id;
+};
+
+struct mpc_program_lut_mode_params {
+ struct mpc *mpc;
+ enum MCM_LUT_ID id;
+ bool enable;
+ bool lut_bank_a;
+ enum dc_cm_lut_size size;
+ int mpcc_id;
+};
+
+struct mpc_set_output_gamma_params {
+ struct mpc *mpc;
+ int mpcc_id;
+ const struct pwl_params *params;
+};
+
+struct dpp_set_pre_degam_params {
+ struct dpp *dpp;
+ const struct dc_transfer_func *in_transfer_func;
+};
+
+struct dpp_program_gamcor_lut_params {
+ struct dpp *dpp;
+ const struct pwl_params *params;
+};
+
+struct hubp_program_3dlut_fl_config_params {
+ struct hubp *hubp;
+ const struct dc_3dlut_dma *config;
+};
+
+struct hubp_set_3dlut_fl_params {
+ struct hubp *hubp;
+ bool enable;
+};
+
struct lsdma_send_pio_copy_params {
struct dc_dmub_srv *dc_dmub_srv;
uint64_t src_addr;
@@ -1525,6 +1587,22 @@ union block_sequence_params {
struct hubbub_program_watermarks_params hubbub_program_watermarks_params;
struct hubbub_program_arbiter_params hubbub_program_arbiter_params;
struct hubbub_program_compbuf_segments_params hubbub_program_compbuf_segments_params;
+ struct tg_wait_for_all_pending_updates_params
+ tg_wait_for_all_pending_updates_params;
+ struct dc_udelay_params dc_udelay_params;
+ struct hubbub_force_wm_propagate_to_pipes_params
+ hubbub_force_wm_propagate_to_pipes_params;
+ struct mpc_set_gamut_remap_bypass_params
+ mpc_set_gamut_remap_bypass_params;
+ struct mpc_set_movable_cm_location_params
+ mpc_set_movable_cm_location_params;
+ struct mpc_program_lut_mode_params mpc_program_lut_mode_params;
+ struct mpc_set_output_gamma_params mpc_set_output_gamma_params;
+ struct dpp_set_pre_degam_params dpp_set_pre_degam_params;
+ struct dpp_program_gamcor_lut_params dpp_program_gamcor_lut_params;
+ struct hubp_program_3dlut_fl_config_params
+ hubp_program_3dlut_fl_config_params;
+ struct hubp_set_3dlut_fl_params hubp_set_3dlut_fl_params;
};
enum block_sequence_func {
@@ -1754,6 +1832,17 @@ enum block_sequence_func {
DIO_LINK_ENC_ENABLE_DP_OUTPUT,
DIO_LINK_ENC_DISABLE_OUTPUT,
BIOS_SET_SCRATCH_CRITICAL_STATE,
+ TG_WAIT_FOR_ALL_PENDING_UPDATES,
+ DC_UDELAY,
+ HUBBUB_FORCE_WM_PROPAGATE_TO_PIPES,
+ MPC_SET_GAMUT_REMAP_BYPASS,
+ MPC_SET_MOVABLE_CM_LOCATION,
+ MPC_PROGRAM_LUT_MODE,
+ MPC_SET_OUTPUT_GAMMA,
+ DPP_SET_PRE_DEGAM,
+ DPP_PROGRAM_GAMCOR_LUT,
+ HUBP_PROGRAM_3DLUT_FL_CONFIG,
+ HUBP_SET_3DLUT_FL,
/* This must be the last value in this enum, add new ones above */
HWSS_BLOCK_SEQUENCE_FUNC_COUNT
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_core_interface.h b/drivers/gpu/drm/amd/display/dc/inc/dc_core_interface.h
index 383d14af91f1..4cd01e34a959 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_core_interface.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_core_interface.h
@@ -9,6 +9,7 @@
struct dc;
struct dc_state;
+struct dc_update_scratch_space;
/*
* Construction-time Core implementation selection. Zero is LEGACY so existing
@@ -28,9 +29,15 @@ struct dc2_funcs {
void (*hardware_init)(struct dc *dc);
void (*hardware_release)(struct dc *dc);
enum dc_status (*commit_state_hw)(struct dc *dc, struct dc_state *context);
+ /* Checked in prepare; execute returns void, so it cannot reject. */
+ bool (*update_state_supported)(
+ const struct dc_update_scratch_space *scratch);
+ void (*update_state_execute)(
+ const struct dc_update_scratch_space *scratch);
};
void legacy_hardware_init(struct dc *dc);
void legacy_hardware_release(struct dc *dc);
enum dc_status legacy_commit_state_hw(struct dc *dc, struct dc_state *context);
+void legacy_update_state_execute(const struct dc_update_scratch_space *scratch);
const struct dc2_funcs *dc2_legacy_funcs(void);
--
2.43.0
next prev parent reply other threads:[~2026-11-11 1:42 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 1:28 [PATCH 00/74] DC Patches November 16, 2026 Wayne Lin
2026-11-11 1:28 ` [PATCH 01/74] drm/amd/display: Fix elapsed time indentation Wayne Lin
2026-11-11 1:28 ` [PATCH 02/74] drm/amd/display: Correct the forced YCbCr420 comment Wayne Lin
2026-11-11 1:28 ` [PATCH 03/74] drm/amd/display: Remove duplicate block sequence leftovers Wayne Lin
2026-11-11 1:28 ` [PATCH 04/74] drm/amd/display: Skip UPSP programming when UPSP regs are absent Wayne Lin
2026-11-11 1:28 ` [PATCH 05/74] drm/amd/display: Dispatch commit_state_hw through dc2_funcs Wayne Lin
2026-11-11 1:28 ` [PATCH 06/74] drm/amd/display: Add leaf BLS entries for a virtual commit Wayne Lin
2026-11-11 1:28 ` [PATCH 07/74] drm/amd/display: Build the dcn401 virtual commit natively Wayne Lin
2026-11-11 1:28 ` [PATCH 08/74] drm/amd/display: Move HDMI FRL Polling Outside dc_lock Wayne Lin
2026-11-11 1:28 ` [PATCH 09/74] drm/amd/display: Extend the IOMMU mismatch workaround to DCN42B Wayne Lin
2026-11-11 1:28 ` [PATCH 10/74] drm/amd/display: Stop HDMI FRL status polling on fini Wayne Lin
2026-11-12 8:51 ` Eren Özen
2026-11-13 3:19 ` Wayne Lin
2026-11-11 1:28 ` [PATCH 11/74] drm/amd/display: Relax stutter constraints for DRR streams Wayne Lin
2026-11-11 1:28 ` [PATCH 12/74] drm/amd/display: Include Ramless Idle in stutter relaxation Wayne Lin
2026-11-11 1:28 ` [PATCH 13/74] drm/amd/display: Initialize DMUB LSDMA ring buffer Wayne Lin
2026-11-11 1:28 ` [PATCH 14/74] drm/amd/display: Fix FFE test automation link rate change Wayne Lin
2026-11-11 1:28 ` [PATCH 15/74] drm/amd/display: Update indicate pstate enable sequence Wayne Lin
2026-11-11 1:28 ` [PATCH 16/74] drm/amd/display: HWSS Refactor - Watermarks Wayne Lin
2026-11-11 1:28 ` [PATCH 17/74] drm/amd/display: Resolve clk_mgr DPP DTO targets when the sequence is built Wayne Lin
2026-11-11 1:28 ` [PATCH 18/74] drm/amd/display: Resolve clk_mgr DTBCLK " Wayne Lin
2026-11-11 1:28 ` [PATCH 19/74] drm/amd/display: Resolve the DCN401 DENTIST divider " Wayne Lin
2026-11-11 1:28 ` [PATCH 20/74] drm/amd/display: Update default VCO frequency Wayne Lin
2026-11-11 1:28 ` [PATCH 21/74] drm/amd/display: commit validated target when minimal transition cannot be built Wayne Lin
2026-11-11 1:28 ` [PATCH 22/74] drm/amd/display: Update DP HPO to use correct APG instance Wayne Lin
2026-11-11 1:28 ` [PATCH 23/74] drm/amd/display: cleanup tiling and address formats Wayne Lin
2026-11-11 1:28 ` [PATCH 24/74] drm/amd/display: Enable SST PCON FRL DSC passthrough Wayne Lin
2026-11-11 1:28 ` [PATCH 25/74] drm/amd/display: Don't let HPD IRQ handler take dc_lock in reset Wayne Lin
2026-11-11 1:28 ` [PATCH 26/74] drm/amd/display: Skip visual confirm color programming when FW owns it Wayne Lin
2026-11-11 1:28 ` [PATCH 27/74] drm/amd/display: Fix Stage Optimizer Parameter Naming Wayne Lin
2026-11-11 1:28 ` Wayne Lin [this message]
2026-11-11 1:28 ` [PATCH 29/74] drm/amd/display: Read accelerated mode through a query builder Wayne Lin
2026-11-11 1:28 ` [PATCH 30/74] drm/amd/display: Ensure exit IPS before checking flip status Wayne Lin
2026-11-11 1:28 ` [PATCH 31/74] drm/amd/display: Updating missing assignments for DCN6 Wayne Lin
2026-11-11 1:28 ` [PATCH 32/74] drm/amd/display: update dcn42b based on dcn42 Wayne Lin
2026-11-11 1:28 ` [PATCH 33/74] drm/amd/display: Build the kept-plane surface update in DC2 Wayne Lin
2026-11-11 1:28 ` [PATCH 34/74] drm/amd/display: Skip first-enable steps on a kept plane Wayne Lin
2026-11-11 1:28 ` [PATCH 35/74] drm/amd/display: Enable DRR stutter constraint relaxation on DCN42 Wayne Lin
2026-11-11 1:28 ` [PATCH 36/74] drm/amd/display: detect static screen state and propagate Wayne Lin
2026-11-11 1:28 ` [PATCH 37/74] drm/amd/display: Allow DC_PSR_MASK to enable PSR without DMUB PSR cap Wayne Lin
2026-11-11 1:28 ` [PATCH 38/74] drm/amd/display: Fix DSC teardown gating in post-unlock BLS sequence Wayne Lin
2026-11-11 1:28 ` [PATCH 39/74] drm/amd/display: Enable HDCP on DCN6 Wayne Lin
2026-11-11 1:28 ` [PATCH 40/74] drm/amd/display: enable DF C-state vote on DCN42B Wayne Lin
2026-11-11 1:28 ` [PATCH 41/74] drm/amd/display: Increase the DCN42 DDR5 stutter latency Wayne Lin
2026-11-11 1:28 ` [PATCH 42/74] drm/amd/display: [FW Promotion] Release 0.1.83.0 Wayne Lin
2026-11-11 1:28 ` [PATCH 43/74] drm/amd/display: Promote DC to 3.2.406 Wayne Lin
2026-11-11 1:28 ` [PATCH 44/74] drm/amd/display: Fix KUnit tiled EDID size Wayne Lin
2026-11-12 7:17 ` Eren Özen
2026-11-11 1:28 ` [PATCH 45/74] drm/amd/display: fix hubbub read state logging Wayne Lin
2026-11-11 1:28 ` [PATCH 46/74] drm/amd/display: Keep panel power across link-loss retrain Wayne Lin
2026-11-11 1:28 ` [PATCH 47/74] drm/amd/display: Don't shrink zero-area recout in full viewport visual confirm Wayne Lin
2026-11-11 1:28 ` [PATCH 48/74] drm/amd/display: Keep patched HDMI panels on FRL across detect Wayne Lin
2026-11-11 1:28 ` [PATCH 49/74] drm/amd/display: Use expanded DMUB-provided SoC BB and IP caps Wayne Lin
2026-11-11 1:28 ` [PATCH 50/74] drm/amd/display: Only force P-State on first plane if TTU is below WM Wayne Lin
2026-11-11 1:28 ` [PATCH 51/74] drm/amd/display: Program the kept-plane scaler in DC2 Wayne Lin
2026-11-11 1:28 ` [PATCH 52/74] drm/amd/display: Add and remove two MPO planes " Wayne Lin
2026-11-11 1:28 ` [PATCH 53/74] drm/amd/display: Add DC2 state facts and split the builders Wayne Lin
2026-11-11 1:29 ` [PATCH 54/74] drm/amd/display: Program DC2 commit stereo once Wayne Lin
2026-11-11 1:29 ` [PATCH 55/74] drm/amd/display: Read DCN6 SOP constraints from the idle row Wayne Lin
2026-11-11 1:29 ` [PATCH 56/74] drm/amd/display: Use soc_bb hostvm fraction instead of hardcoded value Wayne Lin
2026-11-11 1:29 ` [PATCH 57/74] drm/amd/display: Increase state if dcfclk deep sleep needed exceeds dcfclk Wayne Lin
2026-11-11 1:29 ` [PATCH 58/74] drm/amd/display: Flip dml2_core_utils_get_segment_horizontal_contiguous() Inputs Wayne Lin
2026-11-11 1:29 ` [PATCH 59/74] drm/amd/display: Update DCN6 Calcs Wayne Lin
2026-11-11 1:29 ` [PATCH 60/74] drm/amd/display: Add effective_number_of_dpp parameter Wayne Lin
2026-11-11 1:29 ` [PATCH 61/74] drm/amd/display: Read DRAM channel width from SMU init table Wayne Lin
2026-11-11 1:29 ` [PATCH 62/74] drm/amd/display: Update DCN42B stutter latency to match DCN42 Wayne Lin
2026-11-11 1:29 ` [PATCH 63/74] drm/amd/display: Expect VRAM|GTT for the DMUB framebuffer Wayne Lin
2026-11-12 7:17 ` Eren Özen
2026-11-11 1:29 ` [PATCH 64/74] drm/amd/display: Report QoS latency bounds and request Wayne Lin
2026-11-11 1:29 ` [PATCH 65/74] drm/amd/display: Bypass chroma upsampling without the DPP cap Wayne Lin
2026-11-11 1:29 ` [PATCH 66/74] drm/amd/display: Limit VRAM aperture retrieval to DCN6 Wayne Lin
2026-11-11 1:29 ` [PATCH 67/74] drm/amd/display: Make DPP_PG_CONTROL and HUBP_PG_CONTROL BLS compliant Wayne Lin
2026-11-11 1:29 ` [PATCH 68/74] drm/amd/display: Seed boot clocks to avoid lowering pre-OS display clocks Wayne Lin
2026-11-11 1:29 ` [PATCH 69/74] drm/amd/display: Account for split pipe overlap in alt channel copy size Wayne Lin
2026-11-11 1:29 ` [PATCH 70/74] drm/amd/display: Get OPP heads and DPP pipes by stream in dc_resource Wayne Lin
2026-11-11 1:29 ` [PATCH 71/74] drm/amd/display: Program ODM 2:1 and 3:1 on one stream in DC2 Wayne Lin
2026-11-11 1:29 ` [PATCH 72/74] drm/amd/display: Enable Replay timing sync by default Wayne Lin
2026-11-11 1:29 ` [PATCH 73/74] drm/amd/display: [FW Promotion] Release 0.1.84.0 Wayne Lin
2026-11-11 1:29 ` [PATCH 74/74] drm/amd/display: Promote DC to 3.2.407 Wayne Lin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261111014100.3596072-29-Wayne.Lin@amd.com \
--to=wayne.lin@amd.com \
--cc=Chen-Yu.Chen@amd.com \
--cc=PingLei.Lin@amd.com \
--cc=Ray.Wu@amd.com \
--cc=alex.hung@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=aurabindo.pillai@amd.com \
--cc=chiahsuan.chung@amd.com \
--cc=daniel.wheeler@amd.com \
--cc=harry.wentland@amd.com \
--cc=ivan.lipski@amd.com \
--cc=jerry.zuo@amd.com \
--cc=jun.lei@amd.com \
--cc=roman.li@amd.com \
--cc=sunpeng.li@amd.com \
--cc=tony.cheng@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox