diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 761 |
1 files changed, 341 insertions, 420 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index eb91432621ab..1008ac8a0f2a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -25,17 +25,18 @@ #include <linux/delay.h> #include "dm_services.h" +#include "basics/dc_common.h" #include "core_types.h" #include "resource.h" #include "custom_float.h" #include "dcn10_hw_sequencer.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn10_hw_sequencer_debug.h" #include "dce/dce_hwseq.h" #include "abm.h" #include "dmcu.h" #include "dcn10_optc.h" -#include "dcn10/dcn10_dpp.h" -#include "dcn10/dcn10_mpc.h" +#include "dcn10_dpp.h" +#include "dcn10_mpc.h" #include "timing_generator.h" #include "opp.h" #include "ipp.h" @@ -49,9 +50,7 @@ #include "clk_mgr.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dsc.h" -#endif #define DC_LOGGER_INIT(logger) @@ -68,6 +67,8 @@ #define DTN_INFO_MICRO_SEC(ref_cycle) \ print_microsec(dc_ctx, log_ctx, ref_cycle) +#define GAMMA_HW_POINTS_NUM 256 + void print_microsec(struct dc_context *dc_ctx, struct dc_log_buffer_ctx *log_ctx, uint32_t ref_cycle) @@ -81,6 +82,33 @@ void print_microsec(struct dc_context *dc_ctx, us_x10 % frac); } +static void dcn10_lock_all_pipes(struct dc *dc, + struct dc_state *context, + bool lock) +{ + struct pipe_ctx *pipe_ctx; + struct timing_generator *tg; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe_ctx = &context->res_ctx.pipe_ctx[i]; + tg = pipe_ctx->stream_res.tg; + /* + * Only lock the top pipe's tg to prevent redundant + * (un)locking. Also skip if pipe is disabled. + */ + if (pipe_ctx->top_pipe || + !pipe_ctx->stream || !pipe_ctx->plane_state || + !tg->funcs->is_tg_enabled(tg)) + continue; + + if (lock) + tg->funcs->lock(tg); + else + tg->funcs->unlock(tg); + } +} + static void log_mpc_crc(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { @@ -129,9 +157,8 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) struct resource_pool *pool = dc->res_pool; int i; - DTN_INFO("HUBP: format addr_hi width height" - " rot mir sw_mode dcc_en blank_en ttu_dis underflow" - " min_ttu_vblank qos_low_wm qos_high_wm\n"); + DTN_INFO( + "HUBP: format addr_hi width height rot mir sw_mode dcc_en blank_en clock_en ttu_dis underflow min_ttu_vblank qos_low_wm qos_high_wm\n"); for (i = 0; i < pool->pipe_count; i++) { struct hubp *hubp = pool->hubps[i]; struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); @@ -139,8 +166,7 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) hubp->funcs->hubp_read_state(hubp); if (!s->blank_en) { - DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh" - " %6d %8d %7d %8xh", + DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", hubp->inst, s->pixel_format, s->inuse_addr_hi, @@ -151,6 +177,7 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) s->sw_mode, s->dcc_en, s->blank_en, + s->clock_en, s->ttu_disable, s->underflow_status); DTN_INFO_MICRO_SEC(s->min_ttu_vblank); @@ -308,21 +335,31 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); - DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel" - " h_bs h_be h_ss h_se hpol htot vtot underflow\n"); + DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n"); for (i = 0; i < pool->timing_generator_count; i++) { struct timing_generator *tg = pool->timing_generators[i]; struct dcn_otg_state s = {0}; - + /* Read shared OTG state registers for all DCNx */ optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + /* + * For DCN2 and greater, a register on the OPP is used to + * determine if the CRTC is blanked instead of the OTG. So use + * dpg_is_blanked() if exists, otherwise fallback on otg. + * + * TODO: Implement DCN-specific read_otg_state hooks. + */ + if (pool->opps[i]->funcs->dpg_is_blanked) + s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); + else + s.blank_enabled = tg->funcs->is_blanked(tg); + //only print if OTG master is enabled if ((s.otg_enabled & 1) == 0) continue; - DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d" - " %5d %5d %5d %5d %9d\n", + DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", tg->inst, s.v_blank_start, s.v_blank_end, @@ -340,7 +377,8 @@ void dcn10_log_hw_state(struct dc *dc, s.h_sync_a_pol, s.h_total, s.v_total, - s.underflow_occurred_status); + s.underflow_occurred_status, + s.blank_enabled); // Clear underflow for debug purposes // We want to keep underflow sticky bit on for the longevity tests outside of test environment. @@ -350,7 +388,6 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); for (i = 0; i < pool->res_cap->num_dsc; i++) { struct display_stream_compressor *dsc = pool->dscs[i]; @@ -387,7 +424,7 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); - DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS\n"); + DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); for (i = 0; i < dc->link_count; i++) { struct link_encoder *lenc = dc->links[i]->link_enc; @@ -395,16 +432,16 @@ void dcn10_log_hw_state(struct dc *dc, if (lenc->funcs->read_state) { lenc->funcs->read_state(lenc, &s); - DTN_INFO("[%-3d]: %-12d %-22d %-22d\n", + DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", i, s.dphy_fec_en, s.dphy_fec_ready_shadow, - s.dphy_fec_active_status); + s.dphy_fec_active_status, + s.dp_link_training_complete); DTN_INFO("\n"); } } DTN_INFO("\n"); -#endif DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", @@ -438,14 +475,14 @@ bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) return false; } -static void dcn10_enable_power_gating_plane( +void dcn10_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { - bool force_on = 1; /* disable power gating */ + bool force_on = true; /* disable power gating */ if (enable) - force_on = 0; + force_on = false; /* DCHUBP0/1/2/3 */ REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); @@ -460,7 +497,7 @@ static void dcn10_enable_power_gating_plane( REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); } -static void dcn10_disable_vga( +void dcn10_disable_vga( struct dce_hwseq *hws) { unsigned int in_vga1_mode = 0; @@ -493,7 +530,7 @@ static void dcn10_disable_vga( REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); } -static void dcn10_dpp_pg_control( +void dcn10_dpp_pg_control( struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) @@ -545,7 +582,7 @@ static void dcn10_dpp_pg_control( } } -static void dcn10_hubp_pg_control( +void dcn10_hubp_pg_control( struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) @@ -605,8 +642,8 @@ static void power_on_plane( if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - hws->ctx->dc->hwss.dpp_pg_control(hws, plane_id, true); - hws->ctx->dc->hwss.hubp_pg_control(hws, plane_id, true); + hws->funcs.dpp_pg_control(hws, plane_id, true); + hws->funcs.hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); DC_LOG_DEBUG( @@ -627,7 +664,7 @@ static void undo_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dc->hwss.hubp_pg_control(hws, 0, false); + hws->funcs.hubp_pg_control(hws, 0, false); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -656,7 +693,7 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dc->hwss.hubp_pg_control(hws, 0, true); + hws->funcs.hubp_pg_control(hws, 0, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -664,16 +701,16 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) hws->wa_state.DEGVIDCN10_253_applied = true; } -static void dcn10_bios_golden_init(struct dc *dc) +void dcn10_bios_golden_init(struct dc *dc) { + struct dce_hwseq *hws = dc->hwseq; struct dc_bios *bp = dc->ctx->dc_bios; int i; bool allow_self_fresh_force_enable = true; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) - if (dc->hwss.s0i3_golden_init_wa && dc->hwss.s0i3_golden_init_wa(dc)) + if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) return; -#endif + if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) allow_self_fresh_force_enable = dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); @@ -732,7 +769,7 @@ static void false_optc_underflow_wa( tg->funcs->clear_optc_underflow(tg); } -static enum dc_status dcn10_enable_stream_timing( +enum dc_status dcn10_enable_stream_timing( struct pipe_ctx *pipe_ctx, struct dc_state *context, struct dc *dc) @@ -823,6 +860,7 @@ static void dcn10_reset_back_end_for_pipe( struct dc_state *context) { int i; + struct dc_link *link; DC_LOGGER_INIT(dc->ctx->logger); if (pipe_ctx->stream_res.stream_enc == NULL) { pipe_ctx->stream = NULL; @@ -830,8 +868,14 @@ static void dcn10_reset_back_end_for_pipe( } if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - /* DPMS may already disable */ - if (!pipe_ctx->stream->dpms_off) + link = pipe_ctx->stream->link; + /* DPMS may already disable or */ + /* dpms_off status is incorrect due to fastboot + * feature. When system resume from S4 with second + * screen only, the dpms_off would be true but + * VBIOS lit up eDP, so check link status too. + */ + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) core_link_disable_stream(pipe_ctx); else if (pipe_ctx->stream_res.audio) dc->hwss.disable_audio_stream(pipe_ctx); @@ -978,8 +1022,9 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc) } /* trigger HW to start disconnect plane from stream on the next vsync */ -void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; int dpp_id = pipe_ctx->plane_res.dpp->inst; struct mpc *mpc = dc->res_pool->mpc; @@ -1004,10 +1049,10 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->funcs->hubp_disconnect(hubp); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } -static void dcn10_plane_atomic_power_down(struct dc *dc, +void dcn10_plane_atomic_power_down(struct dc *dc, struct dpp *dpp, struct hubp *hubp) { @@ -1017,8 +1062,8 @@ static void dcn10_plane_atomic_power_down(struct dc *dc, if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dc->hwss.dpp_pg_control(hws, dpp->inst, false); - dc->hwss.hubp_pg_control(hws, hubp->inst, false); + hws->funcs.dpp_pg_control(hws, dpp->inst, false); + hws->funcs.hubp_pg_control(hws, hubp->inst, false); dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -1030,8 +1075,9 @@ static void dcn10_plane_atomic_power_down(struct dc *dc, /* disable HW used by plane. * note: cannot disable until disconnect is complete */ -static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; int opp_id = hubp->opp_id; @@ -1050,7 +1096,7 @@ static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - dc->hwss.plane_atomic_power_down(dc, + hws->funcs.plane_atomic_power_down(dc, pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp); @@ -1062,14 +1108,15 @@ static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->plane_state = NULL; } -static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; DC_LOGGER_INIT(dc->ctx->logger); if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; - dc->hwss.plane_atomic_disable(dc, pipe_ctx); + hws->funcs.plane_atomic_disable(dc, pipe_ctx); apply_DEGVIDCN10_253_wa(dc); @@ -1077,9 +1124,10 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } -static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) +void dcn10_init_pipes(struct dc *dc, struct dc_state *context) { int i; + struct dce_hwseq *hws = dc->hwseq; bool can_apply_seamless_boot = false; for (i = 0; i < context->stream_count; i++) { @@ -1104,8 +1152,8 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) * command table. */ if (tg->funcs->is_tg_enabled(tg)) { - if (dc->hwss.init_blank != NULL) { - dc->hwss.init_blank(dc, tg); + if (hws->funcs.init_blank != NULL) { + hws->funcs.init_blank(dc, tg); tg->funcs->lock(tg); } else { tg->funcs->lock(tg); @@ -1115,7 +1163,8 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) } } - for (i = 0; i < dc->res_pool->pipe_count; i++) { + /* num_opp will be equal to number of mpcc */ + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; /* Cannot reset the MPC mux if seamless boot */ @@ -1139,8 +1188,14 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) if (can_apply_seamless_boot && pipe_ctx->stream != NULL && pipe_ctx->stream_res.tg->funcs->is_tg_enabled( - pipe_ctx->stream_res.tg)) + pipe_ctx->stream_res.tg)) { + // Enable double buffering for OTG_BLANK no matter if + // seamless boot is enabled or not to suppress global sync + // signals when OTG blanked. This is to prevent pipe from + // requesting data while in PSR. + tg->funcs->tg_init(tg); continue; + } /* Disable on the current state so the new one isn't cleared. */ pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -1162,7 +1217,7 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - dc->hwss.plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); @@ -1176,7 +1231,7 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) } } -static void dcn10_init_hw(struct dc *dc) +void dcn10_init_hw(struct dc *dc) { int i; struct abm *abm = dc->res_pool->abm; @@ -1208,15 +1263,15 @@ static void dcn10_init_hw(struct dc *dc) } //Enable ability to power gate / don't force power on permanently - dc->hwss.enable_power_gating_plane(hws, true); + hws->funcs.enable_power_gating_plane(hws, true); return; } if (!dcb->funcs->is_accelerated_mode(dcb)) - dc->hwss.disable_vga(dc->hwseq); + hws->funcs.disable_vga(dc->hwseq); - dc->hwss.bios_golden_init(dc); + hws->funcs.bios_golden_init(dc); if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; @@ -1258,11 +1313,9 @@ static void dcn10_init_hw(struct dc *dc) } /* Power gate DSCs */ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT for (i = 0; i < res_pool->res_cap->num_dsc; i++) - if (dc->hwss.dsc_pg_control != NULL) - dc->hwss.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); -#endif + if (hws->funcs.dsc_pg_control != NULL) + hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which @@ -1271,7 +1324,7 @@ static void dcn10_init_hw(struct dc *dc) * everything down. */ if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { - dc->hwss.init_pipes(dc, dc->current_state); + hws->funcs.init_pipes(dc, dc->current_state); } for (i = 0; i < res_pool->audio_count; i++) { @@ -1285,7 +1338,7 @@ static void dcn10_init_hw(struct dc *dc) abm->funcs->abm_init(abm); } - if (dmcu != NULL) + if (dmcu != NULL && !dmcu->auto_load_dmcu) dmcu->funcs->dmcu_init(dmcu); if (abm != NULL && dmcu != NULL) @@ -1303,18 +1356,19 @@ static void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - dc->hwss.enable_power_gating_plane(dc->hwseq, true); + hws->funcs.enable_power_gating_plane(dc->hwseq, true); if (dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); } -static void dcn10_reset_hw_ctx_wrap( +void dcn10_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context) { int i; + struct dce_hwseq *hws = dc->hwseq; /* Reset Back End*/ for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { @@ -1333,8 +1387,8 @@ static void dcn10_reset_hw_ctx_wrap( struct clock_source *old_clk = pipe_ctx_old->clock_source; dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (dc->hwss.enable_stream_gating) - dc->hwss.enable_stream_gating(dc, pipe_ctx); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx); if (old_clk) old_clk->funcs->cs_power_down(old_clk); } @@ -1367,9 +1421,7 @@ static bool patch_address_for_sbs_tb_stereo( return false; } - - -static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) { bool addr_patched = false; PHYSICAL_ADDRESS_LOC addr; @@ -1394,8 +1446,8 @@ static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_c pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; } -static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) +bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; const struct dc_transfer_func *tf = NULL; @@ -1427,6 +1479,11 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); break; case TRANSFER_FUNCTION_PQ: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); + cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); + result = true; + break; default: result = false; break; @@ -1472,9 +1529,8 @@ static void log_tf(struct dc_context *ctx, } } -static bool -dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) +bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) { struct dpp *dpp = pipe_ctx->plane_res.dpp; @@ -1510,11 +1566,13 @@ dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, return true; } -static void dcn10_pipe_control_lock( +void dcn10_pipe_control_lock( struct dc *dc, struct pipe_ctx *pipe, bool lock) { + struct dce_hwseq *hws = dc->hwseq; + /* use TG master update lock to lock everything on the TG * therefore only top pipe need to lock */ @@ -1522,7 +1580,7 @@ static void dcn10_pipe_control_lock( return; if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); if (lock) pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); @@ -1530,7 +1588,7 @@ static void dcn10_pipe_control_lock( pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } static bool wait_for_reset_trigger_to_occur( @@ -1570,7 +1628,7 @@ static bool wait_for_reset_trigger_to_occur( return rc; } -static void dcn10_enable_timing_synchronization( +void dcn10_enable_timing_synchronization( struct dc *dc, int group_index, int group_size, @@ -1600,7 +1658,7 @@ static void dcn10_enable_timing_synchronization( DC_SYNC_INFO("Sync complete\n"); } -static void dcn10_enable_per_frame_crtc_position_reset( +void dcn10_enable_per_frame_crtc_position_reset( struct dc *dc, int group_size, struct pipe_ctx *grouped_pipes[]) @@ -1625,10 +1683,10 @@ static void dcn10_enable_per_frame_crtc_position_reset( } /*static void print_rq_dlg_ttu( - struct dc *core_dc, + struct dc *dc, struct pipe_ctx *pipe_ctx) { - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== DML TTU Output parameters [%d] ==============\n" "qos_level_low_wm: %d, \n" "qos_level_high_wm: %d, \n" @@ -1658,7 +1716,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c ); - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== DML DLG Output parameters [%d] ==============\n" "refcyc_h_blank_end: %d, \n" "dlg_vblank_end: %d, \n" @@ -1693,7 +1751,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l ); - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\ndst_y_per_meta_row_nom_l: %d, \n" "refcyc_per_meta_chunk_nom_l: %d, \n" "refcyc_per_line_delivery_pre_l: %d, \n" @@ -1723,7 +1781,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_line_delivery_c ); - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== DML RQ Output parameters [%d] ==============\n" "chunk_size: %d \n" "min_chunk_size: %d \n" @@ -1838,7 +1896,7 @@ static void dcn10_enable_plane( struct dce_hwseq *hws = dc->hwseq; if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } undo_DEGVIDCN10_253_wa(dc); @@ -1895,11 +1953,11 @@ static void dcn10_enable_plane( dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } } -static void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) +void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) { int i = 0; struct dpp_grph_csc_adjustment adjust; @@ -1947,7 +2005,7 @@ static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint matrix[11] = rgb_bias; } -static void dcn10_program_output_csc(struct dc *dc, +void dcn10_program_output_csc(struct dc *dc, struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace, uint16_t *matrix, @@ -1979,57 +2037,6 @@ static void dcn10_program_output_csc(struct dc *dc, } } -bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) - return true; - if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) - return true; - return false; -} - -bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) - return true; - if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) - return true; - return false; -} - -bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) - return true; - if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) - return true; - if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) - return true; - return false; -} - -bool is_rgb_cspace(enum dc_color_space output_color_space) -{ - switch (output_color_space) { - case COLOR_SPACE_SRGB: - case COLOR_SPACE_SRGB_LIMITED: - case COLOR_SPACE_2020_RGB_FULLRANGE: - case COLOR_SPACE_2020_RGB_LIMITEDRANGE: - case COLOR_SPACE_ADOBERGB: - return true; - case COLOR_SPACE_YCBCR601: - case COLOR_SPACE_YCBCR709: - case COLOR_SPACE_YCBCR601_LIMITED: - case COLOR_SPACE_YCBCR709_LIMITED: - case COLOR_SPACE_2020_YCBCR: - return false; - default: - /* Add a case to switch */ - BREAK_TO_DEBUGGER(); - return false; - } -} - void dcn10_get_surface_visual_confirm_color( const struct pipe_ctx *pipe_ctx, struct tg_color *color) @@ -2103,70 +2110,7 @@ void dcn10_get_hdr_visual_confirm_color( } } -static uint16_t fixed_point_to_int_frac( - struct fixed31_32 arg, - uint8_t integer_bits, - uint8_t fractional_bits) -{ - int32_t numerator; - int32_t divisor = 1 << fractional_bits; - - uint16_t result; - - uint16_t d = (uint16_t)dc_fixpt_floor( - dc_fixpt_abs( - arg)); - - if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor)) - numerator = (uint16_t)dc_fixpt_floor( - dc_fixpt_mul_int( - arg, - divisor)); - else { - numerator = dc_fixpt_floor( - dc_fixpt_sub( - dc_fixpt_from_int( - 1LL << integer_bits), - dc_fixpt_recip( - dc_fixpt_from_int( - divisor)))); - } - - if (numerator >= 0) - result = (uint16_t)numerator; - else - result = (uint16_t)( - (1 << (integer_bits + fractional_bits + 1)) + numerator); - - if ((result != 0) && dc_fixpt_lt( - arg, dc_fixpt_zero)) - result |= 1 << (integer_bits + fractional_bits); - - return result; -} - -void dcn10_build_prescale_params(struct dc_bias_and_scale *bias_and_scale, - const struct dc_plane_state *plane_state) -{ - if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN - && plane_state->format != SURFACE_PIXEL_FORMAT_INVALID - && plane_state->input_csc_color_matrix.enable_adjustment - && plane_state->coeff_reduction_factor.value != 0) { - bias_and_scale->scale_blue = fixed_point_to_int_frac( - dc_fixpt_mul(plane_state->coeff_reduction_factor, - dc_fixpt_from_fraction(256, 255)), - 2, - 13); - bias_and_scale->scale_red = bias_and_scale->scale_blue; - bias_and_scale->scale_green = bias_and_scale->scale_blue; - } else { - bias_and_scale->scale_blue = 0x2000; - bias_and_scale->scale_red = 0x2000; - bias_and_scale->scale_green = 0x2000; - } -} - -static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) +static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) { struct dc_bias_and_scale bns_params = {0}; @@ -2175,21 +2119,18 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) plane_state->format, EXPANSION_MODE_ZERO, plane_state->input_csc_color_matrix, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 plane_state->color_space, NULL); -#else - plane_state->color_space); -#endif //set scale and bias registers - dcn10_build_prescale_params(&bns_params, plane_state); + build_prescale_params(&bns_params, plane_state); if (dpp->funcs->dpp_program_bias_and_scale) dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } -static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct mpcc_blnd_cfg blnd_cfg = {{0}}; bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; @@ -2199,10 +2140,10 @@ static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { - dcn10_get_hdr_visual_confirm_color( + hws->funcs.get_hdr_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { - dcn10_get_surface_visual_confirm_color( + hws->funcs.get_surface_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); } else { color_space_to_black_color( @@ -2284,11 +2225,12 @@ static void update_scaler(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); } -void update_dchubp_dpp( +static void dcn10_update_dchubp_dpp( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -2342,12 +2284,12 @@ void update_dchubp_dpp( if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.bpp_change) - update_dpp(dpp, plane_state); + dcn10_update_dpp(dpp, plane_state); if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.per_pixel_alpha_change || plane_state->update_flags.bits.global_alpha_change) - dc->hwss.update_mpcc(dc, pipe_ctx); + hws->funcs.update_mpcc(dc, pipe_ctx); if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.per_pixel_alpha_change || @@ -2407,13 +2349,13 @@ void update_dchubp_dpp( hubp->power_gated = false; - dc->hwss.update_plane_addr(dc, pipe_ctx); + hws->funcs.update_plane_addr(dc, pipe_ctx); if (is_pipe_tree_visible(pipe_ctx)) hubp->funcs->set_blank(hubp, false); } -static void dcn10_blank_pixel_data( +void dcn10_blank_pixel_data( struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank) @@ -2456,10 +2398,9 @@ static void dcn10_blank_pixel_data( } } -void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) +void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) { - struct fixed31_32 multiplier = dc_fixpt_from_fraction( - pipe_ctx->plane_state->sdr_white_level, 80); + struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; uint32_t hw_mult = 0x1f000; // 1.0 default multiplier struct custom_float_format fmt; @@ -2467,7 +2408,8 @@ void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) fmt.mantissa_bits = 12; fmt.sign = true; - if (pipe_ctx->plane_state->sdr_white_level > 80) + + if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 convert_to_custom_float_format(multiplier, &fmt, &hw_mult); pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( @@ -2479,17 +2421,19 @@ void dcn10_program_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; + if (pipe_ctx->plane_state->update_flags.bits.full_update) dcn10_enable_plane(dc, pipe_ctx, context); - update_dchubp_dpp(dc, pipe_ctx, context); + dcn10_update_dchubp_dpp(dc, pipe_ctx, context); - set_hdr_multiplier(pipe_ctx); + hws->funcs.set_hdr_multiplier(pipe_ctx); if (pipe_ctx->plane_state->update_flags.bits.full_update || pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || pipe_ctx->plane_state->update_flags.bits.gamma_change) - dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); /* dcn10_translate_regamma_to_hw_format takes 750us to finish * only do gamma programming for full update. @@ -2498,14 +2442,16 @@ void dcn10_program_pipe( * doing heavy calculation and programming */ if (pipe_ctx->plane_state->update_flags.bits.full_update) - dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); } -static void program_all_pipe_in_tree( +static void dcn10_program_all_pipe_in_tree( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; + if (pipe_ctx->top_pipe == NULL) { bool blank = !is_pipe_tree_visible(pipe_ctx); @@ -2519,20 +2465,20 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg->funcs->set_vtg_params( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - if (dc->hwss.setup_vupdate_interrupt) - dc->hwss.setup_vupdate_interrupt(pipe_ctx); + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); } if (pipe_ctx->plane_state != NULL) - dcn10_program_pipe(dc, pipe_ctx, context); + hws->funcs.program_pipe(dc, pipe_ctx, context); if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) - program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); + dcn10_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); } -struct pipe_ctx *find_top_pipe_for_stream( +static struct pipe_ctx *dcn10_find_top_pipe_for_stream( struct dc *dc, struct dc_state *context, const struct dc_stream_state *stream) @@ -2556,19 +2502,20 @@ struct pipe_ctx *find_top_pipe_for_stream( return NULL; } -static void dcn10_apply_ctx_for_surface( +void dcn10_apply_ctx_for_surface( struct dc *dc, const struct dc_stream_state *stream, int num_planes, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; int i; struct timing_generator *tg; uint32_t underflow_check_delay_us; bool removed_pipe[4] = { false }; bool interdependent_update = false; struct pipe_ctx *top_pipe_to_program = - find_top_pipe_for_stream(dc, context, stream); + dcn10_find_top_pipe_for_stream(dc, context, stream); DC_LOGGER_INIT(dc->ctx->logger); if (!top_pipe_to_program) @@ -2581,23 +2528,23 @@ static void dcn10_apply_ctx_for_surface( underflow_check_delay_us = dc->debug.underflow_assert_delay_us; - if (underflow_check_delay_us != 0xFFFFFFFF && dc->hwss.did_underflow_occur) - ASSERT(dc->hwss.did_underflow_occur(dc, top_pipe_to_program)); + if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur) + ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program)); if (interdependent_update) - lock_all_pipes(dc, context, true); + dcn10_lock_all_pipes(dc, context, true); else dcn10_pipe_control_lock(dc, top_pipe_to_program, true); if (underflow_check_delay_us != 0xFFFFFFFF) udelay(underflow_check_delay_us); - if (underflow_check_delay_us != 0xFFFFFFFF && dc->hwss.did_underflow_occur) - ASSERT(dc->hwss.did_underflow_occur(dc, top_pipe_to_program)); + if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur) + ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program)); if (num_planes == 0) { /* OTG blank before remove all front end */ - dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); + hws->funcs.blank_pixel_data(dc, top_pipe_to_program, true); } /* Disconnect unused mpcc */ @@ -2623,7 +2570,7 @@ static void dcn10_apply_ctx_for_surface( old_pipe_ctx->plane_state && old_pipe_ctx->stream_res.tg == tg) { - dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; DC_LOG_DC("Reset mpcc for pipe %d\n", @@ -2632,13 +2579,11 @@ static void dcn10_apply_ctx_for_surface( } if (num_planes > 0) - program_all_pipe_in_tree(dc, top_pipe_to_program, context); + dcn10_program_all_pipe_in_tree(dc, top_pipe_to_program, context); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* Program secondary blending tree and writeback pipes */ - if ((stream->num_wb_info > 0) && (dc->hwss.program_all_writeback_pipes_in_tree)) - dc->hwss.program_all_writeback_pipes_in_tree(dc, stream, context); -#endif + if ((stream->num_wb_info > 0) && (hws->funcs.program_all_writeback_pipes_in_tree)) + hws->funcs.program_all_writeback_pipes_in_tree(dc, stream, context); if (interdependent_update) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -2654,7 +2599,7 @@ static void dcn10_apply_ctx_for_surface( } if (interdependent_update) - lock_all_pipes(dc, context, false); + dcn10_lock_all_pipes(dc, context, false); else dcn10_pipe_control_lock(dc, top_pipe_to_program, false); @@ -2691,14 +2636,15 @@ static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *contex } } -static void dcn10_prepare_bandwidth( +void dcn10_prepare_bandwidth( struct dc *dc, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubbub *hubbub = dc->res_pool->hubbub; if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (context->stream_count == 0) @@ -2720,17 +2666,18 @@ static void dcn10_prepare_bandwidth( dcn_bw_notify_pplib_of_wm_ranges(dc); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } -static void dcn10_optimize_bandwidth( +void dcn10_optimize_bandwidth( struct dc *dc, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubbub *hubbub = dc->res_pool->hubbub; if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (context->stream_count == 0) @@ -2752,10 +2699,10 @@ static void dcn10_optimize_bandwidth( dcn_bw_notify_pplib_of_wm_ranges(dc); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } -static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, +void dcn10_set_drr(struct pipe_ctx **pipe_ctx, int num_pipes, unsigned int vmin, unsigned int vmax, unsigned int vmid, unsigned int vmid_frame_number) { @@ -2763,6 +2710,8 @@ static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, struct drr_params params = {0}; // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow unsigned int event_triggers = 0x800; + // Note DRR trigger events are generated regardless of whether num frames met. + unsigned int num_frames = 2; params.vertical_total_max = vmax; params.vertical_total_min = vmin; @@ -2779,11 +2728,11 @@ static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, if (vmax != 0 && vmin != 0) pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( pipe_ctx[i]->stream_res.tg, - event_triggers); + event_triggers, num_frames); } } -static void dcn10_get_position(struct pipe_ctx **pipe_ctx, +void dcn10_get_position(struct pipe_ctx **pipe_ctx, int num_pipes, struct crtc_position *position) { @@ -2795,22 +2744,23 @@ static void dcn10_get_position(struct pipe_ctx **pipe_ctx, pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); } -static void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_events *events) +void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params) { unsigned int i; - unsigned int value = 0; + unsigned int triggers = 0; - if (events->surface_update) - value |= 0x80; - if (events->cursor_update) - value |= 0x2; - if (events->force_trigger) - value |= 0x1; + if (params->triggers.surface_update) + triggers |= 0x80; + if (params->triggers.cursor_update) + triggers |= 0x2; + if (params->triggers.force_trigger) + triggers |= 0x1; for (i = 0; i < num_pipes; i++) pipe_ctx[i]->stream_res.tg->funcs-> - set_static_screen_control(pipe_ctx[i]->stream_res.tg, value); + set_static_screen_control(pipe_ctx[i]->stream_res.tg, + triggers, params->num_frames); } static void dcn10_config_stereo_parameters( @@ -2850,7 +2800,7 @@ static void dcn10_config_stereo_parameters( return; } -static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) +void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) { struct crtc_stereo_flags flags = { 0 }; struct dc_stream_state *stream = pipe_ctx->stream; @@ -2889,15 +2839,16 @@ static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_in return NULL; } -static void dcn10_wait_for_mpcc_disconnect( +void dcn10_wait_for_mpcc_disconnect( struct dc *dc, struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; int mpcc_inst; if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } if (!pipe_ctx->stream_res.opp) @@ -2914,12 +2865,12 @@ static void dcn10_wait_for_mpcc_disconnect( } if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } } -static bool dcn10_dummy_display_power_gating( +bool dcn10_dummy_display_power_gating( struct dc *dc, uint8_t controller_id, struct dc_bios *dcb, @@ -2928,7 +2879,7 @@ static bool dcn10_dummy_display_power_gating( return true; } -static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) { struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct timing_generator *tg = pipe_ctx->stream_res.tg; @@ -2952,7 +2903,7 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) } } -static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; @@ -2960,7 +2911,34 @@ static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh hubbub->funcs->update_dchub(hubbub, dh_data); } -static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) +static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *test_pipe; + const struct rect *r1 = &pipe_ctx->plane_res.scl_data.recout, *r2; + int r1_r = r1->x + r1->width, r1_b = r1->y + r1->height, r2_r, r2_b; + + /** + * Disable the cursor if there's another pipe above this with a + * plane that contains this pipe's viewport to prevent double cursor + * and incorrect scaling artifacts. + */ + for (test_pipe = pipe_ctx->top_pipe; test_pipe; + test_pipe = test_pipe->top_pipe) { + if (!test_pipe->plane_state->visible) + continue; + + r2 = &test_pipe->plane_res.scl_data.recout; + r2_r = r2->x + r2->width; + r2_b = r2->y + r2->height; + + if (r1->x >= r2->x && r1->y >= r2->y && r1_r <= r2_r && r1_b <= r2_b) + return true; + } + + return false; +} + +void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) { struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; struct hubp *hubp = pipe_ctx->plane_res.hubp; @@ -2974,23 +2952,44 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) .rotation = pipe_ctx->plane_state->rotation, .mirror = pipe_ctx->plane_state->horizontal_mirror }; - uint32_t x_plane = pipe_ctx->plane_state->dst_rect.x; - uint32_t y_plane = pipe_ctx->plane_state->dst_rect.y; - uint32_t x_offset = min(x_plane, pos_cpy.x); - uint32_t y_offset = min(y_plane, pos_cpy.y); + bool pipe_split_on = (pipe_ctx->top_pipe != NULL) || + (pipe_ctx->bottom_pipe != NULL); - pos_cpy.x -= x_offset; - pos_cpy.y -= y_offset; - pos_cpy.x_hotspot += (x_plane - x_offset); - pos_cpy.y_hotspot += (y_plane - y_offset); + int x_plane = pipe_ctx->plane_state->dst_rect.x; + int y_plane = pipe_ctx->plane_state->dst_rect.y; + int x_pos = pos_cpy.x; + int y_pos = pos_cpy.y; + + // translate cursor from stream space to plane space + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / + pipe_ctx->plane_state->dst_rect.width; + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / + pipe_ctx->plane_state->dst_rect.height; + + if (x_pos < 0) { + pos_cpy.x_hotspot -= x_pos; + x_pos = 0; + } + + if (y_pos < 0) { + pos_cpy.y_hotspot -= y_pos; + y_pos = 0; + } + + pos_cpy.x = (uint32_t)x_pos; + pos_cpy.y = (uint32_t)y_pos; if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) pos_cpy.enable = false; + if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx)) + pos_cpy.enable = false; + // Swap axis and mirror horizontally if (param.rotation == ROTATION_ANGLE_90) { uint32_t temp_x = pos_cpy.x; + pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; pos_cpy.y = temp_x; @@ -2998,26 +2997,44 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) // Swap axis and mirror vertically else if (param.rotation == ROTATION_ANGLE_270) { uint32_t temp_y = pos_cpy.y; - if (pos_cpy.x > pipe_ctx->plane_res.scl_data.viewport.height) { - pos_cpy.x = pos_cpy.x - pipe_ctx->plane_res.scl_data.viewport.height; - pos_cpy.y = pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.x; - } else { - pos_cpy.y = 2 * pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.x; - } + int viewport_height = + pipe_ctx->plane_res.scl_data.viewport.height; + + if (pipe_split_on) { + if (pos_cpy.x > viewport_height) { + pos_cpy.x = pos_cpy.x - viewport_height; + pos_cpy.y = viewport_height - pos_cpy.x; + } else { + pos_cpy.y = 2 * viewport_height - pos_cpy.x; + } + } else + pos_cpy.y = viewport_height - pos_cpy.x; pos_cpy.x = temp_y; } // Mirror horizontally and vertically else if (param.rotation == ROTATION_ANGLE_180) { - if (pos_cpy.x >= pipe_ctx->plane_res.scl_data.viewport.width + pipe_ctx->plane_res.scl_data.viewport.x) { - pos_cpy.x = 2 * pipe_ctx->plane_res.scl_data.viewport.width - - pos_cpy.x + 2 * pipe_ctx->plane_res.scl_data.viewport.x; - } else { - uint32_t temp_x = pos_cpy.x; - pos_cpy.x = 2 * pipe_ctx->plane_res.scl_data.viewport.x - pos_cpy.x; - if (temp_x >= pipe_ctx->plane_res.scl_data.viewport.x + (int)hubp->curs_attr.width - || pos_cpy.x <= (int)hubp->curs_attr.width + pipe_ctx->plane_state->src_rect.x) { - pos_cpy.x = temp_x + pipe_ctx->plane_res.scl_data.viewport.width; + int viewport_width = + pipe_ctx->plane_res.scl_data.viewport.width; + int viewport_x = + pipe_ctx->plane_res.scl_data.viewport.x; + + if (pipe_split_on) { + if (pos_cpy.x >= viewport_width + viewport_x) { + pos_cpy.x = 2 * viewport_width + - pos_cpy.x + 2 * viewport_x; + } else { + uint32_t temp_x = pos_cpy.x; + + pos_cpy.x = 2 * viewport_x - pos_cpy.x; + if (temp_x >= viewport_x + + (int)hubp->curs_attr.width || pos_cpy.x + <= (int)hubp->curs_attr.width + + pipe_ctx->plane_state->src_rect.x) { + pos_cpy.x = temp_x + viewport_width; + } } + } else { + pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; } pos_cpy.y = pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; } @@ -3026,7 +3043,7 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); } -static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) { struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; @@ -3036,7 +3053,7 @@ static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, attributes); } -static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) +void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) { uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; struct fixed31_32 multiplier; @@ -3063,12 +3080,12 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, &opt_attr); } -/** -* apply_front_porch_workaround TODO FPGA still need? -* -* This is a workaround for a bug that has existed since R5xx and has not been -* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. -*/ +/* + * apply_front_porch_workaround TODO FPGA still need? + * + * This is a workaround for a bug that has existed since R5xx and has not been + * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. + */ static void apply_front_porch_workaround( struct dc_crtc_timing *timing) { @@ -3081,7 +3098,7 @@ static void apply_front_porch_workaround( } } -int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) +int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) { const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; struct dc_crtc_timing patched_crtc_timing; @@ -3110,34 +3127,8 @@ int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) return vertical_line_start; } -void lock_all_pipes(struct dc *dc, - struct dc_state *context, - bool lock) -{ - struct pipe_ctx *pipe_ctx; - struct timing_generator *tg; - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe_ctx = &context->res_ctx.pipe_ctx[i]; - tg = pipe_ctx->stream_res.tg; - /* - * Only lock the top pipe's tg to prevent redundant - * (un)locking. Also skip if pipe is disabled. - */ - if (pipe_ctx->top_pipe || - !pipe_ctx->stream || !pipe_ctx->plane_state || - !tg->funcs->is_tg_enabled(tg)) - continue; - - if (lock) - tg->funcs->lock(tg); - else - tg->funcs->unlock(tg); - } -} - -static void calc_vupdate_position( +static void dcn10_calc_vupdate_position( + struct dc *dc, struct pipe_ctx *pipe_ctx, uint32_t *start_line, uint32_t *end_line) @@ -3145,7 +3136,7 @@ static void calc_vupdate_position( const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; int vline_int_offset_from_vupdate = pipe_ctx->stream->periodic_interrupt0.lines_offset; - int vupdate_offset_from_vsync = get_vupdate_offset_from_vsync(pipe_ctx); + int vupdate_offset_from_vsync = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); int start_position; if (vline_int_offset_from_vupdate > 0) @@ -3166,7 +3157,8 @@ static void calc_vupdate_position( *end_line = 2; } -static void cal_vline_position( +static void dcn10_cal_vline_position( + struct dc *dc, struct pipe_ctx *pipe_ctx, enum vline_select vline, uint32_t *start_line, @@ -3181,7 +3173,8 @@ static void cal_vline_position( switch (ref_point) { case START_V_UPDATE: - calc_vupdate_position( + dcn10_calc_vupdate_position( + dc, pipe_ctx, start_line, end_line); @@ -3195,7 +3188,8 @@ static void cal_vline_position( } } -static void dcn10_setup_periodic_interrupt( +void dcn10_setup_periodic_interrupt( + struct dc *dc, struct pipe_ctx *pipe_ctx, enum vline_select vline) { @@ -3205,7 +3199,7 @@ static void dcn10_setup_periodic_interrupt( uint32_t start_line = 0; uint32_t end_line = 0; - cal_vline_position(pipe_ctx, vline, &start_line, &end_line); + dcn10_cal_vline_position(dc, pipe_ctx, vline, &start_line, &end_line); tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); @@ -3216,10 +3210,10 @@ static void dcn10_setup_periodic_interrupt( } } -static void dcn10_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) +void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct timing_generator *tg = pipe_ctx->stream_res.tg; - int start_line = get_vupdate_offset_from_vsync(pipe_ctx); + int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); if (start_line < 0) { ASSERT(0); @@ -3230,12 +3224,13 @@ static void dcn10_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) tg->funcs->setup_vertical_interrupt2(tg, start_line); } -static void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, +void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings) { struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; /* only 3 items below are used by unblank */ params.timing = pipe_ctx->stream->timing; @@ -3249,11 +3244,11 @@ static void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, } if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_backlight_control(link, true); + hws->funcs.edp_backlight_control(link, true); } } -static void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, +void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, const uint8_t *custom_sdp_message, unsigned int sdp_message_size) { @@ -3264,7 +3259,7 @@ static void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, sdp_message_size); } } -static enum dc_status dcn10_set_clock(struct dc *dc, +enum dc_status dcn10_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping) @@ -3304,7 +3299,7 @@ static enum dc_status dcn10_set_clock(struct dc *dc, } -static void dcn10_get_clock(struct dc *dc, +void dcn10_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg) { @@ -3314,77 +3309,3 @@ static void dcn10_get_clock(struct dc *dc, dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); } - -static const struct hw_sequencer_funcs dcn10_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, - .init_hw = dcn10_init_hw, - .init_pipes = dcn10_init_pipes, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, - .update_plane_addr = dcn10_update_plane_addr, - .plane_atomic_disconnect = hwss1_plane_atomic_disconnect, - .update_dchub = dcn10_update_dchub, - .update_mpcc = dcn10_update_mpcc, - .update_pending_status = dcn10_update_pending_status, - .set_input_transfer_func = dcn10_set_input_transfer_func, - .set_output_transfer_func = dcn10_set_output_transfer_func, - .program_output_csc = dcn10_program_output_csc, - .power_down = dce110_power_down, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dce110_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn10_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .disable_plane = dcn10_disable_plane, - .blank_pixel_data = dcn10_blank_pixel_data, - .pipe_control_lock = dcn10_pipe_control_lock, - .prepare_bandwidth = dcn10_prepare_bandwidth, - .optimize_bandwidth = dcn10_optimize_bandwidth, - .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, - .enable_stream_timing = dcn10_enable_stream_timing, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn10_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dce110_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .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, - .disable_stream_gating = NULL, - .enable_stream_gating = NULL, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = NULL, - .disable_vga = dcn10_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn10_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn10_enable_power_gating_plane, - .dpp_pg_control = dcn10_dpp_pg_control, - .hubp_pg_control = dcn10_hubp_pg_control, - .dsc_pg_control = NULL, -}; - - -void dcn10_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn10_funcs; -} - |