staticint find_free_gsl_group(conststruct dc *dc)
{ if (dc->res_pool->gsl_groups.gsl_0 == 0) return1; if (dc->res_pool->gsl_groups.gsl_1 == 0) return2; if (dc->res_pool->gsl_groups.gsl_2 == 0) return3;
return0;
}
/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) *Thisisonlyusedtolockpipesinpipesplittingcasewithimmediateflip *OrdinaryMPC/OTGlockssuppressVUPDATEwhichdoesn'thelpwithimmediate, *sowegettearingwithfreesyncsincewecannotflipmultiplepipes *atomically. *WeuseGSLforthis: *-immediateflip:findfirstavailableGSLgroupifnotalreadyassigned *programgslwiththatgroup,setcurrentOTGasmaster *andalwaysus0x4=ANDofflip_readyfromallpipes *-vsyncflip:disableGSLifused * *Groupsinstream_resarestoredas+1fromHWregisters,i.e. *gsl_0<=>pipe_ctx->stream_res.gsl_group==1 *Usingamagicvaluelike-1wouldrequiretrackingallinits/resets
*/ void dcn20_setup_gsl_group_as_lock( conststruct dc *dc, struct pipe_ctx *pipe_ctx, bool enable)
{ struct gsl_params gsl; int group_idx;
memset(&gsl, 0, sizeof(struct gsl_params));
if (enable) { /* return if group already assigned since GSL was set up *forvsyncflip,wewouldunassignsoitcan'tbe"leftover"
*/ if (pipe_ctx->stream_res.gsl_group > 0) return;
/* at this point we want to program whether it's to enable or disable */ if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL) {
pipe_ctx->stream_res.tg->funcs->set_gsl(
pipe_ctx->stream_res.tg,
&gsl); if (pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL)
pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(
pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);
} else
BREAK_TO_DEBUGGER();
}
/* program opp dpg blank color */
color_space = COLOR_SPACE_SRGB;
color_space_to_black_color(dc, color_space, &black_color);
/* get the OTG active size */
tg->funcs->get_otg_active_size(tg,
&otg_active_width,
&otg_active_height);
/* get the OPTC source */
tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) {
ASSERT(false); return;
}
opp = dc->res_pool->opps[opp_id_src0];
/* don't override the blank pattern if already enabled with the correct one. */ if (opp->funcs->dpg_is_blanked && opp->funcs->dpg_is_blanked(opp)) return;
if (num_opps == 2) {
otg_active_width = otg_active_width / 2;
/* In flip immediate with pipe splitting case GSL is used for *synchronizationsowemustdisableitwhentheplaneisdisabled.
*/ if (pipe_ctx->stream_res.gsl_group != 0)
dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
if (hubp->funcs->hubp_update_mall_sel)
hubp->funcs->hubp_update_mall_sel(hubp, 0, false);
if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return;
dcn20_plane_atomic_disable(dc, pipe_ctx);
/* Turn back off the phantom OTG after the phantom plane is fully disabled
*/ if (is_phantom) if (tg && tg->funcs->disable_phantom_crtc)
tg->funcs->disable_phantom_crtc(tg);
DC_LOG_DC("Power down front end %d\n",
pipe_ctx->pipe_idx);
}
if (dc->res_pool->dccg->funcs->set_pixel_rate_div)
dc->res_pool->dccg->funcs->set_pixel_rate_div(
dc->res_pool->dccg,
pipe_ctx->stream_res.tg->inst,
pipe_ctx->pixel_rate_divider.div_factor1,
pipe_ctx->pixel_rate_divider.div_factor2);
/* by upper caller loop, pipe0 is parent pipe and be called first. *backendissetupbyforpipe0.Otherchildrenpipesharebackend *withpipe0.Noprogramisneeded.
*/ if (pipe_ctx->top_pipe != NULL) return DC_OK;
/* TODO check if timing_changed, disable stream if timing changed */
opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads); for (i = 0; i < opp_cnt; i++)
opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
flow_control.flow_ctrl_mode = 0;
flow_control.flow_ctrl_cnt0 = 0x80;
flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt,
is_two_pixels_per_container); if (mpc->funcs->set_out_rate_control) { for (i = 0; i < opp_cnt; ++i) {
mpc->funcs->set_out_rate_control(
mpc, opp_inst[i], true,
rate_control_2x_pclk,
&flow_control);
}
}
for (i = 0; i < opp_cnt; i++) {
opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
opp_heads[i]->stream_res.opp, true);
opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
opp_heads[i]->stream_res.opp,
stream->timing.pixel_encoding,
resource_is_pipe_type(opp_heads[i], OTG_MASTER));
}
hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
/* VTG is within DCHUB command block. DCFCLK is always on */ if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
BREAK_TO_DEBUGGER(); return DC_ERROR_UNEXPECTED;
}
// DRR should set trigger event to monitor surface update event if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
event_triggers = 0x80; /* Event triggers and num frames initialized for DRR, but can be *laterupdatedforPSRuse.NoteDRRtriggereventsaregenerated *regardlessofwhethernumframesmet.
*/ if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx->stream_res.tg, event_triggers, 2);
/* TODO program crtc source select for non-virtual signal*/ /* TODO program FMT */ /* TODO setup link_enc */ /* TODO set stream attributes */ /* TODO program audio */ /* TODO enable stream if timing changed */ /* TODO unblank stream if DP */
if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) { if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)
pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);
}
return DC_OK;
}
void dcn20_program_output_csc(struct dc *dc, struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace,
uint16_t *matrix, int opp_id)
{ struct mpc *mpc = dc->res_pool->mpc; enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; int mpcc_id = pipe_ctx->plane_res.hubp->inst;
if (mpc->funcs->power_on_mpc_mem_pwr)
mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { if (mpc->funcs->set_output_csc != NULL)
mpc->funcs->set_output_csc(mpc,
opp_id,
matrix,
ocsc_mode);
} else { if (mpc->funcs->set_ocsc_default != NULL)
mpc->funcs->set_ocsc_default(mpc,
opp_id,
colorspace,
ocsc_mode);
}
}
result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); if (plane_state->lut3d_func.state.bits.initialized == 1)
result = dpp_base->funcs->dpp_program_3dlut(dpp_base,
&plane_state->lut3d_func.lut_3d); else
result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL);
/* use TG master update lock to lock everything on the TG *thereforeonlytoppipeneedtolock
*/ if (!pipe || pipe->top_pipe) return;
if (pipe->plane_state != NULL)
flip_immediate = pipe->plane_state->flip_immediate;
if (pipe->stream_res.gsl_group > 0) {
temp_pipe = pipe->bottom_pipe; while (!flip_immediate && temp_pipe) { if (temp_pipe->plane_state != NULL)
flip_immediate = temp_pipe->plane_state->flip_immediate;
temp_pipe = temp_pipe->bottom_pipe;
}
}
if (flip_immediate && lock) { constint TIMEOUT_FOR_FLIP_PENDING_US = 100000; unsignedint polling_interval_us = 1; int i;
temp_pipe = pipe; while (temp_pipe) { if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) { for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) { if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp)) break;
udelay(polling_interval_us);
}
/* no reason it should take this long for immediate flips */
ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US);
}
temp_pipe = temp_pipe->bottom_pipe;
}
}
/* In flip immediate and pipe splitting case, we need to use GSL *forsynchronization.Onlydosetuponlockingandonfliptypechange.
*/ if (lock && (pipe->bottom_pipe != NULL || !flip_immediate)) if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||
(!flip_immediate && pipe->stream_res.gsl_group > 0))
dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);
if (pipe->plane_state != NULL)
flip_immediate = pipe->plane_state->flip_immediate;
temp_pipe = pipe->bottom_pipe; while (flip_immediate && temp_pipe) { if (temp_pipe->plane_state != NULL)
flip_immediate = temp_pipe->plane_state->flip_immediate;
temp_pipe = temp_pipe->bottom_pipe;
}
/* For SubVP we need to unconditionally enable because any phantom pipes are *alwaysremovedthennewlyaddedforeveryfullupdateswheneverSubVPisinuse. *Theremove-addsequenceofthephantompipealwaysresultsinthepipe *beingblankedinenable_stream_timing(DPG).
*/ if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)
new_pipe->update_flags.bits.enable = 1;
/* Phantom pipes are effectively disabled, if the pipe was previously phantom *wehavetoenable
*/ if (old_pipe->plane_state && old_is_phantom &&
new_pipe->plane_state && !new_is_phantom)
new_pipe->update_flags.bits.enable = 1;
if (old_pipe->plane_state && !new_pipe->plane_state) {
new_pipe->update_flags.bits.disable = 1; return;
}
if (pipe_ctx->update_flags.bits.dppclk)
dpp->funcs->dpp_dppclk_control(dpp, false, true);
if (pipe_ctx->update_flags.bits.enable)
dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);
/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG *VTGiswithinDCHUBBUBwhichiscommondblocksharebyeachpipeHUBP. *VTGis1:1mappingwithOTG.EachpipeHUBPwillselectwhichVTG
*/
if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
// program the input csc
dpp->funcs->dpp_setup(dpp,
plane_state->format,
EXPANSION_MODE_ZERO,
plane_state->input_csc_color_matrix,
plane_state->color_space,
NULL);
if (dpp->funcs->set_cursor_matrix) {
dpp->funcs->set_cursor_matrix(dpp,
plane_state->color_space,
plane_state->cursor_csc_color_matrix);
} if (dpp->funcs->dpp_program_bias_and_scale) { //TODO :for CNVC set scale and bias registers if necessary
dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
}
}
if (pipe_ctx->update_flags.bits.mpcc
|| pipe_ctx->update_flags.bits.plane_changed
|| plane_state->update_flags.bits.global_alpha_change
|| plane_state->update_flags.bits.per_pixel_alpha_change) { // MPCC inst is equal to pipe index in practice
hws->funcs.update_mpcc(dc, pipe_ctx);
}
if (hubp->funcs->hubp_program_mcache_id_and_split_coordinate)
hubp->funcs->hubp_program_mcache_id_and_split_coordinate(hubp, &pipe_ctx->mcache_regs);
/* Any updates are handled in dc interface, just need to apply existing for plane enable */ 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) {
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
if (dc->hwss.set_cursor_sdr_white_level)
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
}
/* Any updates are handled in dc interface, just need
* to apply existing for plane enable / opp change */ if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
|| pipe_ctx->update_flags.bits.plane_changed
|| pipe_ctx->stream->update_flags.bits.gamut_remap
|| plane_state->update_flags.bits.gamut_remap_change
|| pipe_ctx->stream->update_flags.bits.out_csc) { /* dpp/cm gamut remap*/
dc->hwss.program_gamut_remap(pipe_ctx);
/*call the dcn2 method which uses mpc csc*/
dc->hwss.program_output_csc(dc,
pipe_ctx,
pipe_ctx->stream->output_color_space,
pipe_ctx->stream->csc_color_matrix.matrix,
hubp->opp_id);
}
if (pipe_ctx->update_flags.bits.enable)
hubp->funcs->set_blank(hubp, false); /* If the stream paired with this plane is phantom, the plane is also phantom */ if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable)
hubp->funcs->phantom_hubp_post_enable(hubp);
}
/* Only need to unblank on top pipe */ if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) { if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.odm ||
pipe_ctx->stream->update_flags.bits.abm_level)
hws->funcs.blank_pixel_data(dc, pipe_ctx,
!pipe_ctx->plane_state ||
!pipe_ctx->plane_state->visible);
}
/* Only update TG on top pipe */ if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
&& !pipe_ctx->prev_odm_pipe)
dcn20_program_tg(dc, pipe_ctx, context, hws);
if (pipe_ctx->update_flags.bits.odm)
hws->funcs.update_odm(dc, context, pipe_ctx);
if (pipe_ctx->update_flags.bits.enable) { if (hws->funcs.enable_plane)
hws->funcs.enable_plane(dc, pipe_ctx, context); else
dcn20_enable_plane(dc, pipe_ctx, context);
if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
}
if (pipe_ctx->update_flags.bits.det_size) { if (dc->res_pool->hubbub->funcs->program_det_size)
dc->res_pool->hubbub->funcs->program_det_size(
dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
if (dc->res_pool->hubbub->funcs->program_det_segments)
dc->res_pool->hubbub->funcs->program_det_segments(
dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);
}
/* dcn10_translate_regamma_to_hw_format takes 750us to finish *onlydogammaprogrammingforpoweringon,internalmemcmptoavoid *updatingonslaveplanes
*/ if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
pipe_ctx->stream->update_flags.bits.out_tf)
hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
/* If the pipe has been enabled or has a different opp, we *shouldreprogramthefmt.Thisdealswithcaseswhere *interationbetweenmpcandodmcombineondifferentstreams *causesadifferentpipetobechosentoodmcombinewith.
*/ if (pipe_ctx->update_flags.bits.enable
|| pipe_ctx->update_flags.bits.opp_changed) {
/* Set ABM pipe after other pipe configurations done */ if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) { if (pipe_ctx->stream_res.abm) {
dc->hwss.set_pipe(pipe_ctx);
pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
pipe_ctx->stream->abm_level);
}
}
if (resource_is_pipe_topology_changed(dc->current_state, context))
resource_log_pipe_topology_update(dc, context);
if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
if (pipe->plane_state) {
ASSERT(!pipe->plane_state->triplebuffer_flips); /*turn off triple buffer for full update*/
dc->hwss.program_triplebuffer(
dc, pipe, pipe->plane_state->triplebuffer_flips);
}
}
}
for (i = 0; i < dc->res_pool->pipe_count; i++) { if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
prev_hubp_count++; if (context->res_ctx.pipe_ctx[i].plane_state)
hubp_count++;
}
if (prev_hubp_count == 0 && hubp_count > 0) { if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
dc->res_pool->hubbub->funcs->force_pstate_change_control(
dc->res_pool->hubbub, true, false);
udelay(500);
}
/* Set pipe update flags and lock pipes */ for (i = 0; i < dc->res_pool->pipe_count; i++)
dcn20_detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
&context->res_ctx.pipe_ctx[i]);
/* When disabling phantom pipes, turn on phantom OTG first (so we can get double *bufferupdatesproperly)
*/ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
if (tg->funcs->enable_crtc) { if (dc->hwseq->funcs.blank_pixel_data)
dc->hwseq->funcs.blank_pixel_data(dc, pipe, true);
tg->funcs->enable_crtc(tg);
}
}
} /* OTG blank before disabling all front ends */ for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
&& !context->res_ctx.pipe_ctx[i].top_pipe
&& !context->res_ctx.pipe_ctx[i].prev_odm_pipe
&& context->res_ctx.pipe_ctx[i].stream)
hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
/* Disconnect mpcc */ for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
|| context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { struct hubbub *hubbub = dc->res_pool->hubbub;
/* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom *thenwewanttodotheprogramminghere(effectivelyit'sbeingdisabled).Ifwedo *theprogramminglatertheDETwon'tbeupdateduntiltheOTGforthephantompipeis *turnedon(i.e.inanMCLKswitch)whichcancomeintoolateandcauseissueswith *DETallocation.
*/ if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
(context->res_ctx.pipe_ctx[i].plane_state &&
dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i])
== SUBVP_PHANTOM))) { if (hubbub->funcs->program_det_size)
hubbub->funcs->program_det_size(hubbub,
dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); if (dc->res_pool->hubbub->funcs->program_det_segments)
dc->res_pool->hubbub->funcs->program_det_segments(
hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
}
hws->funcs.plane_atomic_disconnect(dc, dc->current_state,
&dc->current_state->res_ctx.pipe_ctx[i]);
DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
}
/* update ODM for blanked OTG master pipes */ for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i]; if (resource_is_pipe_type(pipe, OTG_MASTER) &&
!resource_is_pipe_type(pipe, DPP_PIPE) &&
pipe->update_flags.bits.odm &&
hws->funcs.update_odm)
hws->funcs.update_odm(dc, context, pipe);
}
/* *Programallupdatedpipes,ordermattersformpccsetup.Startwith *toppipeandprogramallpipesthatfollowinorder
*/ for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
if (pipe->plane_state && !pipe->top_pipe) { while (pipe) { if (hws->funcs.program_pipe)
hws->funcs.program_pipe(dc, pipe, context); else { /* Don't program phantom pipes in the regular front end programming sequence. *ThereisanMPOtransitioncasewhereapipebeingusedbyavideoplaneis *transitioneddirectlytobeaphantompipewhenclosingtheMPOvideo. *HoweverthephantompipewillprogramanewHUBP_VTG_SEL(updatetakesplace *rightaway)buttheMPOstillexistsuntilthedoublebufferedupdateofthe *mainpipesowewillgetaframeofunderflowifthephantompipeis *programmedhere.
*/ if (pipe->stream &&
dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)
dcn20_program_pipe(dc, pipe, context);
}
pipe = pipe->bottom_pipe;
}
}
/* Program secondary blending tree and writeback pipes */
pipe = &context->res_ctx.pipe_ctx[i]; if (!pipe->top_pipe && !pipe->prev_odm_pipe
&& pipe->stream && pipe->stream->num_wb_info > 0
&& (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)
|| pipe->stream->update_flags.raw)
&& hws->funcs.program_all_writeback_pipes_in_tree)
hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
/* Avoid underflow by check of pipe line read when adding 2nd plane. */ if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
!pipe->top_pipe &&
pipe->stream &&
pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
dc->current_state->stream_status[0].plane_count == 1 &&
context->stream_status[0].plane_count > 1) {
pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
}
}
}
/* post_unlock_reset_opp - the function wait for corresponding double *bufferedpendingstatusclearandresetoppheadpipe'snonedoublebuffered *registerstotheirinitialstate.
*/ void dcn20_post_unlock_reset_opp(struct dc *dc, struct pipe_ctx *opp_head)
{ struct display_stream_compressor *dsc = opp_head->stream_res.dsc; struct dccg *dccg = dc->res_pool->dccg;
if (dc->hwseq->funcs.dsc_pg_status)
is_dsc_ungated = dc->hwseq->funcs.dsc_pg_status(dc->hwseq, dsc->inst);
if (is_dsc_ungated) { /* *seamlessupdatespecificwherewewillpostponenon *doublebufferedDSCCLKdisablelogicinpostunlock *sequenceafterDSCisdisconnectedfromOPPbutnot *yetpowergated.
*/
dsc->funcs->dsc_wait_disconnect_pending_clear(dsc);
dsc->funcs->dsc_disable(dsc); if (dccg->funcs->set_ref_dscclk)
dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
}
}
}
void dcn20_post_unlock_program_front_end( struct dc *dc, struct dc_state *context)
{ // Timeout for pipe enable unsignedint timeout_us = 100000; unsignedint polling_interval_us = 1; struct dce_hwseq *hwseq = dc->hwseq; int i;
for (i = 0; i < dc->res_pool->pipe_count; i++) if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
dcn20_post_unlock_reset_opp(dc,
&dc->current_state->res_ctx.pipe_ctx[i]);
for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
/* *Ifweareenablingapipe,weneedtowaitforpendingclearasthisisacritical *partoftheenableoperationotherwise,DMmayrequestanimmediateflipwhich *willcauseHWtoperforman"immediateenable"(asopposedto"vsyncenable")which *isunsupportedonDCN.
*/ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; // Don't check flip pending on phantom pipes if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) { struct hubp *hubp = pipe->plane_res.hubp; int j = 0;
for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
/* When going from a smaller ODM slice count to larger, we must ensure double *bufferupdatecompletesbeforewereturntoensurewedon'treduceDISPCLK *beforewe'vetransitionedto2:1or4:1
*/ if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&
resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&
dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) { int j = 0; struct timing_generator *tg = pipe->stream_res.tg;
if (tg->funcs->get_optc_double_buffer_pending) { for (j = 0; j < timeout_us / polling_interval_us
&& tg->funcs->get_optc_double_buffer_pending(tg); j++)
udelay(polling_interval_us);
}
}
}
if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
dc->res_pool->hubbub->funcs->force_pstate_change_control(
dc->res_pool->hubbub, false, false);
for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (pipe->plane_state && !pipe->top_pipe) { /* Program phantom pipe here to prevent a frame of underflow in the MPO transition *case(ifapipebeingusedforavideoplanetransitionstoaphantompipe,it *canunderflowduetoHUBP_VTG_SELprogrammingifdoneintheregularfrontend *programmingsequence).
*/ while (pipe) { if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { /* When turning on the phantom pipe we want to run through the *entireenablesequence,soapplyallthe"enable"flags.
*/ if (dc->hwss.apply_update_flags_for_phantom)
dc->hwss.apply_update_flags_for_phantom(pipe); if (dc->hwss.update_phantom_vp_position)
dc->hwss.update_phantom_vp_position(dc, context, pipe);
dcn20_program_pipe(dc, pipe, context);
}
pipe = pipe->bottom_pipe;
}
}
}
if (!hwseq) return;
/* P-State support transitions: *Natural->FPO:P-Statedisabledinprepare,forcedisallowanytimeissafe *FPO->Natural:UnforceanytimeafterFWdisableissafe(P-Statewillassertnaturally) *Unsupported->FPO:P-Stateenabledinoptimize,forcedisallowanytimeissafe *FPO->Unsupported:P-Statedisabledinprepare,unforcedisallowanytimeissafe *FPO<->SubVP:ForcedisallowismaintainedontheFPO/SubVPpipes
*/ if (hwseq->funcs.update_force_pstate)
dc->hwseq->funcs.update_force_pstate(dc, context);
/* Only program the MALL registers after all the main and phantom pipes *aredoneprogramming.
*/ if (hwseq->funcs.program_mall_pipe_config)
hwseq->funcs.program_mall_pipe_config(dc, context);
/* WA to apply WM setting*/ if (hwseq->wa.DEGVIDCN21)
dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
/* WA for stutter underflow during MPO transitions when adding 2nd plane */ if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
if (dc->current_state->stream_status[0].plane_count == 1 &&
context->stream_status[0].plane_count > 1) {
// Restore the real watermark so we can commit the value to DMCUB // DMCUB uses the "original" watermark value in SubVP MCLK switch
context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a;
void dcn20_optimize_bandwidth( struct dc *dc, struct dc_state *context)
{ struct hubbub *hubbub = dc->res_pool->hubbub; int i;
for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
// At optimize don't need to restore the original watermark value if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {
context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; break;
}
}
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
params.opp_cnt++;
} /* only 3 items below are used by unblank */
params.timing = pipe_ctx->stream->timing;
/* DPMS may already disable or */ /* dpms_off status is incorrect due to fastboot *feature.WhensystemresumefromS4withsecond *screenonly,thedpms_offwouldbetruebut *VBIOSlitupeDP,sochecklinkstatustoo.
*/ if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
dc->link_srv->set_dpms_off(pipe_ctx); elseif (pipe_ctx->stream_res.audio)
dc->hwss.disable_audio_stream(pipe_ctx);
/*free audio*/ if (dc->caps.dynamic_audio == true) { /*we have to dynamic arbitrate the audio endpoints*/ /*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);
pipe_ctx->stream_res.audio = NULL;
}
}
/* by upper caller loop, parent pipe: pipe0, will be reset last. *backendsharebyallpipesandwillbedisableonlywhendisable *parentpipe.
*/ if (pipe_ctx->top_pipe == NULL) {
/* If there is no full update, don't need to touch MPC tree*/ if (!pipe_ctx->plane_state->update_flags.bits.full_update &&
!pipe_ctx->update_flags.bits.mpcc) {
mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); return;
}
/* check if this MPCC is already being used */
new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); /* remove MPCC if being used */ if (new_mpcc != NULL)
mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); else if (dc->debug.sanity_checks)
mpc->funcs->assert_mpcc_idle_before_connect(
dc->res_pool->mpc, mpcc_id);
/* Call MPC to insert new plane */
new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
mpc_tree_params,
&blnd_cfg,
NULL,
NULL,
hubp->inst,
mpcc_id);
dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
if (dc->res_pool->dccg->funcs->set_pixel_rate_div)
dc->res_pool->dccg->funcs->set_pixel_rate_div(
dc->res_pool->dccg,
pipe_ctx->stream_res.tg->inst,
pipe_ctx->pixel_rate_divider.div_factor1,
pipe_ctx->pixel_rate_divider.div_factor2);
link_hwss->setup_stream_encoder(pipe_ctx);
if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) { if (dc->hwss.program_dmdata_engine)
dc->hwss.program_dmdata_engine(pipe_ctx);
}
dc->hwss.update_info_frame(pipe_ctx);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
/* enable early control to avoid corruption on DP monitor*/
active_total_with_borders =
timing->h_addressable
+ timing->h_border_left
+ timing->h_border_right;
if (lane_count != 0)
early_control = active_total_with_borders % lane_count;
if (early_control == 0)
early_control = lane_count;
/* if using dynamic meta, don't set up generic infopackets */ if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
enable = true;
}
if (!hubp) return;
if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) return;
void dcn20_fpga_init_hw(struct dc *dc)
{ int i, j; struct dce_hwseq *hws = dc->hwseq; struct resource_pool *res_pool = dc->res_pool; struct dc_state *context = dc->current_state;
if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
// Initialize the dccg if (res_pool->dccg->funcs->dccg_init)
res_pool->dccg->funcs->dccg_init(res_pool->dccg);
//Enable ability to power gate / don't force power on permanently if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(hws, true);
// Specific to FPGA dccg and registers
REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
/* Blank pixel data with OPP DPG */ for (i = 0; i < dc->res_pool->timing_generator_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
dcn20_init_blank(dc, tg);
}
for (i = 0; i < res_pool->timing_generator_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->lock(tg);
}
for (i = 0; i < dc->res_pool->pipe_count; i++) { struct dpp *dpp = res_pool->dpps[i];
dpp->funcs->dpp_reset(dpp);
}
/* Reset all MPCC muxes */
res_pool->mpc->funcs->mpc_init(res_pool->mpc);
/* initialize OPP mpc_tree parameter */ for (i = 0; i < dc->res_pool->pipe_count; i++) {
res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
res_pool->opps[i]->mpc_tree_params.opp_list = NULL; for (j = 0; j < MAX_PIPES; j++)
res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
}
for (i = 0; i < dc->res_pool->pipe_count; i++) { 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];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.