1578 lines · c
1/* SPDX-License-Identifier: MIT */2/*3 * Copyright 2023 Advanced Micro Devices, Inc.4 *5 * Permission is hereby granted, free of charge, to any person obtaining a6 * copy of this software and associated documentation files (the "Software"),7 * to deal in the Software without restriction, including without limitation8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,9 * and/or sell copies of the Software, and to permit persons to whom the10 * Software is furnished to do so, subject to the following conditions:11 *12 * The above copyright notice and this permission notice shall be included in13 * all copies or substantial portions of the Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21 * OTHER DEALINGS IN THE SOFTWARE.22 *23 * Authors: AMD24 *25 */26 27#include "dm_services.h"28#include "dm_helpers.h"29#include "core_types.h"30#include "resource.h"31#include "dccg.h"32#include "dce/dce_hwseq.h"33#include "clk_mgr.h"34#include "reg_helper.h"35#include "abm.h"36#include "hubp.h"37#include "dchubbub.h"38#include "timing_generator.h"39#include "opp.h"40#include "ipp.h"41#include "mpc.h"42#include "mcif_wb.h"43#include "dc_dmub_srv.h"44#include "dcn35_hwseq.h"45#include "dcn35/dcn35_dccg.h"46#include "link_hwss.h"47#include "dpcd_defs.h"48#include "dce/dmub_outbox.h"49#include "link.h"50#include "dcn10/dcn10_hwseq.h"51#include "inc/link_enc_cfg.h"52#include "dcn30/dcn30_vpg.h"53#include "dce/dce_i2c_hw.h"54#include "dsc.h"55#include "dcn20/dcn20_optc.h"56#include "dcn30/dcn30_cm_common.h"57#include "dcn31/dcn31_hwseq.h"58#include "dcn20/dcn20_hwseq.h"59#include "dc_state_priv.h"60 61#define DC_LOGGER_INIT(logger) \62 struct dal_logger *dc_logger = logger63 64#define CTX \65 hws->ctx66#define REG(reg)\67 hws->regs->reg68#define DC_LOGGER \69 dc_logger70 71 72#undef FN73#define FN(reg_name, field_name) \74 hws->shifts->field_name, hws->masks->field_name75#if 076static void enable_memory_low_power(struct dc *dc)77{78 struct dce_hwseq *hws = dc->hwseq;79 int i;80 81 if (dc->debug.enable_mem_low_power.bits.dmcu) {82 // Force ERAM to shutdown if DMCU is not enabled83 if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {84 REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);85 }86 }87 /*dcn35 has default MEM_PWR enabled, make sure wake them up*/88 // Set default OPTC memory power states89 if (dc->debug.enable_mem_low_power.bits.optc) {90 // Shutdown when unassigned and light sleep in VBLANK91 REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);92 }93 94 if (dc->debug.enable_mem_low_power.bits.vga) {95 // Power down VGA memory96 REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);97 }98 99 if (dc->debug.enable_mem_low_power.bits.mpc &&100 dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode)101 dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc);102 103 if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) {104 // Power down VPGs105 for (i = 0; i < dc->res_pool->stream_enc_count; i++)106 dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg);107#if defined(CONFIG_DRM_AMD_DC_DP2_0)108 for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++)109 dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg);110#endif111 }112 113}114#endif115 116void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable)117{118 REG_UPDATE_3(DMU_CLK_CNTL,119 RBBMIF_FGCG_REP_DIS, !enable,120 IHC_FGCG_REP_DIS, !enable,121 LONO_FGCG_REP_DIS, !enable122 );123}124 125void dcn35_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)126{127 REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable);128}129 130void dcn35_init_hw(struct dc *dc)131{132 struct abm **abms = dc->res_pool->multiple_abms;133 struct dce_hwseq *hws = dc->hwseq;134 struct dc_bios *dcb = dc->ctx->dc_bios;135 struct resource_pool *res_pool = dc->res_pool;136 uint32_t backlight = MAX_BACKLIGHT_LEVEL;137 uint32_t user_level = MAX_BACKLIGHT_LEVEL;138 int i;139 140 if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)141 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);142 143 //dcn35_set_dmu_fgcg(hws, dc->debug.enable_fine_grain_clock_gating.bits.dmu);144 145 if (!dcb->funcs->is_accelerated_mode(dcb)) {146 /*this calls into dmubfw to do the init*/147 hws->funcs.bios_golden_init(dc);148 }149 150 // Initialize the dccg151 if (res_pool->dccg->funcs->dccg_init)152 res_pool->dccg->funcs->dccg_init(res_pool->dccg);153 154 //enable_memory_low_power(dc);155 156 if (dc->ctx->dc_bios->fw_info_valid) {157 res_pool->ref_clocks.xtalin_clock_inKhz =158 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;159 160 if (res_pool->hubbub) {161 162 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,163 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,164 &res_pool->ref_clocks.dccg_ref_clock_inKhz);165 166 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,167 res_pool->ref_clocks.dccg_ref_clock_inKhz,168 &res_pool->ref_clocks.dchub_ref_clock_inKhz);169 } else {170 // Not all ASICs have DCCG sw component171 res_pool->ref_clocks.dccg_ref_clock_inKhz =172 res_pool->ref_clocks.xtalin_clock_inKhz;173 res_pool->ref_clocks.dchub_ref_clock_inKhz =174 res_pool->ref_clocks.xtalin_clock_inKhz;175 }176 } else177 ASSERT_CRITICAL(false);178 179 for (i = 0; i < dc->link_count; i++) {180 /* Power up AND update implementation according to the181 * required signal (which may be different from the182 * default signal on connector).183 */184 struct dc_link *link = dc->links[i];185 186 if (link->ep_type != DISPLAY_ENDPOINT_PHY)187 continue;188 189 link->link_enc->funcs->hw_init(link->link_enc);190 191 /* Check for enabled DIG to identify enabled display */192 if (link->link_enc->funcs->is_dig_enabled &&193 link->link_enc->funcs->is_dig_enabled(link->link_enc)) {194 link->link_status.link_active = true;195 if (link->link_enc->funcs->fec_is_active &&196 link->link_enc->funcs->fec_is_active(link->link_enc))197 link->fec_state = dc_link_fec_enabled;198 }199 }200 201 /* we want to turn off all dp displays before doing detection */202 dc->link_srv->blank_all_dp_displays(dc);203/*204 if (hws->funcs.enable_power_gating_plane)205 hws->funcs.enable_power_gating_plane(dc->hwseq, true);206*/207 if (res_pool->hubbub && res_pool->hubbub->funcs->dchubbub_init)208 res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub);209 /* If taking control over from VBIOS, we may want to optimize our first210 * mode set, so we need to skip powering down pipes until we know which211 * pipes we want to use.212 * Otherwise, if taking control is not possible, we need to power213 * everything down.214 */215 if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {216 217 // we want to turn off edp displays if odm is enabled and no seamless boot218 if (!dc->caps.seamless_odm) {219 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {220 struct timing_generator *tg = dc->res_pool->timing_generators[i];221 uint32_t num_opps, opp_id_src0, opp_id_src1;222 223 num_opps = 1;224 if (tg) {225 if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) {226 tg->funcs->get_optc_source(tg, &num_opps,227 &opp_id_src0, &opp_id_src1);228 }229 }230 231 if (num_opps > 1) {232 dc->link_srv->blank_all_edp_displays(dc);233 break;234 }235 }236 }237 238 hws->funcs.init_pipes(dc, dc->current_state);239 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)240 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,241 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);242 }243 if (res_pool->dccg->funcs->dccg_root_gate_disable_control) {244 for (i = 0; i < res_pool->pipe_count; i++)245 res_pool->dccg->funcs->dccg_root_gate_disable_control(res_pool->dccg, i, 0);246 }247 248 for (i = 0; i < res_pool->audio_count; i++) {249 struct audio *audio = res_pool->audios[i];250 251 audio->funcs->hw_init(audio);252 }253 254 for (i = 0; i < dc->link_count; i++) {255 struct dc_link *link = dc->links[i];256 257 if (link->panel_cntl) {258 backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);259 user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;260 }261 }262 if (dc->ctx->dmub_srv) {263 for (i = 0; i < dc->res_pool->pipe_count; i++) {264 if (abms[i] != NULL && abms[i]->funcs != NULL)265 abms[i]->funcs->abm_init(abms[i], backlight, user_level);266 }267 }268 269 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/270 REG_WRITE(DIO_MEM_PWR_CTRL, 0);271 272 // Set i2c to light sleep until engine is setup273 if (dc->debug.enable_mem_low_power.bits.i2c)274 REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0);275 276 if (hws->funcs.setup_hpo_hw_control)277 hws->funcs.setup_hpo_hw_control(hws, false);278 279 if (!dc->debug.disable_clock_gate) {280 /* enable all DCN clock gating */281 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);282 }283 284 if (dc->debug.disable_mem_low_power) {285 REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 1);286 }287 if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)288 dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);289 290 if (dc->clk_mgr && dc->clk_mgr->funcs->notify_wm_ranges)291 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);292 293 if (dc->clk_mgr && dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)294 dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);295 296 297 298 if (dc->res_pool->hubbub->funcs->force_pstate_change_control)299 dc->res_pool->hubbub->funcs->force_pstate_change_control(300 dc->res_pool->hubbub, false, false);301 302 if (dc->res_pool->hubbub->funcs->init_crb)303 dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);304 305 if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)306 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);307 // Get DMCUB capabilities308 if (dc->ctx->dmub_srv) {309 dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);310 dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;311 dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;312 }313 314 if (dc->res_pool->pg_cntl) {315 if (dc->res_pool->pg_cntl->funcs->init_pg_status)316 dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl);317 }318}319 320static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)321{322 struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;323 struct dc_stream_state *stream = pipe_ctx->stream;324 struct pipe_ctx *odm_pipe;325 int opp_cnt = 1;326 327 DC_LOGGER_INIT(stream->ctx->logger);328 329 ASSERT(dsc);330 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)331 opp_cnt++;332 333 if (enable) {334 struct dsc_config dsc_cfg;335 struct dsc_optc_config dsc_optc_cfg = {0};336 enum optc_dsc_mode optc_dsc_mode;337 struct dcn_dsc_state dsc_state = {0};338 339 if (!dsc) {340 DC_LOG_DSC("DSC is NULL for tg instance %d:", pipe_ctx->stream_res.tg->inst);341 return;342 }343 344 if (dsc->funcs->dsc_read_state) {345 dsc->funcs->dsc_read_state(dsc, &dsc_state);346 if (!dsc_state.dsc_fw_en) {347 DC_LOG_DSC("DSC has been disabled for tg instance %d:", pipe_ctx->stream_res.tg->inst);348 return;349 }350 }351 /* Enable DSC hw block */352 dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;353 dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;354 dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;355 dsc_cfg.color_depth = stream->timing.display_color_depth;356 dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;357 dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;358 ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);359 dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;360 361 dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);362 dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);363 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {364 struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;365 366 ASSERT(odm_dsc);367 odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);368 odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);369 }370 dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;371 dsc_cfg.pic_width *= opp_cnt;372 373 optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;374 375 /* Enable DSC in OPTC */376 DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);377 pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,378 optc_dsc_mode,379 dsc_optc_cfg.bytes_per_pixel,380 dsc_optc_cfg.slice_width);381 } else {382 /* disable DSC in OPTC */383 pipe_ctx->stream_res.tg->funcs->set_dsc_config(384 pipe_ctx->stream_res.tg,385 OPTC_DSC_DISABLED, 0, 0);386 387 /* disable DSC block */388 dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);389 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {390 ASSERT(odm_pipe->stream_res.dsc);391 odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);392 }393 }394}395 396// Given any pipe_ctx, return the total ODM combine factor, and optionally return397// the OPPids which are used398static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances)399{400 unsigned int opp_count = 1;401 struct pipe_ctx *odm_pipe;402 403 // First get to the top pipe404 for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe)405 ;406 407 // First pipe is always used408 if (opp_instances)409 opp_instances[0] = odm_pipe->stream_res.opp->inst;410 411 // Find and count odm pipes, if any412 for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {413 if (opp_instances)414 opp_instances[opp_count] = odm_pipe->stream_res.opp->inst;415 opp_count++;416 }417 418 return opp_count;419}420 421void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)422{423 struct pipe_ctx *odm_pipe;424 int opp_cnt = 0;425 int opp_inst[MAX_PIPES] = {0};426 int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);427 int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);428 429 opp_cnt = get_odm_config(pipe_ctx, opp_inst);430 431 if (opp_cnt > 1)432 pipe_ctx->stream_res.tg->funcs->set_odm_combine(433 pipe_ctx->stream_res.tg,434 opp_inst, opp_cnt,435 odm_slice_width, last_odm_slice_width);436 else437 pipe_ctx->stream_res.tg->funcs->set_odm_bypass(438 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);439 440 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {441 odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(442 odm_pipe->stream_res.opp,443 true);444 }445 446 if (pipe_ctx->stream_res.dsc) {447 struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];448 449 update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC);450 451 /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */452 if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe &&453 current_pipe_ctx->next_odm_pipe->stream_res.dsc) {454 struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc;455 /* disconnect DSC block from stream */456 dsc->funcs->dsc_disconnect(dsc);457 }458 }459}460 461void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on)462{463 if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp)464 return;465 466 if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) {467 hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control(468 hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on);469 }470}471 472void dcn35_dpstream_root_clock_control(struct dce_hwseq *hws, unsigned int dp_hpo_inst, bool clock_on)473{474 if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpstream)475 return;476 477 if (hws->ctx->dc->res_pool->dccg->funcs->set_dpstreamclk_root_clock_gating) {478 hws->ctx->dc->res_pool->dccg->funcs->set_dpstreamclk_root_clock_gating(479 hws->ctx->dc->res_pool->dccg, dp_hpo_inst, clock_on);480 }481}482 483void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_inst, bool clock_on)484{485 if (!hws->ctx->dc->debug.root_clock_optimization.bits.physymclk)486 return;487 488 if (hws->ctx->dc->res_pool->dccg->funcs->set_physymclk_root_clock_gating) {489 hws->ctx->dc->res_pool->dccg->funcs->set_physymclk_root_clock_gating(490 hws->ctx->dc->res_pool->dccg, phy_inst, clock_on);491 }492}493 494void dcn35_dsc_pg_control(495 struct dce_hwseq *hws,496 unsigned int dsc_inst,497 bool power_on)498{499 uint32_t power_gate = power_on ? 0 : 1;500 uint32_t pwr_status = power_on ? 0 : 2;501 uint32_t org_ip_request_cntl = 0;502 503 if (hws->ctx->dc->debug.disable_dsc_power_gate)504 return;505 if (hws->ctx->dc->debug.ignore_pg)506 return;507 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);508 if (org_ip_request_cntl == 0)509 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);510 511 switch (dsc_inst) {512 case 0: /* DSC0 */513 REG_UPDATE(DOMAIN16_PG_CONFIG,514 DOMAIN_POWER_GATE, power_gate);515 516 REG_WAIT(DOMAIN16_PG_STATUS,517 DOMAIN_PGFSM_PWR_STATUS, pwr_status,518 1, 1000);519 break;520 case 1: /* DSC1 */521 REG_UPDATE(DOMAIN17_PG_CONFIG,522 DOMAIN_POWER_GATE, power_gate);523 524 REG_WAIT(DOMAIN17_PG_STATUS,525 DOMAIN_PGFSM_PWR_STATUS, pwr_status,526 1, 1000);527 break;528 case 2: /* DSC2 */529 REG_UPDATE(DOMAIN18_PG_CONFIG,530 DOMAIN_POWER_GATE, power_gate);531 532 REG_WAIT(DOMAIN18_PG_STATUS,533 DOMAIN_PGFSM_PWR_STATUS, pwr_status,534 1, 1000);535 break;536 case 3: /* DSC3 */537 REG_UPDATE(DOMAIN19_PG_CONFIG,538 DOMAIN_POWER_GATE, power_gate);539 540 REG_WAIT(DOMAIN19_PG_STATUS,541 DOMAIN_PGFSM_PWR_STATUS, pwr_status,542 1, 1000);543 break;544 default:545 BREAK_TO_DEBUGGER();546 break;547 }548 549 if (org_ip_request_cntl == 0)550 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);551}552 553void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable)554{555 bool force_on = true; /* disable power gating */556 uint32_t org_ip_request_cntl = 0;557 558 if (hws->ctx->dc->debug.disable_hubp_power_gate)559 return;560 if (hws->ctx->dc->debug.ignore_pg)561 return;562 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);563 if (org_ip_request_cntl == 0)564 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);565 /* DCHUBP0/1/2/3/4/5 */566 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);567 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);568 /* DPP0/1/2/3/4/5 */569 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);570 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);571 572 force_on = true; /* disable power gating */573 if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)574 force_on = false;575 576 /* DCS0/1/2/3/4 */577 REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);578 REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);579 REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);580 REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);581 582 583}584 585/* In headless boot cases, DIG may be turned586 * on which causes HW/SW discrepancies.587 * To avoid this, power down hardware on boot588 * if DIG is turned on589 */590void dcn35_power_down_on_boot(struct dc *dc)591{592 struct dc_link *edp_links[MAX_NUM_EDP];593 struct dc_link *edp_link = NULL;594 int edp_num;595 int i = 0;596 597 dc_get_edp_links(dc, edp_links, &edp_num);598 if (edp_num)599 edp_link = edp_links[0];600 601 if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&602 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&603 dc->hwseq->funcs.edp_backlight_control &&604 dc->hwseq->funcs.power_down &&605 dc->hwss.edp_power_control) {606 dc->hwseq->funcs.edp_backlight_control(edp_link, false);607 dc->hwseq->funcs.power_down(dc);608 dc->hwss.edp_power_control(edp_link, false);609 } else {610 for (i = 0; i < dc->link_count; i++) {611 struct dc_link *link = dc->links[i];612 613 if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&614 link->link_enc->funcs->is_dig_enabled(link->link_enc) &&615 dc->hwseq->funcs.power_down) {616 dc->hwseq->funcs.power_down(dc);617 break;618 }619 620 }621 }622 623 /*624 * Call update_clocks with empty context625 * to send DISPLAY_OFF626 * Otherwise DISPLAY_OFF may not be asserted627 */628 if (dc->clk_mgr->funcs->set_low_power_state)629 dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);630 631 if (dc->clk_mgr->clks.pwr_state == DCN_PWR_STATE_LOW_POWER)632 dc_allow_idle_optimizations(dc, true);633}634 635bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)636{637 if (dc->debug.dmcub_emulation)638 return true;639 640 if (enable) {641 uint32_t num_active_edp = 0;642 int i;643 644 for (i = 0; i < dc->current_state->stream_count; ++i) {645 struct dc_stream_state *stream = dc->current_state->streams[i];646 struct dc_link *link = stream->link;647 bool is_psr = link && !link->panel_config.psr.disable_psr &&648 (link->psr_settings.psr_version == DC_PSR_VERSION_1 ||649 link->psr_settings.psr_version == DC_PSR_VERSION_SU_1);650 bool is_replay = link && link->replay_settings.replay_feature_enabled;651 652 /* Ignore streams that disabled. */653 if (stream->dpms_off)654 continue;655 656 /* Active external displays block idle optimizations. */657 if (!dc_is_embedded_signal(stream->signal))658 return false;659 660 /* If not PWRSEQ0 can't enter idle optimizations */661 if (link && link->link_index != 0)662 return false;663 664 /* Check for panel power features required for idle optimizations. */665 if (!is_psr && !is_replay)666 return false;667 668 num_active_edp += 1;669 }670 671 /* If more than one active eDP then disallow. */672 if (num_active_edp > 1)673 return false;674 }675 676 // TODO: review other cases when idle optimization is allowed677 dc_dmub_srv_apply_idle_power_optimizations(dc, enable);678 679 return true;680}681 682void dcn35_z10_restore(const struct dc *dc)683{684 if (dc->debug.disable_z10)685 return;686 687 dc_dmub_srv_apply_idle_power_optimizations(dc, false);688 689 dcn31_z10_restore(dc);690}691 692void dcn35_init_pipes(struct dc *dc, struct dc_state *context)693{694 int i;695 struct dce_hwseq *hws = dc->hwseq;696 struct hubbub *hubbub = dc->res_pool->hubbub;697 struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;698 bool can_apply_seamless_boot = false;699 bool tg_enabled[MAX_PIPES] = {false};700 701 for (i = 0; i < context->stream_count; i++) {702 if (context->streams[i]->apply_seamless_boot_optimization) {703 can_apply_seamless_boot = true;704 break;705 }706 }707 708 for (i = 0; i < dc->res_pool->pipe_count; i++) {709 struct timing_generator *tg = dc->res_pool->timing_generators[i];710 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];711 712 /* There is assumption that pipe_ctx is not mapping irregularly713 * to non-preferred front end. If pipe_ctx->stream is not NULL,714 * we will use the pipe, so don't disable715 */716 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)717 continue;718 719 /* Blank controller using driver code instead of720 * command table.721 */722 if (tg->funcs->is_tg_enabled(tg)) {723 if (hws->funcs.init_blank != NULL) {724 hws->funcs.init_blank(dc, tg);725 tg->funcs->lock(tg);726 } else {727 tg->funcs->lock(tg);728 tg->funcs->set_blank(tg, true);729 hwss_wait_for_blank_complete(tg);730 }731 }732 }733 734 /* Reset det size */735 for (i = 0; i < dc->res_pool->pipe_count; i++) {736 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];737 struct hubp *hubp = dc->res_pool->hubps[i];738 739 /* Do not need to reset for seamless boot */740 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)741 continue;742 743 if (hubbub && hubp) {744 if (hubbub->funcs->program_det_size)745 hubbub->funcs->program_det_size(hubbub, hubp->inst, 0);746 if (hubbub->funcs->program_det_segments)747 hubbub->funcs->program_det_segments(hubbub, hubp->inst, 0);748 }749 }750 751 /* num_opp will be equal to number of mpcc */752 for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {753 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];754 755 /* Cannot reset the MPC mux if seamless boot */756 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)757 continue;758 759 dc->res_pool->mpc->funcs->mpc_init_single_inst(760 dc->res_pool->mpc, i);761 }762 763 for (i = 0; i < dc->res_pool->pipe_count; i++) {764 struct timing_generator *tg = dc->res_pool->timing_generators[i];765 struct hubp *hubp = dc->res_pool->hubps[i];766 struct dpp *dpp = dc->res_pool->dpps[i];767 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];768 769 /* There is assumption that pipe_ctx is not mapping irregularly770 * to non-preferred front end. If pipe_ctx->stream is not NULL,771 * we will use the pipe, so don't disable772 */773 if (can_apply_seamless_boot &&774 pipe_ctx->stream != NULL &&775 pipe_ctx->stream_res.tg->funcs->is_tg_enabled(776 pipe_ctx->stream_res.tg)) {777 // Enable double buffering for OTG_BLANK no matter if778 // seamless boot is enabled or not to suppress global sync779 // signals when OTG blanked. This is to prevent pipe from780 // requesting data while in PSR.781 tg->funcs->tg_init(tg);782 hubp->power_gated = true;783 tg_enabled[i] = true;784 continue;785 }786 787 /* Disable on the current state so the new one isn't cleared. */788 pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];789 790 dpp->funcs->dpp_reset(dpp);791 792 pipe_ctx->stream_res.tg = tg;793 pipe_ctx->pipe_idx = i;794 795 pipe_ctx->plane_res.hubp = hubp;796 pipe_ctx->plane_res.dpp = dpp;797 pipe_ctx->plane_res.mpcc_inst = dpp->inst;798 hubp->mpcc_id = dpp->inst;799 hubp->opp_id = OPP_ID_INVALID;800 hubp->power_gated = false;801 802 dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;803 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;804 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;805 pipe_ctx->stream_res.opp = dc->res_pool->opps[i];806 807 hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);808 809 if (tg->funcs->is_tg_enabled(tg))810 tg->funcs->unlock(tg);811 812 dc->hwss.disable_plane(dc, context, pipe_ctx);813 814 pipe_ctx->stream_res.tg = NULL;815 pipe_ctx->plane_res.hubp = NULL;816 817 if (tg->funcs->is_tg_enabled(tg)) {818 if (tg->funcs->init_odm)819 tg->funcs->init_odm(tg);820 }821 822 tg->funcs->tg_init(tg);823 }824 825 /* Clean up MPC tree */826 for (i = 0; i < dc->res_pool->pipe_count; i++) {827 if (tg_enabled[i]) {828 if (dc->res_pool->opps[i]->mpc_tree_params.opp_list) {829 if (dc->res_pool->opps[i]->mpc_tree_params.opp_list->mpcc_bot) {830 int bot_id = dc->res_pool->opps[i]->mpc_tree_params.opp_list->mpcc_bot->mpcc_id;831 832 if ((bot_id < MAX_MPCC) && (bot_id < MAX_PIPES) && (!tg_enabled[bot_id]))833 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;834 }835 }836 }837 }838 839 if (pg_cntl != NULL) {840 if (pg_cntl->funcs->dsc_pg_control != NULL) {841 uint32_t num_opps = 0;842 uint32_t opp_id_src0 = OPP_ID_INVALID;843 uint32_t opp_id_src1 = OPP_ID_INVALID;844 845 // Step 1: To find out which OPTC is running & OPTC DSC is ON846 // We can't use res_pool->res_cap->num_timing_generator to check847 // Because it records display pipes default setting built in driver,848 // not display pipes of the current chip.849 // Some ASICs would be fused display pipes less than the default setting.850 // In dcnxx_resource_construct function, driver would obatin real information.851 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {852 uint32_t optc_dsc_state = 0;853 struct timing_generator *tg = dc->res_pool->timing_generators[i];854 855 if (tg->funcs->is_tg_enabled(tg)) {856 if (tg->funcs->get_dsc_status)857 tg->funcs->get_dsc_status(tg, &optc_dsc_state);858 // Only one OPTC with DSC is ON, so if we got one result,859 // we would exit this block. non-zero value is DSC enabled860 if (optc_dsc_state != 0) {861 tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);862 break;863 }864 }865 }866 867 // Step 2: To power down DSC but skip DSC of running OPTC868 for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {869 struct dcn_dsc_state s = {0};870 871 dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s);872 873 if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) &&874 s.dsc_clock_en && s.dsc_fw_en)875 continue;876 877 pg_cntl->funcs->dsc_pg_control(pg_cntl, dc->res_pool->dscs[i]->inst, false);878 }879 }880 }881}882 883void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,884 struct dc_state *context)885{886 /* enable DCFCLK current DCHUB */887 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);888 889 /* initialize HUBP on power up */890 pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);891 892 /* make sure OPP_PIPE_CLOCK_EN = 1 */893 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(894 pipe_ctx->stream_res.opp,895 true);896 /*to do: insert PG here*/897 if (dc->vm_pa_config.valid) {898 struct vm_system_aperture_param apt;899 900 apt.sys_default.quad_part = 0;901 902 apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;903 apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;904 905 // Program system aperture settings906 pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);907 }908 909 if (!pipe_ctx->top_pipe910 && pipe_ctx->plane_state911 && pipe_ctx->plane_state->flip_int_enabled912 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)913 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);914}915 916/* disable HW used by plane.917 * note: cannot disable until disconnect is complete918 */919void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)920{921 struct hubp *hubp = pipe_ctx->plane_res.hubp;922 struct dpp *dpp = pipe_ctx->plane_res.dpp;923 924 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);925 926 /* In flip immediate with pipe splitting case GSL is used for927 * synchronization so we must disable it when the plane is disabled.928 */929 if (pipe_ctx->stream_res.gsl_group != 0)930 dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);931/*932 if (hubp->funcs->hubp_update_mall_sel)933 hubp->funcs->hubp_update_mall_sel(hubp, 0, false);934*/935 dc->hwss.set_flip_control_gsl(pipe_ctx, false);936 937 hubp->funcs->hubp_clk_cntl(hubp, false);938 939 dpp->funcs->dpp_dppclk_control(dpp, false, false);940/*to do, need to support both case*/941 hubp->power_gated = true;942 943 dpp->funcs->dpp_reset(dpp);944 945 pipe_ctx->stream = NULL;946 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));947 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));948 pipe_ctx->top_pipe = NULL;949 pipe_ctx->bottom_pipe = NULL;950 pipe_ctx->plane_state = NULL;951}952 953void dcn35_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx)954{955 struct dce_hwseq *hws = dc->hwseq;956 bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM;957 struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;958 959 DC_LOGGER_INIT(dc->ctx->logger);960 961 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)962 return;963 964 if (hws->funcs.plane_atomic_disable)965 hws->funcs.plane_atomic_disable(dc, pipe_ctx);966 967 /* Turn back off the phantom OTG after the phantom plane is fully disabled968 */969 if (is_phantom)970 if (tg && tg->funcs->disable_phantom_crtc)971 tg->funcs->disable_phantom_crtc(tg);972 973 DC_LOG_DC("Power down front end %d\n",974 pipe_ctx->pipe_idx);975}976 977void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,978 struct pg_block_update *update_state)979{980 bool hpo_frl_stream_enc_acquired = false;981 bool hpo_dp_stream_enc_acquired = false;982 int i = 0, j = 0;983 int edp_num = 0;984 struct dc_link *edp_links[MAX_NUM_EDP] = { NULL };985 986 memset(update_state, 0, sizeof(struct pg_block_update));987 988 for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {989 if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&990 dc->res_pool->hpo_dp_stream_enc[i]) {991 hpo_dp_stream_enc_acquired = true;992 break;993 }994 }995 996 if (!hpo_frl_stream_enc_acquired && !hpo_dp_stream_enc_acquired)997 update_state->pg_res_update[PG_HPO] = true;998 999 update_state->pg_res_update[PG_DWB] = true;1000 1001 for (i = 0; i < dc->res_pool->pipe_count; i++) {1002 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];1003 1004 for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++)1005 update_state->pg_pipe_res_update[j][i] = true;1006 1007 if (!pipe_ctx)1008 continue;1009 1010 if (pipe_ctx->plane_res.hubp)1011 update_state->pg_pipe_res_update[PG_HUBP][pipe_ctx->plane_res.hubp->inst] = false;1012 1013 if (pipe_ctx->plane_res.dpp && pipe_ctx->plane_res.hubp)1014 update_state->pg_pipe_res_update[PG_DPP][pipe_ctx->plane_res.hubp->inst] = false;1015 1016 if (pipe_ctx->plane_res.dpp || pipe_ctx->stream_res.opp)1017 update_state->pg_pipe_res_update[PG_MPCC][pipe_ctx->plane_res.mpcc_inst] = false;1018 1019 if (pipe_ctx->stream_res.dsc)1020 update_state->pg_pipe_res_update[PG_DSC][pipe_ctx->stream_res.dsc->inst] = false;1021 1022 if (pipe_ctx->stream_res.opp)1023 update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false;1024 1025 if (pipe_ctx->stream_res.hpo_dp_stream_enc)1026 update_state->pg_pipe_res_update[PG_DPSTREAM][pipe_ctx->stream_res.hpo_dp_stream_enc->inst] = false;1027 }1028 1029 for (i = 0; i < dc->link_count; i++) {1030 update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;1031 if (dc->links[i]->type != dc_connection_none)1032 update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = false;1033 }1034 1035 /*domain24 controls all the otg, mpc, opp, as long as one otg is still up, avoid enabling OTG PG*/1036 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {1037 struct timing_generator *tg = dc->res_pool->timing_generators[i];1038 if (tg && tg->funcs->is_tg_enabled(tg)) {1039 update_state->pg_pipe_res_update[PG_OPTC][i] = false;1040 break;1041 }1042 }1043 1044 dc_get_edp_links(dc, edp_links, &edp_num);1045 if (edp_num == 0 ||1046 ((!edp_links[0] || !edp_links[0]->edp_sink_present) &&1047 (!edp_links[1] || !edp_links[1]->edp_sink_present))) {1048 /*eDP not exist on this config, keep Domain24 power on, for S0i3, this will be handled in dmubfw*/1049 update_state->pg_pipe_res_update[PG_OPTC][0] = false;1050 }1051 1052 if (dc->caps.sequential_ono) {1053 for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {1054 if (!update_state->pg_pipe_res_update[PG_HUBP][i] &&1055 !update_state->pg_pipe_res_update[PG_DPP][i]) {1056 for (j = i - 1; j >= 0; j--) {1057 update_state->pg_pipe_res_update[PG_HUBP][j] = false;1058 update_state->pg_pipe_res_update[PG_DPP][j] = false;1059 }1060 1061 break;1062 }1063 }1064 }1065}1066 1067void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,1068 struct pg_block_update *update_state)1069{1070 bool hpo_frl_stream_enc_acquired = false;1071 bool hpo_dp_stream_enc_acquired = false;1072 int i = 0, j = 0;1073 1074 memset(update_state, 0, sizeof(struct pg_block_update));1075 1076 for (i = 0; i < dc->res_pool->pipe_count; i++) {1077 struct pipe_ctx *cur_pipe = &dc->current_state->res_ctx.pipe_ctx[i];1078 struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];1079 1080 if (cur_pipe == NULL || new_pipe == NULL)1081 continue;1082 1083 if ((!cur_pipe->plane_state && new_pipe->plane_state) ||1084 (!cur_pipe->stream && new_pipe->stream) ||1085 (cur_pipe->stream != new_pipe->stream && new_pipe->stream)) {1086 // New pipe addition1087 for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) {1088 if (j == PG_HUBP && new_pipe->plane_res.hubp)1089 update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true;1090 1091 if (j == PG_DPP && new_pipe->plane_res.dpp)1092 update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true;1093 1094 if (j == PG_MPCC && new_pipe->plane_res.dpp)1095 update_state->pg_pipe_res_update[j][new_pipe->plane_res.mpcc_inst] = true;1096 1097 if (j == PG_DSC && new_pipe->stream_res.dsc)1098 update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true;1099 1100 if (j == PG_OPP && new_pipe->stream_res.opp)1101 update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true;1102 1103 if (j == PG_OPTC && new_pipe->stream_res.tg)1104 update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true;1105 1106 if (j == PG_DPSTREAM && new_pipe->stream_res.hpo_dp_stream_enc)1107 update_state->pg_pipe_res_update[j][new_pipe->stream_res.hpo_dp_stream_enc->inst] = true;1108 }1109 } else if (cur_pipe->plane_state == new_pipe->plane_state ||1110 cur_pipe == new_pipe) {1111 //unchanged pipes1112 for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) {1113 if (j == PG_HUBP &&1114 cur_pipe->plane_res.hubp != new_pipe->plane_res.hubp &&1115 new_pipe->plane_res.hubp)1116 update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true;1117 1118 if (j == PG_DPP &&1119 cur_pipe->plane_res.dpp != new_pipe->plane_res.dpp &&1120 new_pipe->plane_res.dpp)1121 update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true;1122 1123 if (j == PG_OPP &&1124 cur_pipe->stream_res.opp != new_pipe->stream_res.opp &&1125 new_pipe->stream_res.opp)1126 update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true;1127 1128 if (j == PG_DSC &&1129 cur_pipe->stream_res.dsc != new_pipe->stream_res.dsc &&1130 new_pipe->stream_res.dsc)1131 update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true;1132 1133 if (j == PG_OPTC &&1134 cur_pipe->stream_res.tg != new_pipe->stream_res.tg &&1135 new_pipe->stream_res.tg)1136 update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true;1137 1138 if (j == PG_DPSTREAM &&1139 cur_pipe->stream_res.hpo_dp_stream_enc != new_pipe->stream_res.hpo_dp_stream_enc &&1140 new_pipe->stream_res.hpo_dp_stream_enc)1141 update_state->pg_pipe_res_update[j][new_pipe->stream_res.hpo_dp_stream_enc->inst] = true;1142 }1143 }1144 }1145 1146 for (i = 0; i < dc->link_count; i++)1147 if (dc->links[i]->type != dc_connection_none)1148 update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;1149 1150 for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {1151 if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&1152 dc->res_pool->hpo_dp_stream_enc[i]) {1153 hpo_dp_stream_enc_acquired = true;1154 break;1155 }1156 }1157 1158 if (hpo_frl_stream_enc_acquired || hpo_dp_stream_enc_acquired)1159 update_state->pg_res_update[PG_HPO] = true;1160 1161 if (hpo_frl_stream_enc_acquired)1162 update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = true;1163 1164 if (dc->caps.sequential_ono) {1165 for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {1166 if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1167 update_state->pg_pipe_res_update[PG_DPP][i]) {1168 for (j = i - 1; j >= 0; j--) {1169 update_state->pg_pipe_res_update[PG_HUBP][j] = true;1170 update_state->pg_pipe_res_update[PG_DPP][j] = true;1171 }1172 1173 break;1174 }1175 }1176 }1177}1178 1179/**1180 * dcn35_hw_block_power_down() - power down sequence1181 *1182 * The following sequence describes the ON-OFF (ONO) for power down:1183 *1184 * ONO Region 3, DCPG 25: hpo - SKIPPED1185 * ONO Region 4, DCPG 0: dchubp0, dpp01186 * ONO Region 6, DCPG 1: dchubp1, dpp11187 * ONO Region 8, DCPG 2: dchubp2, dpp21188 * ONO Region 10, DCPG 3: dchubp3, dpp31189 * ONO Region 1, DCPG 23: dchubbub dchvm dchubbubmem - SKIPPED. PMFW will pwr dwn at IPS2 entry1190 * ONO Region 5, DCPG 16: dsc01191 * ONO Region 7, DCPG 17: dsc11192 * ONO Region 9, DCPG 18: dsc21193 * ONO Region 11, DCPG 19: dsc31194 * ONO Region 2, DCPG 24: mpc opp optc dwb1195 * ONO Region 0, DCPG 22: dccg dio dcio - SKIPPED. will be pwr dwn after lono timer is armed1196 *1197 * If sequential ONO is specified the order is modified from ONO Region 11 -> ONO Region 0 descending.1198 *1199 * @dc: Current DC state1200 * @update_state: update PG sequence states for HW block1201 */1202void dcn35_hw_block_power_down(struct dc *dc,1203 struct pg_block_update *update_state)1204{1205 int i = 0;1206 struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;1207 1208 if (!pg_cntl)1209 return;1210 if (dc->debug.ignore_pg)1211 return;1212 1213 if (update_state->pg_res_update[PG_HPO]) {1214 if (pg_cntl->funcs->hpo_pg_control)1215 pg_cntl->funcs->hpo_pg_control(pg_cntl, false);1216 }1217 1218 if (!dc->caps.sequential_ono) {1219 for (i = 0; i < dc->res_pool->pipe_count; i++) {1220 if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1221 update_state->pg_pipe_res_update[PG_DPP][i]) {1222 if (pg_cntl->funcs->hubp_dpp_pg_control)1223 pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, false);1224 }1225 }1226 1227 for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {1228 if (update_state->pg_pipe_res_update[PG_DSC][i]) {1229 if (pg_cntl->funcs->dsc_pg_control)1230 pg_cntl->funcs->dsc_pg_control(pg_cntl, i, false);1231 }1232 }1233 } else {1234 for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {1235 if (update_state->pg_pipe_res_update[PG_DSC][i]) {1236 if (pg_cntl->funcs->dsc_pg_control)1237 pg_cntl->funcs->dsc_pg_control(pg_cntl, i, false);1238 }1239 1240 if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1241 update_state->pg_pipe_res_update[PG_DPP][i]) {1242 if (pg_cntl->funcs->hubp_dpp_pg_control)1243 pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, false);1244 }1245 }1246 }1247 1248 /*this will need all the clients to unregister optc interruts let dmubfw handle this*/1249 if (pg_cntl->funcs->plane_otg_pg_control)1250 pg_cntl->funcs->plane_otg_pg_control(pg_cntl, false);1251 1252 //domain22, 23, 25 currently always on.1253 1254}1255 1256/**1257 * dcn35_hw_block_power_up() - power up sequence1258 *1259 * The following sequence describes the ON-OFF (ONO) for power up:1260 *1261 * ONO Region 0, DCPG 22: dccg dio dcio - SKIPPED1262 * ONO Region 2, DCPG 24: mpc opp optc dwb1263 * ONO Region 5, DCPG 16: dsc01264 * ONO Region 7, DCPG 17: dsc11265 * ONO Region 9, DCPG 18: dsc21266 * ONO Region 11, DCPG 19: dsc31267 * ONO Region 1, DCPG 23: dchubbub dchvm dchubbubmem - SKIPPED. PMFW will power up at IPS2 exit1268 * ONO Region 4, DCPG 0: dchubp0, dpp01269 * ONO Region 6, DCPG 1: dchubp1, dpp11270 * ONO Region 8, DCPG 2: dchubp2, dpp21271 * ONO Region 10, DCPG 3: dchubp3, dpp31272 * ONO Region 3, DCPG 25: hpo - SKIPPED1273 *1274 * If sequential ONO is specified the order is modified from ONO Region 0 -> ONO Region 11 ascending.1275 *1276 * @dc: Current DC state1277 * @update_state: update PG sequence states for HW block1278 */1279void dcn35_hw_block_power_up(struct dc *dc,1280 struct pg_block_update *update_state)1281{1282 int i = 0;1283 struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;1284 1285 if (!pg_cntl)1286 return;1287 if (dc->debug.ignore_pg)1288 return;1289 //domain22, 23, 25 currently always on.1290 /*this will need all the clients to unregister optc interruts let dmubfw handle this*/1291 if (pg_cntl->funcs->plane_otg_pg_control)1292 pg_cntl->funcs->plane_otg_pg_control(pg_cntl, true);1293 1294 if (!dc->caps.sequential_ono) {1295 for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++)1296 if (update_state->pg_pipe_res_update[PG_DSC][i]) {1297 if (pg_cntl->funcs->dsc_pg_control)1298 pg_cntl->funcs->dsc_pg_control(pg_cntl, i, true);1299 }1300 }1301 1302 for (i = 0; i < dc->res_pool->pipe_count; i++) {1303 if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1304 update_state->pg_pipe_res_update[PG_DPP][i]) {1305 if (pg_cntl->funcs->hubp_dpp_pg_control)1306 pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, true);1307 }1308 1309 if (dc->caps.sequential_ono) {1310 if (update_state->pg_pipe_res_update[PG_DSC][i]) {1311 if (pg_cntl->funcs->dsc_pg_control)1312 pg_cntl->funcs->dsc_pg_control(pg_cntl, i, true);1313 }1314 }1315 }1316 if (update_state->pg_res_update[PG_HPO]) {1317 if (pg_cntl->funcs->hpo_pg_control)1318 pg_cntl->funcs->hpo_pg_control(pg_cntl, true);1319 }1320}1321void dcn35_root_clock_control(struct dc *dc,1322 struct pg_block_update *update_state, bool power_on)1323{1324 int i = 0;1325 struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;1326 1327 if (!pg_cntl)1328 return;1329 /*enable root clock first when power up*/1330 if (power_on) {1331 for (i = 0; i < dc->res_pool->pipe_count; i++) {1332 if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1333 update_state->pg_pipe_res_update[PG_DPP][i]) {1334 if (dc->hwseq->funcs.dpp_root_clock_control)1335 dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on);1336 }1337 if (update_state->pg_pipe_res_update[PG_DPSTREAM][i])1338 if (dc->hwseq->funcs.dpstream_root_clock_control)1339 dc->hwseq->funcs.dpstream_root_clock_control(dc->hwseq, i, power_on);1340 }1341 1342 for (i = 0; i < dc->res_pool->dig_link_enc_count; i++)1343 if (update_state->pg_pipe_res_update[PG_PHYSYMCLK][i])1344 if (dc->hwseq->funcs.physymclk_root_clock_control)1345 dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);1346 1347 }1348 for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {1349 if (update_state->pg_pipe_res_update[PG_DSC][i]) {1350 if (power_on) {1351 if (dc->res_pool->dccg->funcs->enable_dsc)1352 dc->res_pool->dccg->funcs->enable_dsc(dc->res_pool->dccg, i);1353 } else {1354 if (dc->res_pool->dccg->funcs->disable_dsc)1355 dc->res_pool->dccg->funcs->disable_dsc(dc->res_pool->dccg, i);1356 }1357 }1358 }1359 /*disable root clock first when power down*/1360 if (!power_on) {1361 for (i = 0; i < dc->res_pool->pipe_count; i++) {1362 if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1363 update_state->pg_pipe_res_update[PG_DPP][i]) {1364 if (dc->hwseq->funcs.dpp_root_clock_control)1365 dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on);1366 }1367 if (update_state->pg_pipe_res_update[PG_DPSTREAM][i])1368 if (dc->hwseq->funcs.dpstream_root_clock_control)1369 dc->hwseq->funcs.dpstream_root_clock_control(dc->hwseq, i, power_on);1370 }1371 1372 for (i = 0; i < dc->res_pool->dig_link_enc_count; i++)1373 if (update_state->pg_pipe_res_update[PG_PHYSYMCLK][i])1374 if (dc->hwseq->funcs.physymclk_root_clock_control)1375 dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);1376 1377 }1378}1379 1380void dcn35_prepare_bandwidth(1381 struct dc *dc,1382 struct dc_state *context)1383{1384 struct pg_block_update pg_update_state;1385 1386 if (dc->hwss.calc_blocks_to_ungate) {1387 dc->hwss.calc_blocks_to_ungate(dc, context, &pg_update_state);1388 1389 if (dc->hwss.root_clock_control)1390 dc->hwss.root_clock_control(dc, &pg_update_state, true);1391 /*power up required HW block*/1392 if (dc->hwss.hw_block_power_up)1393 dc->hwss.hw_block_power_up(dc, &pg_update_state);1394 }1395 1396 dcn20_prepare_bandwidth(dc, context);1397}1398 1399void dcn35_optimize_bandwidth(1400 struct dc *dc,1401 struct dc_state *context)1402{1403 struct pg_block_update pg_update_state;1404 1405 dcn20_optimize_bandwidth(dc, context);1406 1407 if (dc->hwss.calc_blocks_to_gate) {1408 dc->hwss.calc_blocks_to_gate(dc, context, &pg_update_state);1409 /*try to power down unused block*/1410 if (dc->hwss.hw_block_power_down)1411 dc->hwss.hw_block_power_down(dc, &pg_update_state);1412 1413 if (dc->hwss.root_clock_control)1414 dc->hwss.root_clock_control(dc, &pg_update_state, false);1415 }1416}1417 1418void dcn35_set_drr(struct pipe_ctx **pipe_ctx,1419 int num_pipes, struct dc_crtc_timing_adjust adjust)1420{1421 int i = 0;1422 struct drr_params params = {0};1423 // DRR set trigger event mapped to OTG_TRIG_A1424 unsigned int event_triggers = 0x2;//Bit[1]: OTG_TRIG_A1425 // Note DRR trigger events are generated regardless of whether num frames met.1426 unsigned int num_frames = 2;1427 1428 params.vertical_total_max = adjust.v_total_max;1429 params.vertical_total_min = adjust.v_total_min;1430 params.vertical_total_mid = adjust.v_total_mid;1431 params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num;1432 1433 for (i = 0; i < num_pipes; i++) {1434 /* dc_state_destruct() might null the stream resources, so fetch tg1435 * here first to avoid a race condition. The lifetime of the pointee1436 * itself (the timing_generator object) is not a problem here.1437 */1438 struct timing_generator *tg = pipe_ctx[i]->stream_res.tg;1439 1440 if ((tg != NULL) && tg->funcs) {1441 if (pipe_ctx[i]->stream && pipe_ctx[i]->stream->ctx->dc->debug.static_screen_wait_frames) {1442 struct dc_crtc_timing *timing = &pipe_ctx[i]->stream->timing;1443 struct dc *dc = pipe_ctx[i]->stream->ctx->dc;1444 unsigned int frame_rate = timing->pix_clk_100hz / (timing->h_total * timing->v_total);1445 1446 if (frame_rate >= 120 && dc->caps.ips_support &&1447 dc->config.disable_ips != DMUB_IPS_DISABLE_ALL) {1448 /*ips enable case*/1449 num_frames = 2 * (frame_rate % 60);1450 }1451 }1452 if (tg->funcs->set_drr)1453 tg->funcs->set_drr(tg, ¶ms);1454 if (adjust.v_total_max != 0 && adjust.v_total_min != 0)1455 if (tg->funcs->set_static_screen_control)1456 tg->funcs->set_static_screen_control(1457 tg, event_triggers, num_frames);1458 }1459 }1460}1461void dcn35_set_static_screen_control(struct pipe_ctx **pipe_ctx,1462 int num_pipes, const struct dc_static_screen_params *params)1463{1464 unsigned int i;1465 unsigned int triggers = 0;1466 1467 if (params->triggers.surface_update)1468 triggers |= 0x200;/*bit 9 : 10 0000 0000*/1469 if (params->triggers.cursor_update)1470 triggers |= 0x8;/*bit3*/1471 if (params->triggers.force_trigger)1472 triggers |= 0x1;1473 for (i = 0; i < num_pipes; i++)1474 pipe_ctx[i]->stream_res.tg->funcs->1475 set_static_screen_control(pipe_ctx[i]->stream_res.tg,1476 triggers, params->num_frames);1477}1478 1479void dcn35_set_long_vblank(struct pipe_ctx **pipe_ctx,1480 int num_pipes, uint32_t v_total_min, uint32_t v_total_max)1481{1482 int i = 0;1483 struct long_vtotal_params params = {0};1484 1485 params.vertical_total_max = v_total_max;1486 params.vertical_total_min = v_total_min;1487 1488 for (i = 0; i < num_pipes; i++) {1489 if (!pipe_ctx[i])1490 continue;1491 1492 if (pipe_ctx[i]->stream) {1493 struct dc_crtc_timing *timing = &pipe_ctx[i]->stream->timing;1494 1495 if (timing)1496 params.vertical_blank_start = timing->v_total - timing->v_front_porch;1497 else1498 params.vertical_blank_start = 0;1499 1500 if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs &&1501 pipe_ctx[i]->stream_res.tg->funcs->set_long_vtotal)1502 pipe_ctx[i]->stream_res.tg->funcs->set_long_vtotal(pipe_ctx[i]->stream_res.tg, ¶ms);1503 }1504 }1505}1506 1507static bool should_avoid_empty_tu(struct pipe_ctx *pipe_ctx)1508{1509 /* Calculate average pixel count per TU, return false if under ~2.00 to1510 * avoid empty TUs. This is only required for DPIA tunneling as empty TUs1511 * are legal to generate for native DP links. Assume TU size 64 as there1512 * is currently no scenario where it's reprogrammed from HW default.1513 * MTPs have no such limitation, so this does not affect MST use cases.1514 */1515 unsigned int pix_clk_mhz;1516 unsigned int symclk_mhz;1517 unsigned int avg_pix_per_tu_x1000;1518 unsigned int tu_size_bytes = 64;1519 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;1520 struct dc_link_settings *link_settings = &pipe_ctx->link_config.dp_link_settings;1521 const struct dc *dc = pipe_ctx->stream->link->dc;1522 1523 if (pipe_ctx->stream->link->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)1524 return false;1525 1526 // Not necessary for MST configurations1527 if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)1528 return false;1529 1530 pix_clk_mhz = timing->pix_clk_100hz / 10000;1531 1532 // If this is true, can't block due to dynamic ODM1533 if (pix_clk_mhz > dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz)1534 return false;1535 1536 switch (link_settings->link_rate) {1537 case LINK_RATE_LOW:1538 symclk_mhz = 162;1539 break;1540 case LINK_RATE_HIGH:1541 symclk_mhz = 270;1542 break;1543 case LINK_RATE_HIGH2:1544 symclk_mhz = 540;1545 break;1546 case LINK_RATE_HIGH3:1547 symclk_mhz = 810;1548 break;1549 default:1550 // We shouldn't be tunneling any other rates, something is wrong1551 ASSERT(0);1552 return false;1553 }1554 1555 avg_pix_per_tu_x1000 = (1000 * pix_clk_mhz * tu_size_bytes)1556 / (symclk_mhz * link_settings->lane_count);1557 1558 // Add small empirically-decided margin to account for potential jitter1559 return (avg_pix_per_tu_x1000 < 2020);1560}1561 1562bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)1563{1564 struct dc *dc = pipe_ctx->stream->ctx->dc;1565 1566 if (!is_h_timing_divisible_by_2(pipe_ctx->stream))1567 return false;1568 1569 if (should_avoid_empty_tu(pipe_ctx))1570 return false;1571 1572 if (dc_is_dp_signal(pipe_ctx->stream->signal) && !dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) &&1573 dc->debug.enable_dp_dig_pixel_rate_div_policy)1574 return true;1575 1576 return false;1577}1578