]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Driver implementation for cursor offloading to DMU
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tue, 26 Aug 2025 21:12:44 +0000 (17:12 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 13 Oct 2025 18:14:32 +0000 (14:14 -0400)
[Why]
We require an interlock between driver and firmware for upcoming
features and given that this could possibly happen on any single
cursor programming call (and that we can't asynchronously wait for
firmware to respond because of it) we'd be regressing cursor performance
by at least an extra 40us per call.

When we could possibly have cursor update every 20us - 100s from high
frequency gaming mice this means that we'd be stuttering or dropping
updates and impacting overall cursor performance.

We want a solution that can:

1. Interlock between other firmware features
2. Not stall out or require the DMCUB lock for every single update

[How]
When cursor offloading is enabled and supported by an ASIC driver will
route the cursor programming through to DMU as part of the regular
DC stream cursor programming interfaces for attributes and position.

The atomic pipe programming version will not be updated: this will still
follow the existing programming path by keeping track of a field that
specifies when the register writes should be deferred to DMU.

Cursor locking is not required when cursor offload is in progress since
the updates are consolidated and processed by DMU once at the end
of the frame in a periodic manner.

The shared buffer the firmware queries from is allocated along with the
rest of the scratch state region in an area that's accessible by
both firmware and driver.

The size of the cursor offload (v1) state will not change, but it does
have a unique union per ASIC version with room for expansion if needed.

When firmware features notifying DMU of DRR updates are not enabled we
now send an explicit vtotal min/max update via driver to DMU firmware
whenever the vtotal max changes. This is to allow the cursor programming
to determine the appropriate latch update point offset from vupdate.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
25 files changed:
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/core/dc_stream.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp.c
drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c
drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
drivers/gpu/drm/amd/display/dc/inc/hw/cursor_reg_cache.h
drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
drivers/gpu/drm/amd/display/dmub/dmub_srv.h
drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c

index eae2dabd5182c476f7a3a8a9a7cb68d4c688ed3b..2c2635b6cb0f5782b6f364fab10cd916b1ba8705 100644 (file)
@@ -496,6 +496,10 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
                        return true;
                }
        }
+
+       if (dc->hwss.notify_cursor_offload_drr_update)
+               dc->hwss.notify_cursor_offload_drr_update(dc, dc->current_state, stream);
+
        return false;
 }
 
@@ -2188,8 +2192,14 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
                dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
        }
 
+       for (i = 0; i < dc->current_state->stream_count; i++)
+               dc_dmub_srv_control_cursor_offload(dc, dc->current_state, dc->current_state->streams[i], false);
+
        result = dc->hwss.apply_ctx_to_hw(dc, context);
 
+       for (i = 0; i < context->stream_count; i++)
+               dc_dmub_srv_control_cursor_offload(dc, context, context->streams[i], true);
+
        if (result != DC_OK) {
                /* Application of dc_state to hardware stopped. */
                dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
@@ -4488,6 +4498,8 @@ static void commit_planes_for_stream(struct dc *dc,
                                pipe_ctx->plane_state->skip_manual_trigger)
                        continue;
 
+               if (dc->hwss.program_cursor_offload_now)
+                       dc->hwss.program_cursor_offload_now(dc, pipe_ctx);
                if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger)
                        pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg);
        }
index 25a07e5f4ed77b1aa9865f3eaf75da6c77d8da99..1bed3b14a287e993750bbaf07a169b1863794a32 100644 (file)
@@ -911,6 +911,13 @@ void hwss_build_fast_sequence(struct dc *dc,
                                        current_mpc_pipe->stream && current_mpc_pipe->plane_state &&
                                        current_mpc_pipe->plane_state->update_flags.bits.addr_update &&
                                        !current_mpc_pipe->plane_state->skip_manual_trigger) {
+                               if (dc->hwss.program_cursor_offload_now) {
+                                       block_sequence[*num_steps].params.program_cursor_update_now_params.dc = dc;
+                                       block_sequence[*num_steps].params.program_cursor_update_now_params.pipe_ctx = current_mpc_pipe;
+                                       block_sequence[*num_steps].func = PROGRAM_CURSOR_UPDATE_NOW;
+                                       (*num_steps)++;
+                               }
+
                                block_sequence[*num_steps].params.program_manual_trigger_params.pipe_ctx = current_mpc_pipe;
                                block_sequence[*num_steps].func = OPTC_PROGRAM_MANUAL_TRIGGER;
                                (*num_steps)++;
@@ -1004,6 +1011,11 @@ void hwss_execute_sequence(struct dc *dc,
                case DMUB_HW_CONTROL_LOCK_FAST:
                        dc->hwss.dmub_hw_control_lock_fast(params);
                        break;
+               case PROGRAM_CURSOR_UPDATE_NOW:
+                       dc->hwss.program_cursor_offload_now(
+                               params->program_cursor_update_now_params.dc,
+                               params->program_cursor_update_now_params.pipe_ctx);
+                       break;
                default:
                        ASSERT(false);
                        break;
index 9ac2d41f8fcae1c5e4a66e003872c95b3e5bff51..ccaf37d3e7e4a1eb5a9f5e9d46ba1fdd83a6d918 100644 (file)
@@ -231,6 +231,7 @@ void program_cursor_attributes(
        int i;
        struct resource_context *res_ctx;
        struct pipe_ctx *pipe_to_program = NULL;
+       bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc);
 
        if (!stream)
                return;
@@ -245,9 +246,14 @@ void program_cursor_attributes(
 
                if (!pipe_to_program) {
                        pipe_to_program = pipe_ctx;
-                       dc->hwss.cursor_lock(dc, pipe_to_program, true);
-                       if (pipe_to_program->next_odm_pipe)
-                               dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
+
+                       if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
+                               dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
+                       } else {
+                               dc->hwss.cursor_lock(dc, pipe_to_program, true);
+                               if (pipe_to_program->next_odm_pipe)
+                                       dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
+                       }
                }
 
                dc->hwss.set_cursor_attribute(pipe_ctx);
@@ -255,12 +261,18 @@ void program_cursor_attributes(
                        dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
                if (dc->hwss.set_cursor_sdr_white_level)
                        dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
+               if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
+                       dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
        }
 
        if (pipe_to_program) {
-               dc->hwss.cursor_lock(dc, pipe_to_program, false);
-               if (pipe_to_program->next_odm_pipe)
-                       dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
+               if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
+                       dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
+               } else {
+                       dc->hwss.cursor_lock(dc, pipe_to_program, false);
+                       if (pipe_to_program->next_odm_pipe)
+                               dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
+               }
        }
 }
 
