//For now assert if location is not pre-blend if (pipe_ctx->plane_state)
ASSERT(pipe_ctx->plane_state->mcm_location == MPCC_MOVABLE_CM_LOCATION_BEFORE);
// program MPCC_MCM_SECOND_GAMUT_REMAP for Bypass / Disable for now
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_SECOND_GAMUT_REMAP;
// program MPCC_OGAM_GAMUT_REMAP same as is currently used on DCN3x
memset(&mpc_adjust, 0, sizeof(mpc_adjust));
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
mpc_adjust.mpcc_gamut_remap_block_id = MPCC_OGAM_GAMUT_REMAP;
if (pipe_ctx->top_pipe == NULL) { if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
mpc_adjust.temperature_matrix[i] =
pipe_ctx->stream->gamut_remap_matrix.matrix[i];
}
}
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
// mark dcmode limits present if any clock has distinct AC and DC values from SMU
dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
}
// Initialize the dccg if (res_pool->dccg->funcs->dccg_init)
res_pool->dccg->funcs->dccg_init(res_pool->dccg);
// Disable DMUB Initialization until IPS state programming is finalized //if (!dcb->funcs->is_accelerated_mode(dcb)) { // hws->funcs.bios_golden_init(dc); //}
// Set default OPTC memory power states if (dc->debug.enable_mem_low_power.bits.optc) { // Shutdown when unassigned and light sleep in VBLANK
REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
}
if (dc->debug.enable_mem_low_power.bits.vga) { // Power down VGA memory
REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
}
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;
if (res_pool->hubbub) {
(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
&res_pool->ref_clocks.dccg_ref_clock_inKhz);
(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
res_pool->ref_clocks.dccg_ref_clock_inKhz,
&res_pool->ref_clocks.dchub_ref_clock_inKhz);
} else { // Not all ASICs have DCCG sw component
res_pool->ref_clocks.dccg_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
res_pool->ref_clocks.dchub_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
}
} else
ASSERT_CRITICAL(false);
for (i = 0; i < dc->link_count; i++) { /* Power up AND update implementation according to the *requiredsignal(whichmaybedifferentfromthe *defaultsignalonconnector).
*/ struct dc_link *link = dc->links[i];
if (link->ep_type != DISPLAY_ENDPOINT_PHY) continue;
link->link_enc->funcs->hw_init(link->link_enc);
/* Check for enabled DIG to identify enabled display */ if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
link->link_status.link_active = true;
link->phy_state.symclk_state = SYMCLK_ON_TX_ON; if (link->link_enc->funcs->fec_is_active &&
link->link_enc->funcs->fec_is_active(link->link_enc))
link->fec_state = dc_link_fec_enabled;
}
}
/* enable_power_gating_plane before dsc_pg_control because *FORCEON=1withhwdefaultvalueonbootup,resumefroms3
*/ if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
/* we want to turn off all dp displays before doing detection */
dc->link_srv->blank_all_dp_displays(dc);
/* If taking control over from VBIOS, we may want to optimize our first *modeset,soweneedtoskippoweringdownpipesuntilweknowwhich *pipeswewanttouse. *Otherwise,iftakingcontrolisnotpossible,weneedtopower *everythingdown.
*/ if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { /* Disable boot optimizations means power down everything including PHY, DIG, *andOTG(i.e.thebootisnotoptimizedbecausewedoafullpowerdown).
*/ if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
dc->hwss.enable_accelerated_mode(dc, dc->current_state); else
hws->funcs.init_pipes(dc, dc->current_state);
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
dcn401_initialize_min_clocks(dc);
/* On HW init, allow idle optimizations after pipes have been turned off. * *IncertainD3cases(i.e.BOCO/BOMACO)it'spossiblethathardwarestate *isreset(i.e.notinidleatthetimehwinitiscalled),butsoftwarestate *stillhasidle_optimizations=true,sowemustdisableidleoptimizationsfirst *(i.e.setfalse),thenre-enable(settrue).
*/
dc_allow_idle_optimizations(dc, false);
dc_allow_idle_optimizations(dc, true);
}
/* In headless boot cases, DIG may be turned *onwhichcausesHW/SWdiscrepancies. *Toavoidthis,powerdownhardwareonboot *ifDIGisturnedonandseamlessbootnotenabled
*/ if (!dc->config.seamless_boot_edp_requested) { struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_link *edp_link;
dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num) { for (i = 0; i < edp_num; i++) {
edp_link = edp_links[i]; if (edp_link->link_enc->funcs->is_dig_enabled &&
edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
dc->hwss.edp_backlight_control &&
hws->funcs.power_down &&
dc->hwss.edp_power_control) {
dc->hwss.edp_backlight_control(edp_link, false);
hws->funcs.power_down(dc);
dc->hwss.edp_power_control(edp_link, false);
}
}
} else { for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i];
if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
hws->funcs.power_down) {
hws->funcs.power_down(dc); break;
}
}
}
}
for (i = 0; i < res_pool->audio_count; i++) { struct audio *audio = res_pool->audios[i];
audio->funcs->hw_init(audio);
}
for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i];
for (i = 0; i < dc->res_pool->pipe_count; i++) { if (abms[i] != NULL && abms[i]->funcs != NULL)
abms[i]->funcs->abm_init(abms[i], backlight, user_level);
}
/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
REG_WRITE(DIO_MEM_PWR_CTRL, 0);
if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */
REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
dcn401_setup_hpo_hw_control(hws, true);
if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
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);
if (dc->res_pool->hubbub->funcs->init_crb)
dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
// Get DMCUB capabilities if (dc->ctx->dmub_srv) {
dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
dc->debug.fams2_config.bits.enable &=
dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box)
|| res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) { /* update bounding box if FAMS2 disabled, or if dchub clk has changed */ if (dc->clk_mgr)
dc->res_pool->funcs->update_bw_bounding_box(dc,
dc->clk_mgr->bw_params);
}
}
}
if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode)
hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode);
switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) { case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB:
format = hubp_3dlut_fl_format_unorm_12msb_bitslice; break; case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB:
format = hubp_3dlut_fl_format_unorm_12lsb_bitslice; break; case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10:
format = hubp_3dlut_fl_format_float_fp1_5_10; break;
} if (hubp->funcs->hubp_program_3dlut_fl_format)
hubp->funcs->hubp_program_3dlut_fl_format(hubp, format); if (hubp->funcs->hubp_update_3dlut_fl_bias_scale &&
mpc->funcs->mcm.program_bias_scale) {
mpc->funcs->mcm.program_bias_scale(mpc,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale,
mpcc_id);
hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale);
}
//navi 4x has a bug and r and blue are swapped and need to be worked around here in //TODO: need to make a method for get_xbar per asic OR do the workaround in program_crossbar for 4x switch (mcm_luts.lut3d_data.gpu_mem_params.component_order) { case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA: default:
crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15;
crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47; break;
}
if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp,
crossbar_bit_slice_cr_r,
crossbar_bit_slice_y_g,
crossbar_bit_slice_cb_b);
if (mpc->funcs->mcm.program_lut_read_write_control)
mpc->funcs->mcm.program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, true, mpcc_id);
if (mpc->funcs->mcm.program_3dlut_size)
mpc->funcs->mcm.program_3dlut_size(mpc, width, mpcc_id);
if (mpc->funcs->update_3dlut_fast_load_select)
mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, hubp->inst);
// 3D if (mpc->funcs->program_3dlut) { if (plane_state->lut3d_func.state.bits.initialized == 1)
result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id); else
result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
}
return result;
}
bool dcn401_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, conststruct dc_stream_state *stream)
{ int mpcc_id = pipe_ctx->plane_res.hubp->inst; struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; conststruct pwl_params *params = NULL; bool ret = false;
/* program OGAM or 3DLUT only for the top pipe*/ if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) { /*program shaper and 3dlut in MPC*/
ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream); if (ret == false && mpc->funcs->set_output_gamma) { if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func.pwl; elseif (pipe_ctx->stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
cm3_helper_translate_curve_to_hw_format(
&stream->out_transfer_func,
&mpc->blender_params, false))
params = &mpc->blender_params; /* there are no ROM LUTs in OUTGAM */ if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
BREAK_TO_DEBUGGER();
}
}
if (mpc->funcs->set_output_gamma)
mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
/* if we are borrowing from hblank, h_addressable needs to be adjusted */ if (dc->debug.enable_hblank_borrow)
patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->hblank_borrow;
/* 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;
}
/* 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;
}
staticenum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
{ switch (link->link_enc->transmitter) { case TRANSMITTER_UNIPHY_A: return PHYD32CLKA; case TRANSMITTER_UNIPHY_B: return PHYD32CLKB; case TRANSMITTER_UNIPHY_C: return PHYD32CLKC; case TRANSMITTER_UNIPHY_D: return PHYD32CLKD; case TRANSMITTER_UNIPHY_E: return PHYD32CLKE; default: return PHYD32CLKA;
}
}
if (dc_is_tmds_signal(pipe_ctx->stream->signal))
dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div); else
*tmds_div = PIXEL_RATE_DIV_BY_1;
/* 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;
/* DCN4 moved cursor composition after Scaler, so in HW it is in *recoutspaceandforHWCursorpositionprogrammingneedto *translatetorecoutspace. * *CursorXandYpositionprogrammedintoHWcan'tbenegative, *infactitisX,YcoordinateshiftedfortheHWCursorHotspot *positionthatgoesintoHWXandYcoordinateswhileHWHotspot *XandYcoordinatesarelengthrelativetothecursortopleft *corner,hotspotmustbesmallerthanthecursorsize. * *DMs/DCinterfaceforCursorpositionisinstream->srcspace,and *DMssupposedtotransformCursorcoordinatestostream->srcspace, *thenhereweneedtotranslateCursorcoordinatestostream->dst *space,asnowinHW,Cursorcoordinatesareinperpiperecout *space,andforthegivenpipevalidcoordinatesareonlyinrange *from0,0-recoutwidth,recoutheightspace. *Ifcertainpipecombiningisinplace,needtofurtheradjustper *pipetomakesureeachpipeenablingcursoronitspartofthe *screen.
*/
x_pos = pipe_ctx->stream->dst.x + x_pos * pipe_ctx->stream->dst.width /
pipe_ctx->stream->src.width;
y_pos = pipe_ctx->stream->dst.y + y_pos * pipe_ctx->stream->dst.height /
pipe_ctx->stream->src.height;
/* If the cursor's source viewport is clipped then we need to *translatethecursortoappearinthecorrectpositionon *thescreen. * *Thistranslationisn'taffectedbyscalingsoitneedstobe *done*after*weadjustthepositionforthescalefactor. * *Thisisonlydonebyopt-infornowsincetherearestill *someusecasesliketileddisplaythatmightenablethe *cursoronbothstreamswhileexpectingdctoclipit.
*/ if (pos_cpy.translate_by_source) {
x_pos += pipe_ctx->plane_state->src_rect.x;
y_pos += pipe_ctx->plane_state->src_rect.y;
}
/* Adjust for ODM Combine *next/prev_odm_offsetistoaccountforscaledmodesthathaveunderscan
*/ if (odm_combine_on) {
prev_odm_pipe = pipe_ctx->prev_odm_pipe;
/* If the position on bottom MPC pipe is negative then we need to add to the hotspot and *adjustx_posonbottompipetomakecursorvisiblewhencrossingbetweenMPCslices.
*/ if (mpc_combine_on &&
pipe_ctx->top_pipe &&
(pipe_ctx == pipe_ctx->top_pipe->bottom_pipe)) {
staticbool dcn401_check_no_memory_request_for_cab(struct dc *dc)
{ int i;
/* First, check no-memory-request case */ for (i = 0; i < dc->current_state->stream_count; i++) { if ((dc->current_state->stream_status[i].plane_count) &&
(dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)) /* Fail eligibility on a visible stream */ returnfalse;
}
returntrue;
}
static uint32_t dcn401_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
{ int i;
uint8_t num_ways = 0;
uint32_t mall_ss_size_bytes = 0;
mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes; // TODO add additional logic for PSR active stream exclusion optimization // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes;
// Include cursor size for CAB allocation for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i];
if (!pipe->stream || !pipe->plane_state) continue;
// Convert number of cache lines required to number of ways if (dc->debug.force_mall_ss_num_ways > 0)
num_ways = dc->debug.force_mall_ss_num_ways; elseif (dc->res_pool->funcs->calculate_mall_ways_from_bytes)
num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, mall_ss_size_bytes); else
num_ways = 0;
return num_ways;
}
bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable)
{ union dmub_rb_cmd cmd;
uint8_t ways, i; int j; bool mall_ss_unsupported = false; struct dc_plane_state *plane = NULL;
if (!dc->ctx->dmub_srv || !dc->current_state) returnfalse;
for (i = 0; i < dc->current_state->stream_count; i++) { /* MALL SS messaging is not supported with PSR at this time */ if (dc->current_state->streams[i] != NULL &&
dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
DC_LOG_MALL("MALL SS not supported with PSR at this time\n"); returnfalse;
}
}
if (enable) { if (dcn401_check_no_memory_request_for_cab(dc)) { /* 1. Check no memory request case for CAB. *Ifnomemoryrequestcase,sendCAB_ACTIONNO_DCN_REQDMUBmessage
*/
DC_LOG_MALL("sending CAB action NO_DCN_REQ\n");
cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
} else { /* 2. Check if all surfaces can fit in CAB. *IfsurfacescanfitintoCAB,sendCAB_ACTION_ALLOWDMUBmessage *andconfigureHUBP'stofetchfromMALL
*/
ways = dcn401_calculate_cab_allocation(dc, dc->current_state);
/* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo, *orTMZsurface,don'ttrytoenterMALL.
*/ for (i = 0; i < dc->current_state->stream_count; i++) { for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
plane = dc->current_state->stream_status[i].plane_states[j];
/* check if any surfaces are updating address while using flip immediate and dcc */ while (pipe_ctx != NULL) { if (pipe_ctx->plane_state &&
pipe_ctx->plane_state->dcc.enable &&
pipe_ctx->plane_state->flip_immediate &&
pipe_ctx->plane_state->update_flags.bits.addr_update) {
is_wait_needed = true; break;
}
/* check next pipe */
pipe_ctx = pipe_ctx->bottom_pipe;
}
if (is_wait_needed && dc->debug.dcc_meta_propagation_delay_us > 0) {
udelay(dc->debug.dcc_meta_propagation_delay_us);
}
}
/* Any transition into P-State support should disable MCLK switching first to avoid hangs */ if (p_state_change_support) {
dc->optimized_required = true;
context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
}
if (dc->clk_mgr->dc_mode_softmax_enabled) if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
if (p_state_change_support != context->bw_ctx.bw.dcn.clk.p_state_change_support) { /* After disabling P-State, restore the original value to ensure we get the correct P-State
* on the next optimize. */
context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
}
}
void dcn401_optimize_bandwidth( struct dc *dc, struct dc_state *context)
{ int i; struct hubbub *hubbub = dc->res_pool->hubbub;
/* enable fams2 if needed */ if (dc->debug.fams2_config.bits.enable) {
dcn401_fams2_global_control_lock(dc, context, true);
dcn401_fams2_update_config(dc, context, true);
dcn401_fams2_global_control_lock(dc, context, false);
}
void dcn401_fams2_global_control_lock(struct dc *dc, struct dc_state *context, bool lock)
{ /* use always for now */ union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable) return;
if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) {
old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master,
&dc->current_state->res_ctx,
old_opp_heads);
} else { // DC cannot assume that the current state and the new state // share the same OTG pipe since this is not true when called // in the context of a commit stream not checked. Hence, set // old_otg_master to NULL to skip the DSC configuration.
old_otg_master = NULL;
}
if (otg_master->stream_res.dsc)
dcn32_update_dsc_on_stream(otg_master,
otg_master->stream->timing.flags.DSC); if (old_otg_master && old_otg_master->stream_res.dsc) { for (i = 0; i < old_opp_head_count; i++) {
old_pipe = old_opp_heads[i];
new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx]; if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc)
old_pipe->stream_res.dsc->funcs->dsc_disconnect(
old_pipe->stream_res.dsc);
}
}
}
void dcn401_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master)
{ struct pipe_ctx *opp_heads[MAX_PIPES]; int opp_inst[MAX_PIPES] = {0}; int opp_head_count; int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false); int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true); int i;
if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
hws->funcs.edp_backlight_control(link, true);
}
void dcn401_hardware_release(struct dc *dc)
{
dc_dmub_srv_fams2_update_config(dc, dc->current_state, false);
/* If pstate unsupported, or still supported *byfirmware,forceitsupportedbydcn
*/ if (dc->current_state) { if ((!dc->clk_mgr->clks.p_state_change_support ||
dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable) &&
dc->res_pool->hubbub->funcs->force_pstate_change_control)
dc->res_pool->hubbub->funcs->force_pstate_change_control(
dc->res_pool->hubbub, true, true);
if (lock) { for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
tg = pipe->stream_res.tg;
if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
!tg->funcs->is_tg_enabled(tg) ||
dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) continue;
dc->hwss.pipe_control_lock(dc, pipe, true);
}
} else { /* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/ for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
tg = pipe->stream_res.tg;
if (dc->scratch.pipes_to_unlock_first[i]) { struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
dc->hwss.pipe_control_lock(dc, pipe, false); /* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/
dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe);
}
}
/* Unlocking the rest of the pipes */ for (i = 0; i < dc->res_pool->pipe_count; i++) { if (dc->scratch.pipes_to_unlock_first[i]) continue;
void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
{ /* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that *HUBPwillproperlyfetch3DLUTcontentsafterunlock. * *ThisismeanttoworkaroundaknownHWissuewhereVREADYwillcancelthepending3DLUT_ENABLEsignalregardless *ofwhetherOTGlockiscurrentlybeingheldornot.
*/ struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL }; struct pipe_ctx *odm_pipe, *mpc_pipe; int i, wa_pipe_ct = 0;
if (wa_pipe_ct > 0) { if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true);
for (i = 0; i < wa_pipe_ct; ++i) { if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
}
pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status)
pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false);
for (i = 0; i < wa_pipe_ct; ++i) { if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
}
if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false);
} else {
pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
}
}
/* 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) {
/* TODO - convert symclk_ref_cnts for otg to a bit map to solve *thecasewherethesamesymclkissharedacrossmultipleotg *instances
*/ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
link->phy_state.symclk_ref_cnts.otg = 0; if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
link_hwss->disable_link_output(link,
&pipe_ctx->link_res, pipe_ctx->stream->signal);
link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
}
/* reset DTBCLK_P */ if (dc->res_pool->dccg->funcs->set_dtbclk_p_src)
dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst);
}
/* *Incaseofadanglingplane,settingthistoNULLunconditionally *causesfailuresduringresethwctxwhere,ifstreamisNULL, *itisexpectedthatthepipe_ctxpointerstopipesandplaneareNULL.
*/
pipe_ctx->stream = NULL;
pipe_ctx->top_pipe = NULL;
pipe_ctx->bottom_pipe = NULL;
pipe_ctx->next_odm_pipe = NULL;
pipe_ctx->prev_odm_pipe = NULL;
DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
}
void dcn401_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--) { struct pipe_ctx *pipe_ctx_old =
&dc->current_state->res_ctx.pipe_ctx[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (!pipe_ctx_old->stream) continue;
if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) continue;
if (hws->funcs.reset_back_end_for_pipe)
hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); if (hws->funcs.enable_stream_gating)
hws->funcs.enable_stream_gating(dc, pipe_ctx_old); if (old_clk)
old_clk->funcs->cs_power_down(old_clk);
}
}
}
/* 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)
dcn401_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
dc->hwss.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) { if (pipe->plane_state->triplebuffer_flips)
BREAK_TO_DEBUGGER();
/*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++)
dc->hwss.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)
dcn401_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);
}
}
}
void dcn401_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;
DC_LOGGER_INIT(dc->ctx->logger);
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))
dc->hwss.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);
dcn401_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) {
/* 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;
}
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.