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 | 547 |
1 files changed, 344 insertions, 203 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 072e448..8b0f6b8 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 @@ -45,6 +45,8 @@ #include "dcn10_hubbub.h" #include "dcn10_cm_common.h" +#define DC_LOGGER \ + ctx->logger #define CTX \ hws->ctx #define REG(reg)\ @@ -133,7 +135,7 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("[%d]:\t %xh \t %xh \t %d \t %d \t " "%xh \t %xh \t %xh \t " "%d \t %d \t %d \t %xh \t", - i, + hubp->inst, s.pixel_format, s.inuse_addr_hi, s.viewport_width, @@ -155,7 +157,7 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t " "h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n"); - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + for (i = 0; i < pool->timing_generator_count; i++) { struct timing_generator *tg = pool->timing_generators[i]; struct dcn_otg_state s = {0}; @@ -168,7 +170,7 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("[%d]:\t %d \t %d \t %d \t %d \t " "%d \t %d \t %d \t %d \t %d \t %d \t " "%d \t %d \t %d \t %d \t %d \t ", - i, + tg->inst, s.v_blank_start, s.v_blank_end, s.v_sync_a_start, @@ -193,26 +195,6 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO_END(); } -static void enable_dppclk( - struct dce_hwseq *hws, - uint8_t plane_id, - uint32_t requested_pix_clk, - bool dppclk_div) -{ - dm_logger_write(hws->ctx->logger, LOG_SURFACE, - "dppclk_rate_control for pipe %d programed to %d\n", - plane_id, - dppclk_div); - - if (hws->shifts->DPPCLK_RATE_CONTROL) - REG_UPDATE_2(DPP_CONTROL[plane_id], - DPPCLK_RATE_CONTROL, dppclk_div, - DPP_CLOCK_ENABLE, 1); - else - REG_UPDATE(DPP_CONTROL[plane_id], - DPP_CLOCK_ENABLE, 1); -} - static void enable_power_gating_plane( struct dce_hwseq *hws, bool enable) @@ -238,14 +220,24 @@ static void enable_power_gating_plane( static void disable_vga( struct dce_hwseq *hws) { - unsigned int in_vga_mode = 0; + unsigned int in_vga1_mode = 0; + unsigned int in_vga2_mode = 0; + unsigned int in_vga3_mode = 0; + unsigned int in_vga4_mode = 0; - REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga_mode); + REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); + REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); + REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); + REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); - if (in_vga_mode == 0) + if (in_vga1_mode == 0 && in_vga2_mode == 0 && + in_vga3_mode == 0 && in_vga4_mode == 0) return; REG_WRITE(D1VGA_CONTROL, 0); + REG_WRITE(D2VGA_CONTROL, 0); + REG_WRITE(D3VGA_CONTROL, 0); + REG_WRITE(D4VGA_CONTROL, 0); /* HW Engineer's Notes: * During switch from vga->extended, if we set the VGA_TEST_ENABLE and @@ -362,6 +354,7 @@ static void power_on_plane( struct dce_hwseq *hws, int plane_id) { + struct dc_context *ctx = hws->ctx; if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); @@ -369,7 +362,7 @@ static void power_on_plane( hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - dm_logger_write(hws->ctx->logger, LOG_DEBUG, + DC_LOG_DEBUG( "Un-gated front end for pipe %d\n", plane_id); } } @@ -560,7 +553,7 @@ static void reset_back_end_for_pipe( struct dc_state *context) { int i; - + struct dc_context *ctx = dc->ctx; if (pipe_ctx->stream_res.stream_enc == NULL) { pipe_ctx->stream = NULL; return; @@ -570,6 +563,22 @@ static void reset_back_end_for_pipe( /* DPMS may already disable */ if (!pipe_ctx->stream->dpms_off) core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); + else if (pipe_ctx->stream_res.audio) { + /* + * if stream is already disabled outside of commit streams path, + * audio disable was skipped. Need to do it here + */ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + pipe_ctx->stream_res.audio = NULL; + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false); + } + + } + } /* by upper caller loop, parent pipe: pipe0, will be reset last. @@ -590,8 +599,7 @@ static void reset_back_end_for_pipe( return; pipe_ctx->stream = NULL; - dm_logger_write(dc->ctx->logger, LOG_DEBUG, - "Reset back end for pipe %d, tg:%d\n", + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); } @@ -611,29 +619,22 @@ static void dcn10_verify_allow_pstate_change_high(struct dc *dc) /* trigger HW to start disconnect plane from stream on the next vsync */ static void plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) { - int fe_idx = pipe_ctx->pipe_idx; - struct hubp *hubp = dc->res_pool->hubps[fe_idx]; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + int dpp_id = pipe_ctx->plane_res.dpp->inst; struct mpc *mpc = dc->res_pool->mpc; - int opp_id; struct mpc_tree *mpc_tree_params; struct mpcc *mpcc_to_remove = NULL; + struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; - /* look at tree rather than mi here to know if we already reset */ - for (opp_id = 0; opp_id < dc->res_pool->pipe_count; opp_id++) { - struct output_pixel_processor *opp = dc->res_pool->opps[opp_id]; - - mpc_tree_params = &(opp->mpc_tree_params); - mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, fe_idx); - if (mpcc_to_remove != NULL) - break; - } + mpc_tree_params = &(opp->mpc_tree_params); + mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); /*Already reset*/ - if (opp_id == dc->res_pool->pipe_count) + if (mpcc_to_remove == NULL) return; mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - dc->res_pool->opps[opp_id]->mpcc_disconnect_pending[fe_idx] = true; + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; dc->optimized_required = true; @@ -644,21 +645,22 @@ static void plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) dcn10_verify_allow_pstate_change_high(dc); } -static void plane_atomic_power_down(struct dc *dc, int fe_idx) +static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; - struct dpp *dpp = dc->res_pool->dpps[fe_idx]; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_context *ctx = dc->ctx; if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dpp_pg_control(hws, fe_idx, false); - hubp_pg_control(hws, fe_idx, false); + dpp_pg_control(hws, dpp->inst, false); + hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - dm_logger_write(dc->ctx->logger, LOG_DEBUG, - "Power gated front end %d\n", fe_idx); + DC_LOG_DEBUG( + "Power gated front end %d\n", pipe_ctx->pipe_idx); } } @@ -667,26 +669,25 @@ static void plane_atomic_power_down(struct dc *dc, int fe_idx) */ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) { - int fe_idx = pipe_ctx->pipe_idx; - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = dc->res_pool->hubps[fe_idx]; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; int opp_id = hubp->opp_id; dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); - REG_UPDATE(HUBP_CLK_CNTL[fe_idx], - HUBP_CLOCK_ENABLE, 0); - REG_UPDATE(DPP_CONTROL[fe_idx], - DPP_CLOCK_ENABLE, 0); + hubp->funcs->hubp_clk_cntl(hubp, false); - if (opp_id != 0xf && dc->res_pool->opps[opp_id]->mpc_tree_params.opp_list == NULL) - REG_UPDATE(OPP_PIPE_CONTROL[opp_id], - OPP_PIPE_CLOCK_EN, 0); + dpp->funcs->dpp_dppclk_control(dpp, false, false); + + if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + false); hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - plane_atomic_power_down(dc, fe_idx); + plane_atomic_power_down(dc, pipe_ctx); pipe_ctx->stream = NULL; memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); @@ -698,15 +699,16 @@ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) { - if (dc->res_pool->hubps[pipe_ctx->pipe_idx]->power_gated) + struct dc_context *ctx = dc->ctx; + + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; plane_atomic_disable(dc, pipe_ctx); apply_DEGVIDCN10_253_wa(dc); - dm_logger_write(dc->ctx->logger, LOG_DC, - "Power down front end %d\n", + DC_LOG_DC("Power down front end %d\n", pipe_ctx->pipe_idx); } @@ -734,26 +736,25 @@ static void dcn10_init_hw(struct dc *dc) } enable_power_gating_plane(dc->hwseq, true); - return; - } - /* end of FPGA. Below if real ASIC */ + } else { - if (!dcb->funcs->is_accelerated_mode(dcb)) { - bios_golden_init(dc); - disable_vga(dc->hwseq); - } + if (!dcb->funcs->is_accelerated_mode(dcb)) { + bios_golden_init(dc); + disable_vga(dc->hwseq); + } - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; - if (link->link_enc->connector.id == CONNECTOR_ID_EDP) - dc->hwss.edp_power_control(link, true); + if (link->link_enc->connector.id == CONNECTOR_ID_EDP) + dc->hwss.edp_power_control(link, true); - link->link_enc->funcs->hw_init(link->link_enc); + link->link_enc->funcs->hw_init(link->link_enc); + } } for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -782,18 +783,21 @@ static void dcn10_init_hw(struct dc *dc) struct timing_generator *tg = dc->res_pool->timing_generators[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; + struct dpp *dpp = dc->res_pool->dpps[i]; pipe_ctx->stream_res.tg = tg; pipe_ctx->pipe_idx = i; pipe_ctx->plane_res.hubp = hubp; - hubp->mpcc_id = i; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; hubp->opp_id = 0xf; hubp->power_gated = false; dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[i] = true; + 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]; plane_atomic_disconnect(dc, pipe_ctx); @@ -818,6 +822,10 @@ static void dcn10_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } + /* end of FPGA. Below if real ASIC */ + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + return; + for (i = 0; i < dc->res_pool->audio_count; i++) { struct audio *audio = dc->res_pool->audios[i]; @@ -936,7 +944,10 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, if (plane_state->in_transfer_func) tf = plane_state->in_transfer_func; - if (plane_state->gamma_correction && dce_use_lut(plane_state)) + if (plane_state->gamma_correction && + plane_state->gamma_correction->is_identity) + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + else if (plane_state->gamma_correction && dce_use_lut(plane_state->format)) dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); if (tf == NULL) @@ -1007,8 +1018,6 @@ static void dcn10_pipe_control_lock( struct pipe_ctx *pipe, bool lock) { - struct hubp *hubp = NULL; - hubp = dc->res_pool->hubps[pipe->pipe_idx]; /* use TG master update lock to lock everything on the TG * therefore only top pipe need to lock */ @@ -1111,7 +1120,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( DC_SYNC_INFO("Waiting for trigger\n"); - for (i = 1; i < group_size; i++) + for (i = 0; i < group_size; i++) wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); DC_SYNC_INFO("Multi-display sync is complete\n"); @@ -1121,7 +1130,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( struct dc *core_dc, struct pipe_ctx *pipe_ctx) { - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\n============== DML TTU Output parameters [%d] ==============\n" "qos_level_low_wm: %d, \n" "qos_level_high_wm: %d, \n" @@ -1151,7 +1160,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c ); - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\n============== DML DLG Output parameters [%d] ==============\n" "refcyc_h_blank_end: %d, \n" "dlg_vblank_end: %d, \n" @@ -1186,7 +1195,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l ); - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_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" @@ -1216,7 +1225,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_line_delivery_c ); - dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, "\n============== DML RQ Output parameters [%d] ==============\n" "chunk_size: %d \n" "min_chunk_size: %d \n" @@ -1337,19 +1346,19 @@ static void dcn10_enable_plane( undo_DEGVIDCN10_253_wa(dc); power_on_plane(dc->hwseq, - pipe_ctx->pipe_idx); + pipe_ctx->plane_res.hubp->inst); /* enable DCFCLK current DCHUB */ - REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx], - HUBP_CLOCK_ENABLE, 1); + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); /* make sure OPP_PIPE_CLOCK_EN = 1 */ - REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->stream_res.tg->inst], - OPP_PIPE_CLOCK_EN, 1); + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); /* TODO: enable/disable in dm as per update type. if (plane_state) { - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Pipe:%d 0x%x: addr hi:0x%x, " "addr low:0x%x, " "src: %d, %d, %d," @@ -1367,7 +1376,7 @@ static void dcn10_enable_plane( plane_state->dst_rect.width, plane_state->dst_rect.height); - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC(dc->ctx->logger, "Pipe %d: width, height, x, y format:%d\n" "viewport:%d, %d, %d, %d\n" "recout: %d, %d, %d, %d\n", @@ -1394,6 +1403,7 @@ static void dcn10_enable_plane( static void program_gamut_remap(struct pipe_ctx *pipe_ctx) { + int i = 0; struct dpp_grph_csc_adjustment adjust; memset(&adjust, 0, sizeof(adjust)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; @@ -1401,33 +1411,9 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx) if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - adjust.temperature_matrix[0] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[0]; - adjust.temperature_matrix[1] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[1]; - adjust.temperature_matrix[2] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[2]; - adjust.temperature_matrix[3] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[4]; - adjust.temperature_matrix[4] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[5]; - adjust.temperature_matrix[5] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[6]; - adjust.temperature_matrix[6] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[8]; - adjust.temperature_matrix[7] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[9]; - adjust.temperature_matrix[8] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[10]; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; } pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); @@ -1488,7 +1474,7 @@ static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) return false; } -static bool is_rgb_cspace(enum dc_color_space output_color_space) +bool is_rgb_cspace(enum dc_color_space output_color_space) { switch (output_color_space) { case COLOR_SPACE_SRGB: @@ -1626,6 +1612,7 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } + static void update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; @@ -1716,22 +1703,28 @@ static void update_dchubp_dpp( 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; union plane_size size = plane_state->plane_size; /* depends on DML calculation, DPP clock value may change dynamically */ + /* If request max dpp clk is lower than current dispclk, no need to + * divided by 2 + */ if (plane_state->update_flags.bits.full_update) { - enable_dppclk( - dc->hwseq, - pipe_ctx->pipe_idx, - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk, - context->bw.dcn.calc_clk.dppclk_div); - dc->current_state->bw.dcn.cur_clk.dppclk_div = - context->bw.dcn.calc_clk.dppclk_div; - context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div; + bool should_divided_by_2 = context->bw.dcn.calc_clk.dppclk_khz <= + context->bw.dcn.cur_clk.dispclk_khz / 2; + + dpp->funcs->dpp_dppclk_control( + dpp, + should_divided_by_2, + true); + + dc->current_state->bw.dcn.cur_clk.dppclk_khz = + should_divided_by_2 ? + context->bw.dcn.cur_clk.dispclk_khz / 2 : + context->bw.dcn.cur_clk.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -1739,7 +1732,7 @@ static void update_dchubp_dpp( * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG */ if (plane_state->update_flags.bits.full_update) { - REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->stream_res.tg->inst); + hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); hubp->funcs->hubp_setup( hubp, @@ -1792,6 +1785,7 @@ static void update_dchubp_dpp( } if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.pixel_format_change || plane_state->update_flags.bits.horizontal_mirror_change || plane_state->update_flags.bits.rotation_change || plane_state->update_flags.bits.swizzle_change || @@ -1816,14 +1810,62 @@ static void update_dchubp_dpp( hubp->funcs->set_blank(hubp, false); } +static void dcn10_otg_blank( + struct dc *dc, + struct stream_resource stream_res, + struct dc_stream_state *stream, + bool blank) +{ + enum dc_color_space color_space; + struct tg_color black_color = {0}; + + /* program otg blank color */ + color_space = stream->output_color_space; + color_space_to_black_color(dc, color_space, &black_color); + + if (stream_res.tg->funcs->set_blank_color) + stream_res.tg->funcs->set_blank_color( + stream_res.tg, + &black_color); + + if (!blank) { + if (stream_res.tg->funcs->set_blank) + stream_res.tg->funcs->set_blank(stream_res.tg, blank); + if (stream_res.abm) + stream_res.abm->funcs->set_abm_level(stream_res.abm, stream->abm_level); + } else if (blank) { + if (stream_res.abm) + stream_res.abm->funcs->set_abm_immediate_disable(stream_res.abm); + if (stream_res.tg->funcs->set_blank) + stream_res.tg->funcs->set_blank(stream_res.tg, blank); + } +} + +static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) +{ + struct fixed31_32 multiplier = dal_fixed31_32_from_fraction( + pipe_ctx->plane_state->sdr_white_level, 80); + uint32_t hw_mult = 0x1f000; // 1.0 default multiplier + struct custom_float_format fmt; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = true; + + if (pipe_ctx->plane_state->sdr_white_level > 80) + convert_to_custom_float_format(multiplier, &fmt, &hw_mult); + + pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( + pipe_ctx->plane_res.dpp, hw_mult); +} static void program_all_pipe_in_tree( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { - if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; @@ -1834,22 +1876,21 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg->funcs->program_global_sync( pipe_ctx->stream_res.tg); - if (pipe_ctx->stream_res.tg->funcs->set_blank) - pipe_ctx->stream_res.tg->funcs->set_blank( - pipe_ctx->stream_res.tg, - !is_pipe_tree_visible(pipe_ctx)); + dcn10_otg_blank(dc, pipe_ctx->stream_res, + pipe_ctx->stream, blank); } if (pipe_ctx->plane_state != NULL) { - struct pipe_ctx *cur_pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; - if (pipe_ctx->plane_state->update_flags.bits.full_update) dcn10_enable_plane(dc, pipe_ctx, context); update_dchubp_dpp(dc, pipe_ctx, context); - if (cur_pipe_ctx->plane_state != pipe_ctx->plane_state) + 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); /* dcn10_translate_regamma_to_hw_format takes 750us to finish @@ -1862,8 +1903,9 @@ static void program_all_pipe_in_tree( dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); } - if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) + if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) { program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); + } } static void dcn10_pplib_apply_display_requirements( @@ -1872,16 +1914,10 @@ static void dcn10_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->all_displays_in_sync = false;/*todo*/ - pp_display_cfg->nb_pstate_switch_disable = false; pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->avail_mclk_switch_time_us = - context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0; - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = - context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0; pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); @@ -1944,28 +1980,23 @@ static void dcn10_apply_ctx_for_surface( { int i; struct timing_generator *tg; - struct output_pixel_processor *opp; bool removed_pipe[4] = { false }; unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; bool program_water_mark = false; - + struct dc_context *ctx = dc->ctx; struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); if (!top_pipe_to_program) return; - opp = top_pipe_to_program->stream_res.opp; - tg = top_pipe_to_program->stream_res.tg; - tg->funcs->lock(tg); + dcn10_pipe_control_lock(dc, top_pipe_to_program, true); if (num_planes == 0) { - /* OTG blank before remove all front end */ - if (tg->funcs->set_blank) - tg->funcs->set_blank(tg, true); + dcn10_otg_blank(dc, top_pipe_to_program->stream_res, top_pipe_to_program->stream, true); } /* Disconnect unused mpcc */ @@ -1983,7 +2014,7 @@ static void dcn10_apply_ctx_for_surface( if (old_pipe_ctx->stream_res.tg == tg && old_pipe_ctx->plane_res.hubp && old_pipe_ctx->plane_res.hubp->opp_id != 0xf) { - dcn10_disable_plane(dc, pipe_ctx); + dcn10_disable_plane(dc, old_pipe_ctx); /* * power down fe will unlock when calling reset, need * to lock it back here. Messy, need rework. @@ -1999,7 +2030,7 @@ static void dcn10_apply_ctx_for_surface( plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; - dm_logger_write(dc->ctx->logger, LOG_DC, + DC_LOG_DC( "Reset mpcc for pipe %d\n", old_pipe_ctx->pipe_idx); } @@ -2008,7 +2039,7 @@ static void dcn10_apply_ctx_for_surface( if (num_planes > 0) program_all_pipe_in_tree(dc, top_pipe_to_program, context); - tg->funcs->unlock(tg); + dcn10_pipe_control_lock(dc, top_pipe_to_program, false); if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); @@ -2042,7 +2073,7 @@ static void dcn10_apply_ctx_for_surface( dcn10_verify_allow_pstate_change_high(dc); } } -/* dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, +/* DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== Watermark parameters ==============\n" "a.urgent_ns: %d \n" "a.cstate_enter_plus_exit: %d \n" @@ -2065,7 +2096,7 @@ static void dcn10_apply_ctx_for_surface( context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns, context->bw.dcn.watermarks.b.pte_meta_urgent_ns ); - dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\nc.urgent_ns: %d \n" "c.cstate_enter_plus_exit: %d \n" "c.cstate_exit: %d \n" @@ -2091,6 +2122,101 @@ static void dcn10_apply_ctx_for_surface( */ } +static inline bool should_set_clock(bool decrease_allowed, int calc_clk, int cur_clk) +{ + return ((decrease_allowed && calc_clk < cur_clk) || calc_clk > cur_clk); +} + +static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) +{ + bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.calc_clk.dppclk_khz; + bool dispclk_increase = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.cur_clk.dispclk_khz; + int disp_clk_threshold = context->bw.dcn.calc_clk.max_supported_dppclk_khz; + bool cur_dpp_div = context->bw.dcn.cur_clk.dispclk_khz > + context->bw.dcn.cur_clk.dppclk_khz; + + /* increase clock, looking for div is 0 for current, request div is 1*/ + if (dispclk_increase) { + /* already divided by 2, no need to reach target clk with 2 steps*/ + if (cur_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* request disp clk is lower than maximum supported dpp clk, + * no need to reach target clk with two steps. + */ + if (context->bw.dcn.calc_clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* target dpp clk not request divided by 2, still within threshold */ + if (!request_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + } else { + /* decrease clock, looking for current dppclk divided by 2, + * request dppclk not divided by 2. + */ + + /* current dpp clk not divided by 2, no need to ramp*/ + if (!cur_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* current disp clk is lower than current maximum dpp clk, + * no need to ramp + */ + if (context->bw.dcn.cur_clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.calc_clk.dispclk_khz; + + /* request dpp clk need to be divided by 2 */ + if (request_dpp_div) + return context->bw.dcn.calc_clk.dispclk_khz; + } + + return disp_clk_threshold; +} + +static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) +{ + int i; + bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > + context->bw.dcn.calc_clk.dppclk_khz; + + int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); + + /* set disp clk to dpp clk threshold */ + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + dispclk_to_dpp_threshold); + + /* update request dpp clk division option */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state) + continue; + + pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( + pipe_ctx->plane_res.dpp, + request_dpp_div, + true); + } + + /* If target clk not same as dppclk threshold, set to target clock */ + if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + context->bw.dcn.calc_clk.dispclk_khz); + } + + context->bw.dcn.cur_clk.dispclk_khz = + context->bw.dcn.calc_clk.dispclk_khz; + context->bw.dcn.cur_clk.dppclk_khz = + context->bw.dcn.calc_clk.dppclk_khz; + context->bw.dcn.cur_clk.max_supported_dppclk_khz = + context->bw.dcn.calc_clk.max_supported_dppclk_khz; +} + static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, @@ -2108,31 +2234,33 @@ static void dcn10_set_bandwidth( if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; - if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz - > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - dc->current_state->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - } - if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dcfclk_khz, + dc->current_state->bw.dcn.cur_clk.dcfclk_khz)) { + context->bw.dcn.cur_clk.dcfclk_khz = + context->bw.dcn.calc_clk.dcfclk_khz; smu_req.hard_min_dcefclk_khz = context->bw.dcn.calc_clk.dcfclk_khz; } - if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz - > dc->current_state->bw.dcn.cur_clk.fclk_khz) { - smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; - } - if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) { - dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; + + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, + dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz)) { context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; } + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.fclk_khz, + dc->current_state->bw.dcn.cur_clk.fclk_khz)) { + context->bw.dcn.cur_clk.fclk_khz = + context->bw.dcn.calc_clk.fclk_khz; + smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; + } + smu_req.display_count = context->stream_count; if (pp_smu->set_display_requirement) @@ -2140,21 +2268,17 @@ static void dcn10_set_bandwidth( *smu_req_cur = smu_req; - /* Decrease in freq is increase in period so opposite comparison for dram_ccm */ - if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us - < dc->current_state->bw.dcn.cur_clk.dram_ccm_us) { - dc->current_state->bw.dcn.calc_clk.dram_ccm_us = - context->bw.dcn.calc_clk.dram_ccm_us; - context->bw.dcn.cur_clk.dram_ccm_us = - context->bw.dcn.calc_clk.dram_ccm_us; - } - if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us - < dc->current_state->bw.dcn.cur_clk.min_active_dram_ccm_us) { - dc->current_state->bw.dcn.calc_clk.min_active_dram_ccm_us = - context->bw.dcn.calc_clk.min_active_dram_ccm_us; - context->bw.dcn.cur_clk.min_active_dram_ccm_us = - context->bw.dcn.calc_clk.min_active_dram_ccm_us; + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ + if (should_set_clock( + decrease_allowed, + context->bw.dcn.calc_clk.dispclk_khz, + dc->current_state->bw.dcn.cur_clk.dispclk_khz)) { + + ramp_up_dispclk_with_dpp(dc, context); } + dcn10_pplib_apply_display_requirements(dc, context); if (dc->debug.sanity_checks) { @@ -2203,6 +2327,8 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, value |= 0x80; if (events->cursor_update) value |= 0x2; + if (events->force_trigger) + value |= 0x1; for (i = 0; i < num_pipes; i++) pipe_ctx[i]->stream_res.tg->funcs-> @@ -2275,12 +2401,24 @@ static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) return; } +static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) +{ + int i; + + for (i = 0; i < res_pool->pipe_count; i++) { + if (res_pool->hubps[i]->inst == mpcc_inst) + return res_pool->hubps[i]; + } + ASSERT(false); + return NULL; +} + static void dcn10_wait_for_mpcc_disconnect( struct dc *dc, struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx) { - int i; + int mpcc_inst; if (dc->debug.sanity_checks) { dcn10_verify_allow_pstate_change_high(dc); @@ -2289,12 +2427,14 @@ static void dcn10_wait_for_mpcc_disconnect( if (!pipe_ctx->stream_res.opp) return; - for (i = 0; i < MAX_PIPES; i++) { - if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i]) { - res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, i); - pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i] = false; - res_pool->hubps[i]->funcs->set_blank(res_pool->hubps[i], true); - /*dm_logger_write(dc->ctx->logger, LOG_ERROR, + for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { + if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { + struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); + + res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); + pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; + hubp->funcs->set_blank(hubp, true); + /*DC_LOG_ERROR(dc->ctx->logger, "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", i);*/ } @@ -2395,6 +2535,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .enable_stream = dce110_enable_stream, .disable_stream = dce110_disable_stream, .unblank_stream = dce110_unblank_stream, + .blank_stream = dce110_blank_stream, .enable_display_power_gating = dcn10_dummy_display_power_gating, .disable_plane = dcn10_disable_plane, .pipe_control_lock = dcn10_pipe_control_lock, |