@@ -366,6 +378,7 @@ void program_cursor_position(
        int i;
        struct resource_context *res_ctx;
        struct pipe_ctx *pipe_to_program = NULL;
+       bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc);
 
        if (!stream)
                return;
@@ -384,16 +397,27 @@ void program_cursor_position(
 
                if (!pipe_to_program) {
                        pipe_to_program = pipe_ctx;
-                       dc->hwss.cursor_lock(dc, pipe_to_program, true);
+
+                       if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update)
+                               dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
+                       else
+                               dc->hwss.cursor_lock(dc, pipe_to_program, true);
                }
 
                dc->hwss.set_cursor_position(pipe_ctx);
+               if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
+                       dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+
                if (dc->ctx->dmub_srv)
                        dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
        }
 
-       if (pipe_to_program)
-               dc->hwss.cursor_lock(dc, pipe_to_program, false);
+       if (pipe_to_program) {
+               if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update)
+                       dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
+               else
+                       dc->hwss.cursor_lock(dc, pipe_to_program, false);
+       }
 }
 
 bool dc_stream_set_cursor_position(
index 35140b3e1332a79958dcad434fd56435e3ba48dd..0494e6cd3b33dc8f9c8894f6e1f867aa929fe70d 100644 (file)
@@ -530,6 +530,7 @@ struct dc_config {
        bool set_pipe_unlock_order;
        bool enable_dpia_pre_training;
        bool unify_link_enc_assignment;
+       bool enable_cursor_offload;
        struct spl_sharpness_range dcn_sharpness_range;
        struct spl_sharpness_range dcn_override_sharpness_range;
 };
index 53a088ebddefe6c111629fe098876903046124cb..c75663aefcf3ff2b5d58503cbec84d30dd634c63 100644 (file)
@@ -1174,6 +1174,100 @@ void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, con
        dmub_srv_subvp_save_surf_addr(dc_dmub_srv->dmub, addr, subvp_index);
 }
 
+void dc_dmub_srv_cursor_offload_init(struct dc *dc)
+{
+       struct dmub_rb_cmd_cursor_offload_init *init;
+       struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
+       union dmub_rb_cmd cmd;
+
+       if (!dc->config.enable_cursor_offload)
+               return;
+
+       if (!dc_dmub_srv->dmub->meta_info.feature_bits.bits.cursor_offload_v1_support)
+               return;
+
+       if (!dc_dmub_srv->dmub->cursor_offload_fb.gpu_addr || !dc_dmub_srv->dmub->cursor_offload_fb.cpu_addr)
+               return;
+
+       if (!dc_dmub_srv->dmub->cursor_offload_v1)
+               return;
+
+       if (!dc_dmub_srv->dmub->shared_state)
+               return;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       init = &cmd.cursor_offload_init;
+       init->header.type = DMUB_CMD__CURSOR_OFFLOAD;
+       init->header.sub_type = DMUB_CMD__CURSOR_OFFLOAD_INIT;
+       init->header.payload_bytes = sizeof(init->init_data);
+       init->init_data.state_addr.quad_part = dc_dmub_srv->dmub->cursor_offload_fb.gpu_addr;
+       init->init_data.state_size = dc_dmub_srv->dmub->cursor_offload_fb.size;
+
+       dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       dc_dmub_srv->cursor_offload_enabled = true;
+}
+
+void dc_dmub_srv_control_cursor_offload(struct dc *dc, struct dc_state *context,
+                                       const struct dc_stream_state *stream, bool enable)
+{
+       struct pipe_ctx const *pipe_ctx;
+       struct dmub_rb_cmd_cursor_offload_stream_cntl *cntl;
+       union dmub_rb_cmd cmd;
+
+       if (!dc_dmub_srv_is_cursor_offload_enabled(dc))
+               return;
+
+       if (!stream)
+               return;
+
+       pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
+       if (!pipe_ctx || !pipe_ctx->stream_res.tg || pipe_ctx->stream != stream)
+               return;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cntl = &cmd.cursor_offload_stream_ctnl;
+       cntl->header.type = DMUB_CMD__CURSOR_OFFLOAD;
+       cntl->header.sub_type =
+               enable ? DMUB_CMD__CURSOR_OFFLOAD_STREAM_ENABLE : DMUB_CMD__CURSOR_OFFLOAD_STREAM_DISABLE;
+       cntl->header.payload_bytes = sizeof(cntl->data);
+
+       cntl->data.otg_inst = pipe_ctx->stream_res.tg->inst;
+       cntl->data.line_time_in_ns = 1u + (uint32_t)(div64_u64(stream->timing.h_total * 1000000ull,
+                                                              stream->timing.pix_clk_100hz / 10));
+
+       cntl->data.v_total_max = stream->adjust.v_total_max > stream->timing.v_total ?
+                                        stream->adjust.v_total_max :
+                                        stream->timing.v_total;
+
+       dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd,
+                                    enable ? DM_DMUB_WAIT_TYPE_NO_WAIT : DM_DMUB_WAIT_TYPE_WAIT);
+}
+
+void dc_dmub_srv_program_cursor_now(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       struct dmub_rb_cmd_cursor_offload_stream_cntl *cntl;
+       union dmub_rb_cmd cmd;
+
+       if (!dc_dmub_srv_is_cursor_offload_enabled(dc))
+               return;
+
+       if (!pipe || !pipe->stream || !pipe->stream_res.tg)
+               return;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cntl = &cmd.cursor_offload_stream_ctnl;
+       cntl->header.type = DMUB_CMD__CURSOR_OFFLOAD;
+       cntl->header.sub_type = DMUB_CMD__CURSOR_OFFLOAD_STREAM_PROGRAM;
+       cntl->header.payload_bytes = sizeof(cntl->data);
+       cntl->data.otg_inst = pipe->stream_res.tg->inst;
+
+       dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT);
+}
+
 bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait)
 {
        struct dc_context *dc_ctx;
@@ -2231,6 +2325,11 @@ bool dmub_lsdma_send_poll_reg_write_command(struct dc_dmub_srv *dc_dmub_srv, uin
        return result;
 }
 
+bool dc_dmub_srv_is_cursor_offload_enabled(const struct dc *dc)
+{
+       return dc->ctx->dmub_srv && dc->ctx->dmub_srv->cursor_offload_enabled;
+}
+
 void dc_dmub_srv_release_hw(const struct dc *dc)
 {
        struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
index 7ef93444ef3cf87e0affeb8851ce27ae8efcdd97..9bb00d48fd5e16e65ec298c63bce34af1a9797e2 100644 (file)
@@ -56,6 +56,7 @@ struct dc_dmub_srv {
        union dmub_shared_state_ips_driver_signals driver_signals;
        bool idle_allowed;
        bool needs_idle_wake;
+       bool cursor_offload_enabled;
 };
 
 bool dc_dmub_srv_wait_for_pending(struct dc_dmub_srv *dc_dmub_srv);
@@ -325,6 +326,41 @@ bool dc_dmub_srv_ips_query_residency_info(const struct dc_context *ctx, uint8_t
                                          struct dmub_ips_residency_info *driver_info,
                                          enum ips_residency_mode ips_mode);
 
+/**
+ * dc_dmub_srv_cursor_offload_init() - Enables or disables cursor offloading for a stream.
+ *
+ * @dc: pointer to DC object
+ */
+void dc_dmub_srv_cursor_offload_init(struct dc *dc);
+
+/**
+ * dc_dmub_srv_control_cursor_offload() - Enables or disables cursor offloading for a stream.
+ *
+ * @dc: pointer to DC object
+ * @context: the DC context to reference for pipe allocations
+ * @stream: the stream to control
+ * @enable: true to enable cursor offload, false to disable
+ */
+void dc_dmub_srv_control_cursor_offload(struct dc *dc, struct dc_state *context,
+                                       const struct dc_stream_state *stream, bool enable);
+
+/**
+ * dc_dmub_srv_program_cursor_now() - Requests immediate cursor programming for a given pipe.
+ *
+ * @dc: pointer to DC object
+ * @pipe: top-most pipe for a stream.
+ */
+void dc_dmub_srv_program_cursor_now(struct dc *dc, const struct pipe_ctx *pipe);
+
+/**
+ * dc_dmub_srv_is_cursor_offload_enabled() - Checks if cursor offload is supported.
+ *
+ * @dc: pointer to DC object
+ *
+ * Return: true if cursor offload is supported, false otherwise
+ */
+bool dc_dmub_srv_is_cursor_offload_enabled(const struct dc *dc);
+
 /**
  * dc_dmub_srv_release_hw() - Notifies DMUB service that HW access is no longer required.
  *
index 01480a04f85ef52680bc0eb2bb946ea36b42c72e..ce91e5d289567e0e07600720c577a14463090e59 100644 (file)
@@ -199,6 +199,8 @@ void dpp_reset(struct dpp *dpp_base)
 
        memset(&dpp->scl_data, 0, sizeof(dpp->scl_data));
        memset(&dpp->pwl_data, 0, sizeof(dpp->pwl_data));
+
+       dpp_base->cursor_offload = false;
 }
 
 
@@ -484,10 +486,12 @@ void dpp1_set_cursor_position(
                cur_en = 0;  /* not visible beyond top edge*/
 
        if (dpp_base->pos.cur0_ctl.bits.cur0_enable != cur_en) {
-               REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, cur_en);
-
-               dpp_base->pos.cur0_ctl.bits.cur0_enable = cur_en;
+               if (!dpp_base->cursor_offload)
+                       REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, cur_en);
        }
+
+       dpp_base->pos.cur0_ctl.bits.cur0_enable = cur_en;
+       dpp_base->att.cur0_ctl.bits.cur0_enable = cur_en;
 }
 
 void dpp1_cnv_set_optional_cursor_attributes(
@@ -497,8 +501,13 @@ void dpp1_cnv_set_optional_cursor_attributes(
        struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
 
        if (attr) {
-               REG_UPDATE(CURSOR0_FP_SCALE_BIAS,  CUR0_FP_BIAS,  attr->bias);
-               REG_UPDATE(CURSOR0_FP_SCALE_BIAS,  CUR0_FP_SCALE, attr->scale);
+               if (!dpp_base->cursor_offload) {
+                       REG_UPDATE(CURSOR0_FP_SCALE_BIAS,  CUR0_FP_BIAS,  attr->bias);
+                       REG_UPDATE(CURSOR0_FP_SCALE_BIAS,  CUR0_FP_SCALE, attr->scale);
+               }
+
+               dpp_base->att.fp_scale_bias.bits.fp_bias = attr->bias;
+               dpp_base->att.fp_scale_bias.bits.fp_scale = attr->scale;
        }
 }
 
index 09be2a90cc79dcdcbdd3f9d394c550ec2d2cc838..94d0dc3461d260526feafe71a7b9a9285529aec3 100644 (file)
@@ -396,17 +396,21 @@ void dpp3_set_cursor_attributes(
                }
        }
 
-       REG_UPDATE_3(CURSOR0_CONTROL,
-                       CUR0_MODE, color_format,
-                       CUR0_EXPANSION_MODE, 0,
-                       CUR0_ROM_EN, cur_rom_en);
+       if (!dpp_base->cursor_offload)
+               REG_UPDATE_3(CURSOR0_CONTROL,
+                               CUR0_MODE, color_format,
+                               CUR0_EXPANSION_MODE, 0,
+                               CUR0_ROM_EN, cur_rom_en);
 
        if (color_format == CURSOR_MODE_MONO) {
                /* todo: clarify what to program these to */
-               REG_UPDATE(CURSOR0_COLOR0,
-                               CUR0_COLOR0, 0x00000000);
-               REG_UPDATE(CURSOR0_COLOR1,
-                               CUR0_COLOR1, 0xFFFFFFFF);
+
+               if (!dpp_base->cursor_offload) {
+                       REG_UPDATE(CURSOR0_COLOR0,
+                                       CUR0_COLOR0, 0x00000000);
+                       REG_UPDATE(CURSOR0_COLOR1,
+                                       CUR0_COLOR1, 0xFFFFFFFF);
+               }
        }
 
        dpp_base->att.cur0_ctl.bits.expansion_mode = 0;
index 7aab77b588694de74542c24f87dc2b1ff8e159bf..3adc17f2fc35b637348e4ddff114149a8eeac7eb 100644 (file)
@@ -103,17 +103,21 @@ void dpp401_set_cursor_attributes(
                }
        }
 
-       REG_UPDATE_3(CURSOR0_CONTROL,
-               CUR0_MODE, color_format,
-               CUR0_EXPANSION_MODE, 0,
-               CUR0_ROM_EN, cur_rom_en);
+       if (!dpp_base->cursor_offload)
+               REG_UPDATE_3(CURSOR0_CONTROL,
+                       CUR0_MODE, color_format,
+                       CUR0_EXPANSION_MODE, 0,
+                       CUR0_ROM_EN, cur_rom_en);
 
        if (color_format == CURSOR_MODE_MONO) {
                /* todo: clarify what to program these to */
-               REG_UPDATE(CURSOR0_COLOR0,
-                       CUR0_COLOR0, 0x00000000);
-               REG_UPDATE(CURSOR0_COLOR1,
-                       CUR0_COLOR1, 0xFFFFFFFF);
+
+               if (!dpp_base->cursor_offload) {
+                       REG_UPDATE(CURSOR0_COLOR0,
+                               CUR0_COLOR0, 0x00000000);
+                       REG_UPDATE(CURSOR0_COLOR1,
+                               CUR0_COLOR1, 0xFFFFFFFF);
+               }
        }
 
        dpp_base->att.cur0_ctl.bits.expansion_mode = 0;
@@ -132,10 +136,11 @@ void dpp401_set_cursor_position(
        uint32_t cur_en = pos->enable ? 1 : 0;
 
        if (dpp_base->pos.cur0_ctl.bits.cur0_enable != cur_en) {
-               REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, cur_en);
-
-               dpp_base->pos.cur0_ctl.bits.cur0_enable = cur_en;
+               if (!dpp_base->cursor_offload)
+                       REG_UPDATE(CURSOR0_CONTROL, CUR0_ENABLE, cur_en);
        }
+
+       dpp_base->pos.cur0_ctl.bits.cur0_enable = cur_en;
 }
 
 void dpp401_set_optional_cursor_attributes(
@@ -145,10 +150,17 @@ void dpp401_set_optional_cursor_attributes(
        struct dcn401_dpp *dpp = TO_DCN401_DPP(dpp_base);
 
        if (attr) {
-               REG_UPDATE(CURSOR0_FP_SCALE_BIAS_G_Y, CUR0_FP_BIAS_G_Y, attr->bias);
-               REG_UPDATE(CURSOR0_FP_SCALE_BIAS_G_Y, CUR0_FP_SCALE_G_Y, attr->scale);
-               REG_UPDATE(CURSOR0_FP_SCALE_BIAS_RB_CRCB, CUR0_FP_BIAS_RB_CRCB, attr->bias);
-               REG_UPDATE(CURSOR0_FP_SCALE_BIAS_RB_CRCB, CUR0_FP_SCALE_RB_CRCB, attr->scale);
+               if (!dpp_base->cursor_offload) {
+                       REG_UPDATE(CURSOR0_FP_SCALE_BIAS_G_Y, CUR0_FP_BIAS_G_Y, attr->bias);
+                       REG_UPDATE(CURSOR0_FP_SCALE_BIAS_G_Y, CUR0_FP_SCALE_G_Y, attr->scale);
+                       REG_UPDATE(CURSOR0_FP_SCALE_BIAS_RB_CRCB, CUR0_FP_BIAS_RB_CRCB, attr->bias);
+                       REG_UPDATE(CURSOR0_FP_SCALE_BIAS_RB_CRCB, CUR0_FP_SCALE_RB_CRCB, attr->scale);
+               }
+
+               dpp_base->att.fp_scale_bias_g_y.bits.fp_bias_g_y = attr->bias;
+               dpp_base->att.fp_scale_bias_g_y.bits.fp_scale_g_y = attr->scale;
+               dpp_base->att.fp_scale_bias_rb_crcb.bits.fp_bias_rb_crcb = attr->bias;
+               dpp_base->att.fp_scale_bias_rb_crcb.bits.fp_scale_rb_crcb = attr->scale;
        }
 }
 
index 9b026600b90e8bb548ddd59e4045e4fc07a74ea7..6378e3fd72494c7d03f56d806e1def8368f60c40 100644 (file)
@@ -550,6 +550,7 @@ void hubp_reset(struct hubp *hubp)
 {
        memset(&hubp->pos, 0, sizeof(hubp->pos));
        memset(&hubp->att, 0, sizeof(hubp->att));
+       hubp->cursor_offload = false;
 }
 
 void hubp1_program_surface_config(
index 91259b896e0320884efedadbe5f36e1a63858f30..92288de4cc10c312959c6179dcb8251ec1e15ed6 100644 (file)
@@ -613,26 +613,28 @@ void hubp2_cursor_set_attributes(
 
        hubp->curs_attr = *attr;
 
-       REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
-                       CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part);
-       REG_UPDATE(CURSOR_SURFACE_ADDRESS,
-                       CURSOR_SURFACE_ADDRESS, attr->address.low_part);
-
-       REG_UPDATE_2(CURSOR_SIZE,
-                       CURSOR_WIDTH, attr->width,
-                       CURSOR_HEIGHT, attr->height);
-
-       REG_UPDATE_4(CURSOR_CONTROL,
-                       CURSOR_MODE, attr->color_format,
-                       CURSOR_2X_MAGNIFY, attr->attribute_flags.bits.ENABLE_MAGNIFICATION,
-                       CURSOR_PITCH, hw_pitch,
-                       CURSOR_LINES_PER_CHUNK, lpc);
-
-       REG_SET_2(CURSOR_SETTINGS, 0,
-                       /* no shift of the cursor HDL schedule */
-                       CURSOR0_DST_Y_OFFSET, 0,
-                        /* used to shift the cursor chunk request deadline */
-                       CURSOR0_CHUNK_HDL_ADJUST, 3);
+       if (!hubp->cursor_offload) {
+               REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
+                               CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part);
+               REG_UPDATE(CURSOR_SURFACE_ADDRESS,
+                               CURSOR_SURFACE_ADDRESS, attr->address.low_part);
+
+               REG_UPDATE_2(CURSOR_SIZE,
+                               CURSOR_WIDTH, attr->width,
+                               CURSOR_HEIGHT, attr->height);
+
+               REG_UPDATE_4(CURSOR_CONTROL,
+                               CURSOR_MODE, attr->color_format,
+                               CURSOR_2X_MAGNIFY, attr->attribute_flags.bits.ENABLE_MAGNIFICATION,
+                               CURSOR_PITCH, hw_pitch,
+                               CURSOR_LINES_PER_CHUNK, lpc);
+
+               REG_SET_2(CURSOR_SETTINGS, 0,
+                               /* no shift of the cursor HDL schedule */
+                               CURSOR0_DST_Y_OFFSET, 0,
+                               /* used to shift the cursor chunk request deadline */
+                               CURSOR0_CHUNK_HDL_ADJUST, 3);
+       }
 
        hubp->att.SURFACE_ADDR_HIGH  = attr->address.high_part;
        hubp->att.SURFACE_ADDR       = attr->address.low_part;
@@ -1059,23 +1061,28 @@ void hubp2_cursor_set_position(
                cur_en = 0;  /* not visible beyond top edge*/
 
        if (hubp->pos.cur_ctl.bits.cur_enable != cur_en) {
-               if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0)
+               bool cursor_not_programmed = hubp->att.SURFACE_ADDR == 0 && hubp->att.SURFACE_ADDR_HIGH == 0;
+
+               if (cur_en && cursor_not_programmed)
                        hubp->funcs->set_cursor_attributes(hubp, &hubp->curs_attr);
 
-               REG_UPDATE(CURSOR_CONTROL,
-                       CURSOR_ENABLE, cur_en);
+               if (!hubp->cursor_offload)
+                       REG_UPDATE(CURSOR_CONTROL, CURSOR_ENABLE, cur_en);
        }
 
-       REG_SET_2(CURSOR_POSITION, 0,
-                       CURSOR_X_POSITION, pos->x,
-                       CURSOR_Y_POSITION, pos->y);
+       if (!hubp->cursor_offload) {
+               REG_SET_2(CURSOR_POSITION, 0,
+                               CURSOR_X_POSITION, pos->x,
+                               CURSOR_Y_POSITION, pos->y);
 
-       REG_SET_2(CURSOR_HOT_SPOT, 0,
-                       CURSOR_HOT_SPOT_X, pos->x_hotspot,
-                       CURSOR_HOT_SPOT_Y, pos->y_hotspot);
+               REG_SET_2(CURSOR_HOT_SPOT, 0,
+                               CURSOR_HOT_SPOT_X, pos->x_hotspot,
+                               CURSOR_HOT_SPOT_Y, pos->y_hotspot);
+
+               REG_SET(CURSOR_DST_OFFSET, 0,
+                               CURSOR_DST_X_OFFSET, dst_x_offset);
+       }
 
-       REG_SET(CURSOR_DST_OFFSET, 0,
-                       CURSOR_DST_X_OFFSET, dst_x_offset);
        /* TODO Handle surface pixel formats other than 4:4:4 */
        /* Cursor Position Register Config */
        hubp->pos.cur_ctl.bits.cur_enable = cur_en;
index c88781de6d18ac6e0448de112df61ac1dd07174d..fa62e40a9858684e93ffb6e65cd5862bf77697af 100644 (file)
@@ -3090,6 +3090,9 @@ static void dcn10_update_dchubp_dpp(
        }
 
        if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
+               if (dc->hwss.abort_cursor_offload_update)
+                       dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+
                dc->hwss.set_cursor_attribute(pipe_ctx);
                dc->hwss.set_cursor_position(pipe_ctx);
 
index cf9e8ce784ce1a483613adda96e38a643bf3a479..6bd905905984b4230b2599be7b181eafecef3f3a 100644 (file)
@@ -1793,6 +1793,9 @@ void dcn20_update_dchubp_dpp(
        if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
                        pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
                        pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
+               if (dc->hwss.abort_cursor_offload_update)
+                       dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+
                dc->hwss.set_cursor_attribute(pipe_ctx);
                dc->hwss.set_cursor_position(pipe_ctx);
 
index 7ea3fe48b329e9484337660240545d800e7e4a15..404ff00c71300c26cac31d49626fabb362094646 100644 (file)
@@ -1593,3 +1593,141 @@ void dcn35_hardware_release(struct dc *dc)
        if (dc->hwss.hw_block_power_up)
                dc->hwss.hw_block_power_up(dc, &pg_update_state);
 }
+
+void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       if (!dc_dmub_srv_is_cursor_offload_enabled(dc))
+               return;
+
+       /*
+        * Insert a blank update to modify the write index and set pipe_mask to 0.
+        *
+        * While the DMU is interlocked with driver full pipe programming via
+        * the DMU HW lock, if the cursor update begins to execute after a full
+        * pipe programming occurs there are two possible issues:
+        *
+        * 1. Outdated cursor information is programmed, replacing the current update
+        * 2. The cursor update in firmware holds the cursor lock, preventing
+        *    the current update from being latched atomically in the same frame
+        *    as the rest of the update.
+        *
+        * This blank update, treated as a no-op, will allow the firmware to skip
+        * the programming.
+        */
+
+       if (dc->hwss.begin_cursor_offload_update)
+               dc->hwss.begin_cursor_offload_update(dc, pipe);
+
+       if (dc->hwss.commit_cursor_offload_update)
+               dc->hwss.commit_cursor_offload_update(dc, pipe);
+}
+
+void dcn35_begin_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
+       const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
+       uint32_t stream_idx, write_idx, payload_idx;
+
+       if (!top_pipe)
+               return;
+
+       stream_idx = top_pipe->pipe_idx;
+       write_idx = cs->offload_streams[stream_idx].write_idx + 1; /*  new payload (+1) */
+       payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
+
+       cs->offload_streams[stream_idx].payloads[payload_idx].write_idx_start = write_idx;
+
+       if (pipe->plane_res.hubp)
+               pipe->plane_res.hubp->cursor_offload = true;
+
+       if (pipe->plane_res.dpp)
+               pipe->plane_res.dpp->cursor_offload = true;
+}
+
+void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
+       volatile struct dmub_shared_state_cursor_offload_stream_v1 *shared_stream;
+       const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
+       uint32_t stream_idx, write_idx, payload_idx;
+
+       if (pipe->plane_res.hubp)
+               pipe->plane_res.hubp->cursor_offload = false;
+
+       if (pipe->plane_res.dpp)
+               pipe->plane_res.dpp->cursor_offload = false;
+
+       if (!top_pipe)
+               return;
+
+       stream_idx = top_pipe->pipe_idx;
+       write_idx = cs->offload_streams[stream_idx].write_idx + 1; /*  new payload (+1) */
+       payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
+
+       shared_stream = &dc->ctx->dmub_srv->dmub->shared_state[DMUB_SHARED_STATE_FEATURE__CURSOR_OFFLOAD_V1]
+                                .data.cursor_offload_v1.offload_streams[stream_idx];
+
+       shared_stream->last_write_idx = write_idx;
+
+       cs->offload_streams[stream_idx].write_idx = write_idx;
+       cs->offload_streams[stream_idx].payloads[payload_idx].write_idx_finish = write_idx;
+}
+
+void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
+       const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
+       const struct hubp *hubp = pipe->plane_res.hubp;
+       const struct dpp *dpp = pipe->plane_res.dpp;
+       volatile struct dmub_cursor_offload_pipe_data_dcn30_v1 *p;
+       uint32_t stream_idx, write_idx, payload_idx;
+
+       if (!top_pipe || !hubp || !dpp)
+               return;
+
+       stream_idx = top_pipe->pipe_idx;
+       write_idx = cs->offload_streams[stream_idx].write_idx + 1; /*  new payload (+1) */
+       payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
+
+       p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn30;
+
+       p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
+       p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
+       p->CURSOR0_0_CURSOR_SIZE__CURSOR_WIDTH = hubp->att.size.bits.width;
+       p->CURSOR0_0_CURSOR_SIZE__CURSOR_HEIGHT = hubp->att.size.bits.height;
+       p->CURSOR0_0_CURSOR_POSITION__CURSOR_X_POSITION = hubp->pos.position.bits.x_pos;
+       p->CURSOR0_0_CURSOR_POSITION__CURSOR_Y_POSITION = hubp->pos.position.bits.y_pos;
+       p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_X = hubp->pos.hot_spot.bits.x_hot;
+       p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_Y = hubp->pos.hot_spot.bits.y_hot;
+       p->CURSOR0_0_CURSOR_DST_OFFSET__CURSOR_DST_X_OFFSET = hubp->pos.dst_offset.bits.dst_x_offset;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_ENABLE = hubp->pos.cur_ctl.bits.cur_enable;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_MODE = hubp->att.cur_ctl.bits.mode;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY = hubp->pos.cur_ctl.bits.cur_2x_magnify;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_PITCH = hubp->att.cur_ctl.bits.pitch;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_LINES_PER_CHUNK = hubp->pos.cur_ctl.bits.line_per_chunk;
+
+       p->CNVC_CUR0_CURSOR0_CONTROL__CUR0_ENABLE = dpp->att.cur0_ctl.bits.cur0_enable;
+       p->CNVC_CUR0_CURSOR0_CONTROL__CUR0_MODE = dpp->att.cur0_ctl.bits.mode;
+       p->CNVC_CUR0_CURSOR0_CONTROL__CUR0_EXPANSION_MODE = dpp->att.cur0_ctl.bits.expansion_mode;
+       p->CNVC_CUR0_CURSOR0_CONTROL__CUR0_ROM_EN = dpp->att.cur0_ctl.bits.cur0_rom_en;
+       p->CNVC_CUR0_CURSOR0_COLOR0__CUR0_COLOR0 = 0x000000;
+       p->CNVC_CUR0_CURSOR0_COLOR1__CUR0_COLOR1 = 0xFFFFFF;
+       p->CNVC_CUR0_CURSOR0_FP_SCALE_BIAS__CUR0_FP_BIAS = dpp->att.fp_scale_bias.bits.fp_bias;
+       p->CNVC_CUR0_CURSOR0_FP_SCALE_BIAS__CUR0_FP_SCALE = dpp->att.fp_scale_bias.bits.fp_scale;
+
+       p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset;
+       p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
+
+       cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+}
+
+void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
+                                           const struct dc_stream_state *stream)
+{
+       dc_dmub_srv_control_cursor_offload(dc, context, stream, true);
+}
+
+void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       dc_dmub_srv_program_cursor_now(dc, pipe);
+}
index 0b1d6f608edd7c421249aeaccad98c02e15e1de7..1ff41dba556c035de9349d07a5d578e1d17fdd78 100644 (file)
@@ -101,4 +101,12 @@ bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
 
 void dcn35_hardware_release(struct dc *dc);
 
+void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_begin_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
+                                           const struct dc_stream_state *stream);
+void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe);
+
 #endif /* __DC_HWSS_DCN35_H__ */
index f2f16a0bdb4f3faec48fd4307f19a1a60d7d8b11..5a66c9db267094a540188ec6a6d4496971b428dd 100644 (file)
@@ -86,6 +86,12 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
        .set_cursor_position = dcn10_set_cursor_position,
        .set_cursor_attribute = dcn10_set_cursor_attribute,
        .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
+       .abort_cursor_offload_update = dcn35_abort_cursor_offload_update,
+       .begin_cursor_offload_update = dcn35_begin_cursor_offload_update,
+       .commit_cursor_offload_update = dcn35_commit_cursor_offload_update,
+       .update_cursor_offload_pipe = dcn35_update_cursor_offload_pipe,
+       .notify_cursor_offload_drr_update = dcn35_notify_cursor_offload_drr_update,
+       .program_cursor_offload_now = dcn35_program_cursor_offload_now,
        .setup_periodic_interrupt = dcn10_setup_periodic_interrupt,
        .set_clock = dcn10_set_clock,
        .get_clock = dcn10_get_clock,
index ab21da435a36dd6d6df895439f310d4caf42a8a8..71c2cfa4df755fb752a16c36ca4ce5462cea77f3 100644 (file)
@@ -1473,7 +1473,10 @@ void dcn401_dmub_hw_control_lock(struct dc *dc,
        /* use always for now */
        union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
 
-       if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable)
+       if (!dc->ctx || !dc->ctx->dmub_srv)
+               return;
+
+       if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc))
                return;
 
        hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
@@ -2669,3 +2672,58 @@ void dcn401_plane_atomic_power_down(struct dc *dc,
        if (hws->funcs.dpp_root_clock_control)
                hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
 }
+
+void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+{
+       volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
+       const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
+       const struct hubp *hubp = pipe->plane_res.hubp;
+       const struct dpp *dpp = pipe->plane_res.dpp;
+       volatile struct dmub_cursor_offload_pipe_data_dcn401_v1 *p;
+       uint32_t stream_idx, write_idx, payload_idx;
+
+       if (!top_pipe || !hubp || !dpp)
+               return;
+
+       stream_idx = top_pipe->pipe_idx;
+       write_idx = cs->offload_streams[stream_idx].write_idx;
+       payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
+
+       p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn401;
+
+       p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
+       p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
+       p->CURSOR0_0_CURSOR_SIZE__CURSOR_WIDTH = hubp->att.size.bits.width;
+       p->CURSOR0_0_CURSOR_SIZE__CURSOR_HEIGHT = hubp->att.size.bits.height;
+       p->CURSOR0_0_CURSOR_POSITION__CURSOR_X_POSITION = hubp->pos.position.bits.x_pos;
+       p->CURSOR0_0_CURSOR_POSITION__CURSOR_Y_POSITION = hubp->pos.position.bits.y_pos;
+       p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_X = hubp->pos.hot_spot.bits.x_hot;
+       p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_Y = hubp->pos.hot_spot.bits.y_hot;
+       p->CURSOR0_0_CURSOR_DST_OFFSET__CURSOR_DST_X_OFFSET = hubp->pos.dst_offset.bits.dst_x_offset;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_ENABLE = hubp->pos.cur_ctl.bits.cur_enable;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_MODE = hubp->att.cur_ctl.bits.mode;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY = hubp->pos.cur_ctl.bits.cur_2x_magnify;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_PITCH = hubp->att.cur_ctl.bits.pitch;
+       p->CURSOR0_0_CURSOR_CONTROL__CURSOR_LINES_PER_CHUNK = hubp->pos.cur_ctl.bits.line_per_chunk;
+
+       p->CM_CUR0_CURSOR0_CONTROL__CUR0_ENABLE = dpp->att.cur0_ctl.bits.cur0_enable;
+       p->CM_CUR0_CURSOR0_CONTROL__CUR0_MODE = dpp->att.cur0_ctl.bits.mode;
+       p->CM_CUR0_CURSOR0_CONTROL__CUR0_EXPANSION_MODE = dpp->att.cur0_ctl.bits.expansion_mode;
+       p->CM_CUR0_CURSOR0_CONTROL__CUR0_ROM_EN = dpp->att.cur0_ctl.bits.cur0_rom_en;
+       p->CM_CUR0_CURSOR0_COLOR0__CUR0_COLOR0 = 0x000000;
+       p->CM_CUR0_CURSOR0_COLOR1__CUR0_COLOR1 = 0xFFFFFF;
+
+       p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_BIAS_G_Y =
+               dpp->att.fp_scale_bias_g_y.bits.fp_bias_g_y;
+       p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_SCALE_G_Y =
+               dpp->att.fp_scale_bias_g_y.bits.fp_scale_g_y;
+       p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_BIAS_RB_CRCB =
+               dpp->att.fp_scale_bias_rb_crcb.bits.fp_bias_rb_crcb;
+       p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_SCALE_RB_CRCB =
+               dpp->att.fp_scale_bias_rb_crcb.bits.fp_scale_rb_crcb;
+
+       p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset;
+       p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
+
+       cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+}
index 9591657d8eee3174f0b68cd797e5cdde26a0f545..f489bb7a4c268972efc53b27958838e97ef0ae11 100644 (file)
@@ -110,4 +110,6 @@ void dcn401_plane_atomic_power_down(struct dc *dc,
                struct dpp *dpp,
                struct hubp *hubp);
 void dcn401_initialize_min_clocks(struct dc *dc);
+void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+
 #endif /* __DC_HWSS_DCN401_H__ */
index a221b8cb6d4dd3ebeef7514801f34c7551fafb56..1c736b7e33001cd3ebec0f71bfbe02b25e202ce6 100644 (file)
@@ -9,6 +9,7 @@
 #include "dcn30/dcn30_hwseq.h"
 #include "dcn31/dcn31_hwseq.h"
 #include "dcn32/dcn32_hwseq.h"
+#include "dcn35/dcn35_hwseq.h"
 #include "dcn401/dcn401_hwseq.h"
 #include "dcn401_init.h"
 
@@ -60,6 +61,12 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
        .set_cursor_position = dcn401_set_cursor_position,
        .set_cursor_attribute = dcn10_set_cursor_attribute,
        .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
+       .abort_cursor_offload_update = dcn35_abort_cursor_offload_update,
+       .begin_cursor_offload_update = dcn35_begin_cursor_offload_update,
+       .commit_cursor_offload_update = dcn35_commit_cursor_offload_update,
+       .update_cursor_offload_pipe = dcn401_update_cursor_offload_pipe,
+       .notify_cursor_offload_drr_update = dcn35_notify_cursor_offload_drr_update,
+       .program_cursor_offload_now = dcn35_program_cursor_offload_now,
        .setup_periodic_interrupt = dcn10_setup_periodic_interrupt,
        .set_clock = dcn10_set_clock,
        .get_clock = dcn10_get_clock,
index 619ac4dfff078574373fe351df4c42dc7f2ffb09..a937a2b2135e7d5a243274f9ae4ea4e7ce731d1e 100644 (file)
@@ -154,6 +154,11 @@ struct dmub_hw_control_lock_fast_params {
        bool lock;
 };
 
+struct program_cursor_update_now_params {
+       struct dc *dc;
+       struct pipe_ctx *pipe_ctx;
+};
+
 union block_sequence_params {
        struct update_plane_addr_params update_plane_addr_params;
        struct subvp_pipe_control_lock_fast_params subvp_pipe_control_lock_fast_params;
@@ -174,6 +179,7 @@ union block_sequence_params {
        struct subvp_save_surf_addr subvp_save_surf_addr;
        struct wait_for_dcc_meta_propagation_params wait_for_dcc_meta_propagation_params;
        struct dmub_hw_control_lock_fast_params dmub_hw_control_lock_fast_params;
+       struct program_cursor_update_now_params program_cursor_update_now_params;
 };
 
 enum block_sequence_func {
@@ -196,6 +202,7 @@ enum block_sequence_func {
        DMUB_SUBVP_SAVE_SURF_ADDR,
        HUBP_WAIT_FOR_DCC_META_PROP,
        DMUB_HW_CONTROL_LOCK_FAST,
+       PROGRAM_CURSOR_UPDATE_NOW,
        /* This must be the last value in this enum, add new ones above */
        HWSS_BLOCK_SEQUENCE_FUNC_COUNT
 };
@@ -310,6 +317,13 @@ struct hw_sequencer_funcs {
        void (*set_cursor_position)(struct pipe_ctx *pipe);
        void (*set_cursor_attribute)(struct pipe_ctx *pipe);
        void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe);
+       void (*abort_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
+       void (*begin_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
+       void (*commit_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
+       void (*update_cursor_offload_pipe)(struct dc *dc, const struct pipe_ctx *pipe);
+       void (*notify_cursor_offload_drr_update)(struct dc *dc, struct dc_state *context,
+                                                const struct dc_stream_state *stream);
+       void (*program_cursor_offload_now)(struct dc *dc, const struct pipe_ctx *pipe);
 
        /* Colour Related */
        void (*program_gamut_remap)(struct pipe_ctx *pipe_ctx);
index 45645f9fd86c42597e593d338551bb036dba4c66..081831230821a6d818c90cb025b30bb8f4496df7 100644 (file)
@@ -83,12 +83,34 @@ union reg_cur0_control_cfg {
        } bits;
        uint32_t raw;
 };
+
 struct cursor_position_cache_dpp {
        union reg_cur0_control_cfg cur0_ctl;
 };
 
 struct cursor_attribute_cache_dpp {
        union reg_cur0_control_cfg cur0_ctl;
+       union reg_cur0_fp_scale_bias {
+               struct {
+                       uint32_t  fp_bias: 16;
+                       uint32_t fp_scale: 16;
+               } bits;
+               uint32_t raw;
+       } fp_scale_bias;
+       union reg_cur0_fp_scale_bias_g_y {
+               struct {
+                       uint32_t  fp_bias_g_y: 16;
+                       uint32_t fp_scale_g_y: 16;
+               } bits;
+               uint32_t raw;
+       } fp_scale_bias_g_y;
+       union reg_cur0_fp_scale_bias_rb_crcb {
+               struct {
+                       uint32_t  fp_bias_rb_crcb: 16;
+                       uint32_t fp_scale_rb_crcb: 16;
+               } bits;
+               uint32_t raw;
+       } fp_scale_bias_rb_crcb;
 };
 
 struct cursor_attributes_cfg {
index 1b7c085dc2cc1e578caedac783d390fb812fb582..09c224691618a5b4d038a0db9825d3354cb6ca8e 100644 (file)
@@ -84,6 +84,7 @@ struct dpp {
 
        struct pwl_params shaper_params;
        bool cm_bypass_mode;
+       bool cursor_offload;
 
        struct cursor_position_cache_dpp  pos;
        struct cursor_attribute_cache_dpp att;
index 2b874d2cc61c580dd6e0057cc16e4accb4cf92ea..5998a20a18c4fe56a5d8ba5fa496abbc88f6c883 100644 (file)
@@ -126,6 +126,7 @@ struct hubp {
        int mpcc_id;
        struct dc_cursor_attributes curs_attr;
        struct dc_cursor_position curs_pos;
+       bool cursor_offload;
        bool power_gated;
 
        struct cursor_position_cache_hubp  pos;
index 338fdc651f2cf2520dde21550ff649d04506841d..9012a7ba1602104c00bcc1b981847b4ecd2797ea 100644 (file)
@@ -132,6 +132,7 @@ enum dmub_window_id {
        DMUB_WINDOW_IB_MEM,
        DMUB_WINDOW_SHARED_STATE,
        DMUB_WINDOW_LSDMA_BUFFER,
+       DMUB_WINDOW_CURSOR_OFFLOAD,
        DMUB_WINDOW_TOTAL,
 };
 
@@ -535,7 +536,8 @@ struct dmub_srv_create_params {
  * @fw_version: the current firmware version, if any
  * @is_virtual: false if hardware support only
  * @shared_state: dmub shared state between firmware and driver
- * @fw_state: dmub firmware state pointer
+ * @cursor_offload_v1: Cursor offload state
+ * @fw_state: dmub firmware state pointer (debug purpose only)
  */
 struct dmub_srv {
        enum dmub_asic asic;
@@ -544,7 +546,9 @@ struct dmub_srv {
        bool is_virtual;
        struct dmub_fb scratch_mem_fb;
        struct dmub_fb ib_mem_gart;
+       struct dmub_fb cursor_offload_fb;
        volatile struct dmub_shared_state_feature_block *shared_state;
+       volatile struct dmub_cursor_offload_v1 *cursor_offload_v1;
        volatile const struct dmub_fw_state *fw_state;
 
        /* private: internal use only */
index b17a19400c067eede5b370252f0bcd1acf0d9a17..0244c9b44eccf3c8e67b35c30d68f7738bb4c953 100644 (file)
@@ -564,10 +564,11 @@ enum dmub_status
        window_sizes[DMUB_WINDOW_4_MAILBOX] = DMUB_MAILBOX_SIZE;
        window_sizes[DMUB_WINDOW_5_TRACEBUFF] = trace_buffer_size;
        window_sizes[DMUB_WINDOW_6_FW_STATE] = fw_state_size;
-       window_sizes[DMUB_WINDOW_7_SCRATCH_MEM] = DMUB_SCRATCH_MEM_SIZE;
+       window_sizes[DMUB_WINDOW_7_SCRATCH_MEM] = dmub_align(DMUB_SCRATCH_MEM_SIZE, 64);
        window_sizes[DMUB_WINDOW_IB_MEM] = DMUB_IB_MEM_SIZE;
        window_sizes[DMUB_WINDOW_SHARED_STATE] = max(DMUB_FW_HEADER_SHARED_STATE_SIZE, shared_state_size);
        window_sizes[DMUB_WINDOW_LSDMA_BUFFER] = DMUB_LSDMA_RB_SIZE;
+       window_sizes[DMUB_WINDOW_CURSOR_OFFLOAD] = dmub_align(sizeof(struct dmub_cursor_offload_v1), 64);
 
        out->fb_size =
                dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_FB);
@@ -652,21 +653,22 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
        struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
        struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
        struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE];
-       struct dmub_fb *scratch_mem_fb = params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
-       struct dmub_fb *ib_mem_gart = params->fb[DMUB_WINDOW_IB_MEM];
        struct dmub_fb *shared_state_fb = params->fb[DMUB_WINDOW_SHARED_STATE];
 
        struct dmub_rb_init_params rb_params, outbox0_rb_params;
        struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6, region6;
        struct dmub_region inbox1, outbox1, outbox0;
 
+       uint32_t i;
+
        if (!dmub->sw_init)
                return DMUB_STATUS_INVALID;
 
-       if (!inst_fb || !stack_fb || !data_fb || !bios_fb || !mail_fb ||
-               !tracebuff_fb || !fw_state_fb || !scratch_mem_fb || !ib_mem_gart) {
-               ASSERT(0);
-               return DMUB_STATUS_INVALID;
+       for (i = 0; i < DMUB_WINDOW_TOTAL; ++i) {
+               if (!params->fb[i]) {
+                       ASSERT(0);
+                       return DMUB_STATUS_INVALID;
+               }
        }
 
        dmub->fb_base = params->fb_base;
@@ -748,9 +750,11 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
 
        dmub->shared_state = shared_state_fb->cpu_addr;
 
-       dmub->scratch_mem_fb = *scratch_mem_fb;
+       dmub->scratch_mem_fb = *params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
+       dmub->ib_mem_gart = *params->fb[DMUB_WINDOW_IB_MEM];
 
-       dmub->ib_mem_gart = *ib_mem_gart;
+       dmub->cursor_offload_fb = *params->fb[DMUB_WINDOW_CURSOR_OFFLOAD];
+       dmub->cursor_offload_v1 = (struct dmub_cursor_offload_v1 *)dmub->cursor_offload_fb.cpu_addr;
 
        if (dmub->hw_funcs.setup_windows)
                dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, &cw5, &cw6, &region6);