3203 lines · c
1/*2 * Copyright 2016 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25#include <linux/delay.h>26 27#include "dm_services.h"28#include "basics/dc_common.h"29#include "dm_helpers.h"30#include "core_types.h"31#include "resource.h"32#include "dcn20/dcn20_resource.h"33#include "dcn20_hwseq.h"34#include "dce/dce_hwseq.h"35#include "dcn20/dcn20_dsc.h"36#include "dcn20/dcn20_optc.h"37#include "abm.h"38#include "clk_mgr.h"39#include "dmcu.h"40#include "hubp.h"41#include "timing_generator.h"42#include "opp.h"43#include "ipp.h"44#include "mpc.h"45#include "mcif_wb.h"46#include "dchubbub.h"47#include "reg_helper.h"48#include "dcn10/dcn10_cm_common.h"49#include "vm_helper.h"50#include "dccg.h"51#include "dc_dmub_srv.h"52#include "dce/dmub_hw_lock_mgr.h"53#include "hw_sequencer.h"54#include "dpcd_defs.h"55#include "inc/link_enc_cfg.h"56#include "link_hwss.h"57#include "link.h"58#include "dc_state_priv.h"59 60#define DC_LOGGER \61 dc_logger62#define DC_LOGGER_INIT(logger) \63 struct dal_logger *dc_logger = logger64 65#define CTX \66 hws->ctx67#define REG(reg)\68 hws->regs->reg69 70#undef FN71#define FN(reg_name, field_name) \72 hws->shifts->field_name, hws->masks->field_name73 74void dcn20_log_color_state(struct dc *dc,75 struct dc_log_buffer_ctx *log_ctx)76{77 struct dc_context *dc_ctx = dc->ctx;78 struct resource_pool *pool = dc->res_pool;79 int i;80 81 DTN_INFO("DPP: DGAM mode SHAPER mode 3DLUT mode 3DLUT bit depth"82 " 3DLUT size RGAM mode GAMUT adjust "83 "C11 C12 C13 C14 "84 "C21 C22 C23 C24 "85 "C31 C32 C33 C34 \n");86 87 for (i = 0; i < pool->pipe_count; i++) {88 struct dpp *dpp = pool->dpps[i];89 struct dcn_dpp_state s = {0};90 91 dpp->funcs->dpp_read_state(dpp, &s);92 dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);93 94 if (!s.is_enabled)95 continue;96 97 DTN_INFO("[%2d]: %8s %11s %10s %15s %10s %9s %12s "98 "%010lld %010lld %010lld %010lld "99 "%010lld %010lld %010lld %010lld "100 "%010lld %010lld %010lld %010lld",101 dpp->inst,102 (s.dgam_lut_mode == 0) ? "Bypass" :103 ((s.dgam_lut_mode == 1) ? "sRGB" :104 ((s.dgam_lut_mode == 2) ? "Ycc" :105 ((s.dgam_lut_mode == 3) ? "RAM" :106 ((s.dgam_lut_mode == 4) ? "RAM" :107 "Unknown")))),108 (s.shaper_lut_mode == 1) ? "RAM A" :109 ((s.shaper_lut_mode == 2) ? "RAM B" :110 "Bypass"),111 (s.lut3d_mode == 1) ? "RAM A" :112 ((s.lut3d_mode == 2) ? "RAM B" :113 "Bypass"),114 (s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit",115 (s.lut3d_size == 0) ? "17x17x17" : "9x9x9",116 (s.rgam_lut_mode == 1) ? "RAM A" :117 ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass"),118 (s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" :119 ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :120 "SW"),121 s.gamut_remap.temperature_matrix[0].value,122 s.gamut_remap.temperature_matrix[1].value,123 s.gamut_remap.temperature_matrix[2].value,124 s.gamut_remap.temperature_matrix[3].value,125 s.gamut_remap.temperature_matrix[4].value,126 s.gamut_remap.temperature_matrix[5].value,127 s.gamut_remap.temperature_matrix[6].value,128 s.gamut_remap.temperature_matrix[7].value,129 s.gamut_remap.temperature_matrix[8].value,130 s.gamut_remap.temperature_matrix[9].value,131 s.gamut_remap.temperature_matrix[10].value,132 s.gamut_remap.temperature_matrix[11].value);133 DTN_INFO("\n");134 }135 DTN_INFO("\n");136 DTN_INFO("DPP Color Caps: input_lut_shared:%d icsc:%d"137 " dgam_ram:%d dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d"138 " post_csc:%d gamcor:%d dgam_rom_for_yuv:%d 3d_lut:%d"139 " blnd_lut:%d oscs:%d\n\n",140 dc->caps.color.dpp.input_lut_shared,141 dc->caps.color.dpp.icsc,142 dc->caps.color.dpp.dgam_ram,143 dc->caps.color.dpp.dgam_rom_caps.srgb,144 dc->caps.color.dpp.dgam_rom_caps.bt2020,145 dc->caps.color.dpp.dgam_rom_caps.gamma2_2,146 dc->caps.color.dpp.dgam_rom_caps.pq,147 dc->caps.color.dpp.dgam_rom_caps.hlg,148 dc->caps.color.dpp.post_csc,149 dc->caps.color.dpp.gamma_corr,150 dc->caps.color.dpp.dgam_rom_for_yuv,151 dc->caps.color.dpp.hw_3d_lut,152 dc->caps.color.dpp.ogam_ram,153 dc->caps.color.dpp.ocsc);154 155 DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE"156 " OGAM mode\n");157 158 for (i = 0; i < pool->mpcc_count; i++) {159 struct mpcc_state s = {0};160 161 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);162 if (s.opp_id != 0xf)163 DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d %9s\n",164 i, s.opp_id, s.dpp_id, s.bot_mpcc_id,165 s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only,166 s.idle,167 (s.rgam_mode == 1) ? "RAM A" :168 ((s.rgam_mode == 2) ? "RAM B" :169 "Bypass"));170 }171 DTN_INFO("\n");172 DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n",173 dc->caps.color.mpc.gamut_remap,174 dc->caps.color.mpc.num_3dluts,175 dc->caps.color.mpc.ogam_ram,176 dc->caps.color.mpc.ocsc);177}178 179 180static int find_free_gsl_group(const struct dc *dc)181{182 if (dc->res_pool->gsl_groups.gsl_0 == 0)183 return 1;184 if (dc->res_pool->gsl_groups.gsl_1 == 0)185 return 2;186 if (dc->res_pool->gsl_groups.gsl_2 == 0)187 return 3;188 189 return 0;190}191 192/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock)193 * This is only used to lock pipes in pipe splitting case with immediate flip194 * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate,195 * so we get tearing with freesync since we cannot flip multiple pipes196 * atomically.197 * We use GSL for this:198 * - immediate flip: find first available GSL group if not already assigned199 * program gsl with that group, set current OTG as master200 * and always us 0x4 = AND of flip_ready from all pipes201 * - vsync flip: disable GSL if used202 *203 * Groups in stream_res are stored as +1 from HW registers, i.e.204 * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1205 * Using a magic value like -1 would require tracking all inits/resets206 */207void dcn20_setup_gsl_group_as_lock(208 const struct dc *dc,209 struct pipe_ctx *pipe_ctx,210 bool enable)211{212 struct gsl_params gsl;213 int group_idx;214 215 memset(&gsl, 0, sizeof(struct gsl_params));216 217 if (enable) {218 /* return if group already assigned since GSL was set up219 * for vsync flip, we would unassign so it can't be "left over"220 */221 if (pipe_ctx->stream_res.gsl_group > 0)222 return;223 224 group_idx = find_free_gsl_group(dc);225 ASSERT(group_idx != 0);226 pipe_ctx->stream_res.gsl_group = group_idx;227 228 /* set gsl group reg field and mark resource used */229 switch (group_idx) {230 case 1:231 gsl.gsl0_en = 1;232 dc->res_pool->gsl_groups.gsl_0 = 1;233 break;234 case 2:235 gsl.gsl1_en = 1;236 dc->res_pool->gsl_groups.gsl_1 = 1;237 break;238 case 3:239 gsl.gsl2_en = 1;240 dc->res_pool->gsl_groups.gsl_2 = 1;241 break;242 default:243 BREAK_TO_DEBUGGER();244 return; // invalid case245 }246 gsl.gsl_master_en = 1;247 } else {248 group_idx = pipe_ctx->stream_res.gsl_group;249 if (group_idx == 0)250 return; // if not in use, just return251 252 pipe_ctx->stream_res.gsl_group = 0;253 254 /* unset gsl group reg field and mark resource free */255 switch (group_idx) {256 case 1:257 gsl.gsl0_en = 0;258 dc->res_pool->gsl_groups.gsl_0 = 0;259 break;260 case 2:261 gsl.gsl1_en = 0;262 dc->res_pool->gsl_groups.gsl_1 = 0;263 break;264 case 3:265 gsl.gsl2_en = 0;266 dc->res_pool->gsl_groups.gsl_2 = 0;267 break;268 default:269 BREAK_TO_DEBUGGER();270 return;271 }272 gsl.gsl_master_en = 0;273 }274 275 /* at this point we want to program whether it's to enable or disable */276 if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL &&277 pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) {278 pipe_ctx->stream_res.tg->funcs->set_gsl(279 pipe_ctx->stream_res.tg,280 &gsl);281 282 pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(283 pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);284 } else285 BREAK_TO_DEBUGGER();286}287 288void dcn20_set_flip_control_gsl(289 struct pipe_ctx *pipe_ctx,290 bool flip_immediate)291{292 if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl)293 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl(294 pipe_ctx->plane_res.hubp, flip_immediate);295 296}297 298void dcn20_enable_power_gating_plane(299 struct dce_hwseq *hws,300 bool enable)301{302 bool force_on = true; /* disable power gating */303 uint32_t org_ip_request_cntl = 0;304 305 if (enable)306 force_on = false;307 308 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);309 if (org_ip_request_cntl == 0)310 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);311 312 /* DCHUBP0/1/2/3/4/5 */313 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);314 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);315 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);316 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);317 if (REG(DOMAIN8_PG_CONFIG))318 REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);319 if (REG(DOMAIN10_PG_CONFIG))320 REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);321 322 /* DPP0/1/2/3/4/5 */323 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);324 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);325 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);326 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);327 if (REG(DOMAIN9_PG_CONFIG))328 REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);329 if (REG(DOMAIN11_PG_CONFIG))330 REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);331 332 /* DCS0/1/2/3/4/5 */333 REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on);334 REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on);335 REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on);336 if (REG(DOMAIN19_PG_CONFIG))337 REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on);338 if (REG(DOMAIN20_PG_CONFIG))339 REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on);340 if (REG(DOMAIN21_PG_CONFIG))341 REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on);342 343 if (org_ip_request_cntl == 0)344 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);345 346}347 348void dcn20_dccg_init(struct dce_hwseq *hws)349{350 /*351 * set MICROSECOND_TIME_BASE_DIV352 * 100Mhz refclk -> 0x120264353 * 27Mhz refclk -> 0x12021b354 * 48Mhz refclk -> 0x120230355 *356 */357 REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264);358 359 /*360 * set MILLISECOND_TIME_BASE_DIV361 * 100Mhz refclk -> 0x1186a0362 * 27Mhz refclk -> 0x106978363 * 48Mhz refclk -> 0x10bb80364 *365 */366 REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0);367 368 /* This value is dependent on the hardware pipeline delay so set once per SOC */369 REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c);370}371 372void dcn20_disable_vga(373 struct dce_hwseq *hws)374{375 REG_WRITE(D1VGA_CONTROL, 0);376 REG_WRITE(D2VGA_CONTROL, 0);377 REG_WRITE(D3VGA_CONTROL, 0);378 REG_WRITE(D4VGA_CONTROL, 0);379 REG_WRITE(D5VGA_CONTROL, 0);380 REG_WRITE(D6VGA_CONTROL, 0);381}382 383void dcn20_program_triple_buffer(384 const struct dc *dc,385 struct pipe_ctx *pipe_ctx,386 bool enable_triple_buffer)387{388 if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) {389 pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer(390 pipe_ctx->plane_res.hubp,391 enable_triple_buffer);392 }393}394 395/* Blank pixel data during initialization */396void dcn20_init_blank(397 struct dc *dc,398 struct timing_generator *tg)399{400 struct dce_hwseq *hws = dc->hwseq;401 enum dc_color_space color_space;402 struct tg_color black_color = {0};403 struct output_pixel_processor *opp = NULL;404 struct output_pixel_processor *bottom_opp = NULL;405 uint32_t num_opps, opp_id_src0, opp_id_src1;406 uint32_t otg_active_width = 0, otg_active_height = 0;407 408 /* program opp dpg blank color */409 color_space = COLOR_SPACE_SRGB;410 color_space_to_black_color(dc, color_space, &black_color);411 412 /* get the OTG active size */413 tg->funcs->get_otg_active_size(tg,414 &otg_active_width,415 &otg_active_height);416 417 /* get the OPTC source */418 tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);419 420 if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) {421 ASSERT(false);422 return;423 }424 opp = dc->res_pool->opps[opp_id_src0];425 426 /* don't override the blank pattern if already enabled with the correct one. */427 if (opp->funcs->dpg_is_blanked && opp->funcs->dpg_is_blanked(opp))428 return;429 430 if (num_opps == 2) {431 otg_active_width = otg_active_width / 2;432 433 if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) {434 ASSERT(false);435 return;436 }437 bottom_opp = dc->res_pool->opps[opp_id_src1];438 }439 440 opp->funcs->opp_set_disp_pattern_generator(441 opp,442 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,443 CONTROLLER_DP_COLOR_SPACE_UDEFINED,444 COLOR_DEPTH_UNDEFINED,445 &black_color,446 otg_active_width,447 otg_active_height,448 0);449 450 if (num_opps == 2) {451 bottom_opp->funcs->opp_set_disp_pattern_generator(452 bottom_opp,453 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,454 CONTROLLER_DP_COLOR_SPACE_UDEFINED,455 COLOR_DEPTH_UNDEFINED,456 &black_color,457 otg_active_width,458 otg_active_height,459 0);460 }461 462 hws->funcs.wait_for_blank_complete(opp);463}464 465void dcn20_dsc_pg_control(466 struct dce_hwseq *hws,467 unsigned int dsc_inst,468 bool power_on)469{470 uint32_t power_gate = power_on ? 0 : 1;471 uint32_t pwr_status = power_on ? 0 : 2;472 uint32_t org_ip_request_cntl = 0;473 474 if (hws->ctx->dc->debug.disable_dsc_power_gate)475 return;476 477 if (REG(DOMAIN16_PG_CONFIG) == 0)478 return;479 480 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);481 if (org_ip_request_cntl == 0)482 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);483 484 switch (dsc_inst) {485 case 0: /* DSC0 */486 REG_UPDATE(DOMAIN16_PG_CONFIG,487 DOMAIN16_POWER_GATE, power_gate);488 489 REG_WAIT(DOMAIN16_PG_STATUS,490 DOMAIN16_PGFSM_PWR_STATUS, pwr_status,491 1, 1000);492 break;493 case 1: /* DSC1 */494 REG_UPDATE(DOMAIN17_PG_CONFIG,495 DOMAIN17_POWER_GATE, power_gate);496 497 REG_WAIT(DOMAIN17_PG_STATUS,498 DOMAIN17_PGFSM_PWR_STATUS, pwr_status,499 1, 1000);500 break;501 case 2: /* DSC2 */502 REG_UPDATE(DOMAIN18_PG_CONFIG,503 DOMAIN18_POWER_GATE, power_gate);504 505 REG_WAIT(DOMAIN18_PG_STATUS,506 DOMAIN18_PGFSM_PWR_STATUS, pwr_status,507 1, 1000);508 break;509 case 3: /* DSC3 */510 REG_UPDATE(DOMAIN19_PG_CONFIG,511 DOMAIN19_POWER_GATE, power_gate);512 513 REG_WAIT(DOMAIN19_PG_STATUS,514 DOMAIN19_PGFSM_PWR_STATUS, pwr_status,515 1, 1000);516 break;517 case 4: /* DSC4 */518 REG_UPDATE(DOMAIN20_PG_CONFIG,519 DOMAIN20_POWER_GATE, power_gate);520 521 REG_WAIT(DOMAIN20_PG_STATUS,522 DOMAIN20_PGFSM_PWR_STATUS, pwr_status,523 1, 1000);524 break;525 case 5: /* DSC5 */526 REG_UPDATE(DOMAIN21_PG_CONFIG,527 DOMAIN21_POWER_GATE, power_gate);528 529 REG_WAIT(DOMAIN21_PG_STATUS,530 DOMAIN21_PGFSM_PWR_STATUS, pwr_status,531 1, 1000);532 break;533 default:534 BREAK_TO_DEBUGGER();535 break;536 }537 538 if (org_ip_request_cntl == 0)539 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);540}541 542void dcn20_dpp_pg_control(543 struct dce_hwseq *hws,544 unsigned int dpp_inst,545 bool power_on)546{547 uint32_t power_gate = power_on ? 0 : 1;548 uint32_t pwr_status = power_on ? 0 : 2;549 550 if (hws->ctx->dc->debug.disable_dpp_power_gate)551 return;552 if (REG(DOMAIN1_PG_CONFIG) == 0)553 return;554 555 switch (dpp_inst) {556 case 0: /* DPP0 */557 REG_UPDATE(DOMAIN1_PG_CONFIG,558 DOMAIN1_POWER_GATE, power_gate);559 560 REG_WAIT(DOMAIN1_PG_STATUS,561 DOMAIN1_PGFSM_PWR_STATUS, pwr_status,562 1, 1000);563 break;564 case 1: /* DPP1 */565 REG_UPDATE(DOMAIN3_PG_CONFIG,566 DOMAIN3_POWER_GATE, power_gate);567 568 REG_WAIT(DOMAIN3_PG_STATUS,569 DOMAIN3_PGFSM_PWR_STATUS, pwr_status,570 1, 1000);571 break;572 case 2: /* DPP2 */573 REG_UPDATE(DOMAIN5_PG_CONFIG,574 DOMAIN5_POWER_GATE, power_gate);575 576 REG_WAIT(DOMAIN5_PG_STATUS,577 DOMAIN5_PGFSM_PWR_STATUS, pwr_status,578 1, 1000);579 break;580 case 3: /* DPP3 */581 REG_UPDATE(DOMAIN7_PG_CONFIG,582 DOMAIN7_POWER_GATE, power_gate);583 584 REG_WAIT(DOMAIN7_PG_STATUS,585 DOMAIN7_PGFSM_PWR_STATUS, pwr_status,586 1, 1000);587 break;588 case 4: /* DPP4 */589 REG_UPDATE(DOMAIN9_PG_CONFIG,590 DOMAIN9_POWER_GATE, power_gate);591 592 REG_WAIT(DOMAIN9_PG_STATUS,593 DOMAIN9_PGFSM_PWR_STATUS, pwr_status,594 1, 1000);595 break;596 case 5: /* DPP5 */597 /*598 * Do not power gate DPP5, should be left at HW default, power on permanently.599 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard600 * reset.601 * REG_UPDATE(DOMAIN11_PG_CONFIG,602 * DOMAIN11_POWER_GATE, power_gate);603 *604 * REG_WAIT(DOMAIN11_PG_STATUS,605 * DOMAIN11_PGFSM_PWR_STATUS, pwr_status,606 * 1, 1000);607 */608 break;609 default:610 BREAK_TO_DEBUGGER();611 break;612 }613}614 615 616void dcn20_hubp_pg_control(617 struct dce_hwseq *hws,618 unsigned int hubp_inst,619 bool power_on)620{621 uint32_t power_gate = power_on ? 0 : 1;622 uint32_t pwr_status = power_on ? 0 : 2;623 624 if (hws->ctx->dc->debug.disable_hubp_power_gate)625 return;626 if (REG(DOMAIN0_PG_CONFIG) == 0)627 return;628 629 switch (hubp_inst) {630 case 0: /* DCHUBP0 */631 REG_UPDATE(DOMAIN0_PG_CONFIG,632 DOMAIN0_POWER_GATE, power_gate);633 634 REG_WAIT(DOMAIN0_PG_STATUS,635 DOMAIN0_PGFSM_PWR_STATUS, pwr_status,636 1, 1000);637 break;638 case 1: /* DCHUBP1 */639 REG_UPDATE(DOMAIN2_PG_CONFIG,640 DOMAIN2_POWER_GATE, power_gate);641 642 REG_WAIT(DOMAIN2_PG_STATUS,643 DOMAIN2_PGFSM_PWR_STATUS, pwr_status,644 1, 1000);645 break;646 case 2: /* DCHUBP2 */647 REG_UPDATE(DOMAIN4_PG_CONFIG,648 DOMAIN4_POWER_GATE, power_gate);649 650 REG_WAIT(DOMAIN4_PG_STATUS,651 DOMAIN4_PGFSM_PWR_STATUS, pwr_status,652 1, 1000);653 break;654 case 3: /* DCHUBP3 */655 REG_UPDATE(DOMAIN6_PG_CONFIG,656 DOMAIN6_POWER_GATE, power_gate);657 658 REG_WAIT(DOMAIN6_PG_STATUS,659 DOMAIN6_PGFSM_PWR_STATUS, pwr_status,660 1, 1000);661 break;662 case 4: /* DCHUBP4 */663 REG_UPDATE(DOMAIN8_PG_CONFIG,664 DOMAIN8_POWER_GATE, power_gate);665 666 REG_WAIT(DOMAIN8_PG_STATUS,667 DOMAIN8_PGFSM_PWR_STATUS, pwr_status,668 1, 1000);669 break;670 case 5: /* DCHUBP5 */671 /*672 * Do not power gate DCHUB5, should be left at HW default, power on permanently.673 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard674 * reset.675 * REG_UPDATE(DOMAIN10_PG_CONFIG,676 * DOMAIN10_POWER_GATE, power_gate);677 *678 * REG_WAIT(DOMAIN10_PG_STATUS,679 * DOMAIN10_PGFSM_PWR_STATUS, pwr_status,680 * 1, 1000);681 */682 break;683 default:684 BREAK_TO_DEBUGGER();685 break;686 }687}688 689 690/* disable HW used by plane.691 * note: cannot disable until disconnect is complete692 */693void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)694{695 struct dce_hwseq *hws = dc->hwseq;696 struct hubp *hubp = pipe_ctx->plane_res.hubp;697 struct dpp *dpp = pipe_ctx->plane_res.dpp;698 699 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);700 701 /* In flip immediate with pipe splitting case GSL is used for702 * synchronization so we must disable it when the plane is disabled.703 */704 if (pipe_ctx->stream_res.gsl_group != 0)705 dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);706 707 if (hubp->funcs->hubp_update_mall_sel)708 hubp->funcs->hubp_update_mall_sel(hubp, 0, false);709 710 dc->hwss.set_flip_control_gsl(pipe_ctx, false);711 712 hubp->funcs->hubp_clk_cntl(hubp, false);713 714 dpp->funcs->dpp_dppclk_control(dpp, false, false);715 716 hubp->power_gated = true;717 718 hws->funcs.plane_atomic_power_down(dc,719 pipe_ctx->plane_res.dpp,720 pipe_ctx->plane_res.hubp);721 722 pipe_ctx->stream = NULL;723 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));724 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));725 pipe_ctx->top_pipe = NULL;726 pipe_ctx->bottom_pipe = NULL;727 pipe_ctx->prev_odm_pipe = NULL;728 pipe_ctx->next_odm_pipe = NULL;729 pipe_ctx->plane_state = NULL;730}731 732 733void dcn20_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx)734{735 bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM;736 struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;737 738 DC_LOGGER_INIT(dc->ctx->logger);739 740 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)741 return;742 743 dcn20_plane_atomic_disable(dc, pipe_ctx);744 745 /* Turn back off the phantom OTG after the phantom plane is fully disabled746 */747 if (is_phantom)748 if (tg && tg->funcs->disable_phantom_crtc)749 tg->funcs->disable_phantom_crtc(tg);750 751 DC_LOG_DC("Power down front end %d\n",752 pipe_ctx->pipe_idx);753}754 755void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank)756{757 dcn20_blank_pixel_data(dc, pipe_ctx, blank);758}759 760static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,761 int opp_cnt, bool is_two_pixels_per_container)762{763 bool hblank_halved = is_two_pixels_per_container;764 int flow_ctrl_cnt;765 766 if (opp_cnt >= 2)767 hblank_halved = true;768 769 flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable -770 stream->timing.h_border_left -771 stream->timing.h_border_right;772 773 if (hblank_halved)774 flow_ctrl_cnt /= 2;775 776 /* ODM combine 4:1 case */777 if (opp_cnt == 4)778 flow_ctrl_cnt /= 2;779 780 return flow_ctrl_cnt;781}782 783static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)784{785 switch (link->link_enc->transmitter) {786 case TRANSMITTER_UNIPHY_A:787 return PHYD32CLKA;788 case TRANSMITTER_UNIPHY_B:789 return PHYD32CLKB;790 case TRANSMITTER_UNIPHY_C:791 return PHYD32CLKC;792 case TRANSMITTER_UNIPHY_D:793 return PHYD32CLKD;794 case TRANSMITTER_UNIPHY_E:795 return PHYD32CLKE;796 default:797 return PHYD32CLKA;798 }799}800 801static int get_odm_segment_count(struct pipe_ctx *pipe_ctx)802{803 struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;804 int count = 1;805 806 while (odm_pipe != NULL) {807 count++;808 odm_pipe = odm_pipe->next_odm_pipe;809 }810 811 return count;812}813 814enum dc_status dcn20_enable_stream_timing(815 struct pipe_ctx *pipe_ctx,816 struct dc_state *context,817 struct dc *dc)818{819 struct dce_hwseq *hws = dc->hwseq;820 struct dc_stream_state *stream = pipe_ctx->stream;821 struct drr_params params = {0};822 unsigned int event_triggers = 0;823 int opp_cnt = 1;824 int opp_inst[MAX_PIPES] = {0};825 bool interlace = stream->timing.flags.INTERLACE;826 int i;827 struct mpc_dwb_flow_control flow_control;828 struct mpc *mpc = dc->res_pool->mpc;829 bool is_two_pixels_per_container =830 pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);831 bool rate_control_2x_pclk = (interlace || is_two_pixels_per_container);832 int odm_slice_width;833 int last_odm_slice_width;834 struct pipe_ctx *opp_heads[MAX_PIPES];835 836 if (dc->res_pool->dccg->funcs->set_pixel_rate_div)837 dc->res_pool->dccg->funcs->set_pixel_rate_div(838 dc->res_pool->dccg,839 pipe_ctx->stream_res.tg->inst,840 pipe_ctx->pixel_rate_divider.div_factor1,841 pipe_ctx->pixel_rate_divider.div_factor2);842 843 /* by upper caller loop, pipe0 is parent pipe and be called first.844 * back end is set up by for pipe0. Other children pipe share back end845 * with pipe 0. No program is needed.846 */847 if (pipe_ctx->top_pipe != NULL)848 return DC_OK;849 850 /* TODO check if timing_changed, disable stream if timing changed */851 852 opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);853 for (i = 0; i < opp_cnt; i++)854 opp_inst[i] = opp_heads[i]->stream_res.opp->inst;855 856 odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);857 last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);858 if (opp_cnt > 1)859 pipe_ctx->stream_res.tg->funcs->set_odm_combine(860 pipe_ctx->stream_res.tg,861 opp_inst, opp_cnt, odm_slice_width,862 last_odm_slice_width);863 864 /* HW program guide assume display already disable865 * by unplug sequence. OTG assume stop.866 */867 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);868 869 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(870 pipe_ctx->clock_source,871 &pipe_ctx->stream_res.pix_clk_params,872 dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),873 &pipe_ctx->pll_settings)) {874 BREAK_TO_DEBUGGER();875 return DC_ERROR_UNEXPECTED;876 }877 878 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {879 struct dccg *dccg = dc->res_pool->dccg;880 struct timing_generator *tg = pipe_ctx->stream_res.tg;881 struct dtbclk_dto_params dto_params = {0};882 883 if (dccg->funcs->set_dtbclk_p_src)884 dccg->funcs->set_dtbclk_p_src(dccg, DTBCLK0, tg->inst);885 886 dto_params.otg_inst = tg->inst;887 dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;888 dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);889 dto_params.timing = &pipe_ctx->stream->timing;890 dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);891 dccg->funcs->set_dtbclk_dto(dccg, &dto_params);892 }893 894 if (dc_is_hdmi_tmds_signal(stream->signal)) {895 stream->link->phy_state.symclk_ref_cnts.otg = 1;896 if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF)897 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;898 else899 stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;900 }901 902 if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))903 dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);904 905 pipe_ctx->stream_res.tg->funcs->program_timing(906 pipe_ctx->stream_res.tg,907 &stream->timing,908 pipe_ctx->pipe_dlg_param.vready_offset,909 pipe_ctx->pipe_dlg_param.vstartup_start,910 pipe_ctx->pipe_dlg_param.vupdate_offset,911 pipe_ctx->pipe_dlg_param.vupdate_width,912 pipe_ctx->pipe_dlg_param.pstate_keepout,913 pipe_ctx->stream->signal,914 true);915 916 rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;917 flow_control.flow_ctrl_mode = 0;918 flow_control.flow_ctrl_cnt0 = 0x80;919 flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt,920 is_two_pixels_per_container);921 if (mpc->funcs->set_out_rate_control) {922 for (i = 0; i < opp_cnt; ++i) {923 mpc->funcs->set_out_rate_control(924 mpc, opp_inst[i],925 true,926 rate_control_2x_pclk,927 &flow_control);928 }929 }930 931 for (i = 0; i < opp_cnt; i++) {932 opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(933 opp_heads[i]->stream_res.opp,934 true);935 opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(936 opp_heads[i]->stream_res.opp,937 stream->timing.pixel_encoding,938 resource_is_pipe_type(opp_heads[i], OTG_MASTER));939 }940 941 hws->funcs.blank_pixel_data(dc, pipe_ctx, true);942 943 /* VTG is within DCHUB command block. DCFCLK is always on */944 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {945 BREAK_TO_DEBUGGER();946 return DC_ERROR_UNEXPECTED;947 }948 949 hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);950 951 params.vertical_total_min = stream->adjust.v_total_min;952 params.vertical_total_max = stream->adjust.v_total_max;953 params.vertical_total_mid = stream->adjust.v_total_mid;954 params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;955 if (pipe_ctx->stream_res.tg->funcs->set_drr)956 pipe_ctx->stream_res.tg->funcs->set_drr(957 pipe_ctx->stream_res.tg, ¶ms);958 959 // DRR should set trigger event to monitor surface update event960 if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)961 event_triggers = 0x80;962 /* Event triggers and num frames initialized for DRR, but can be963 * later updated for PSR use. Note DRR trigger events are generated964 * regardless of whether num frames met.965 */966 if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)967 pipe_ctx->stream_res.tg->funcs->set_static_screen_control(968 pipe_ctx->stream_res.tg, event_triggers, 2);969 970 /* TODO program crtc source select for non-virtual signal*/971 /* TODO program FMT */972 /* TODO setup link_enc */973 /* TODO set stream attributes */974 /* TODO program audio */975 /* TODO enable stream if timing changed */976 /* TODO unblank stream if DP */977 978 if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {979 if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)980 pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);981 }982 983 return DC_OK;984}985 986void dcn20_program_output_csc(struct dc *dc,987 struct pipe_ctx *pipe_ctx,988 enum dc_color_space colorspace,989 uint16_t *matrix,990 int opp_id)991{992 struct mpc *mpc = dc->res_pool->mpc;993 enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A;994 int mpcc_id = pipe_ctx->plane_res.hubp->inst;995 996 if (mpc->funcs->power_on_mpc_mem_pwr)997 mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);998 999 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {1000 if (mpc->funcs->set_output_csc != NULL)1001 mpc->funcs->set_output_csc(mpc,1002 opp_id,1003 matrix,1004 ocsc_mode);1005 } else {1006 if (mpc->funcs->set_ocsc_default != NULL)1007 mpc->funcs->set_ocsc_default(mpc,1008 opp_id,1009 colorspace,1010 ocsc_mode);1011 }1012}1013 1014bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,1015 const struct dc_stream_state *stream)1016{1017 int mpcc_id = pipe_ctx->plane_res.hubp->inst;1018 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;1019 const struct pwl_params *params = NULL;1020 /*1021 * program OGAM only for the top pipe1022 * if there is a pipe split then fix diagnostic is required:1023 * how to pass OGAM parameter for stream.1024 * if programming for all pipes is required then remove condition1025 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.1026 */1027 if (mpc->funcs->power_on_mpc_mem_pwr)1028 mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);1029 if (pipe_ctx->top_pipe == NULL1030 && mpc->funcs->set_output_gamma) {1031 if (stream->out_transfer_func.type == TF_TYPE_HWPWL)1032 params = &stream->out_transfer_func.pwl;1033 else if (pipe_ctx->stream->out_transfer_func.type ==1034 TF_TYPE_DISTRIBUTED_POINTS &&1035 cm_helper_translate_curve_to_hw_format(dc->ctx,1036 &stream->out_transfer_func,1037 &mpc->blender_params, false))1038 params = &mpc->blender_params;1039 /*1040 * there is no ROM1041 */1042 if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)1043 BREAK_TO_DEBUGGER();1044 }1045 /*1046 * if above if is not executed then 'params' equal to 0 and set in bypass1047 */1048 if (mpc->funcs->set_output_gamma)1049 mpc->funcs->set_output_gamma(mpc, mpcc_id, params);1050 1051 return true;1052}1053 1054bool dcn20_set_blend_lut(1055 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)1056{1057 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;1058 bool result = true;1059 const struct pwl_params *blend_lut = NULL;1060 1061 if (plane_state->blend_tf.type == TF_TYPE_HWPWL)1062 blend_lut = &plane_state->blend_tf.pwl;1063 else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {1064 cm_helper_translate_curve_to_hw_format(plane_state->ctx,1065 &plane_state->blend_tf,1066 &dpp_base->regamma_params, false);1067 blend_lut = &dpp_base->regamma_params;1068 }1069 result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);1070 1071 return result;1072}1073 1074bool dcn20_set_shaper_3dlut(1075 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)1076{1077 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;1078 bool result = true;1079 const struct pwl_params *shaper_lut = NULL;1080 1081 if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)1082 shaper_lut = &plane_state->in_shaper_func.pwl;1083 else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {1084 cm_helper_translate_curve_to_hw_format(plane_state->ctx,1085 &plane_state->in_shaper_func,1086 &dpp_base->shaper_params, true);1087 shaper_lut = &dpp_base->shaper_params;1088 }1089 1090 result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut);1091 if (plane_state->lut3d_func.state.bits.initialized == 1)1092 result = dpp_base->funcs->dpp_program_3dlut(dpp_base,1093 &plane_state->lut3d_func.lut_3d);1094 else1095 result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL);1096 1097 return result;1098}1099 1100bool dcn20_set_input_transfer_func(struct dc *dc,1101 struct pipe_ctx *pipe_ctx,1102 const struct dc_plane_state *plane_state)1103{1104 struct dce_hwseq *hws = dc->hwseq;1105 struct dpp *dpp_base = pipe_ctx->plane_res.dpp;1106 const struct dc_transfer_func *tf = NULL;1107 bool result = true;1108 bool use_degamma_ram = false;1109 1110 if (dpp_base == NULL || plane_state == NULL)1111 return false;1112 1113 hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);1114 hws->funcs.set_blend_lut(pipe_ctx, plane_state);1115 1116 tf = &plane_state->in_transfer_func;1117 1118 if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS)1119 use_degamma_ram = true;1120 1121 if (use_degamma_ram == true) {1122 if (tf->type == TF_TYPE_HWPWL)1123 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,1124 &tf->pwl);1125 else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) {1126 cm_helper_translate_curve_to_degamma_hw_format(tf,1127 &dpp_base->degamma_params);1128 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,1129 &dpp_base->degamma_params);1130 }1131 return true;1132 }1133 /* handle here the optimized cases when de-gamma ROM could be used.1134 *1135 */1136 if (tf->type == TF_TYPE_PREDEFINED) {1137 switch (tf->tf) {1138 case TRANSFER_FUNCTION_SRGB:1139 dpp_base->funcs->dpp_set_degamma(dpp_base,1140 IPP_DEGAMMA_MODE_HW_sRGB);1141 break;1142 case TRANSFER_FUNCTION_BT709:1143 dpp_base->funcs->dpp_set_degamma(dpp_base,1144 IPP_DEGAMMA_MODE_HW_xvYCC);1145 break;1146 case TRANSFER_FUNCTION_LINEAR:1147 dpp_base->funcs->dpp_set_degamma(dpp_base,1148 IPP_DEGAMMA_MODE_BYPASS);1149 break;1150 case TRANSFER_FUNCTION_PQ:1151 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);1152 cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);1153 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);1154 result = true;1155 break;1156 default:1157 result = false;1158 break;1159 }1160 } else if (tf->type == TF_TYPE_BYPASS)1161 dpp_base->funcs->dpp_set_degamma(dpp_base,1162 IPP_DEGAMMA_MODE_BYPASS);1163 else {1164 /*1165 * if we are here, we did not handle correctly.1166 * fix is required for this use case1167 */1168 BREAK_TO_DEBUGGER();1169 dpp_base->funcs->dpp_set_degamma(dpp_base,1170 IPP_DEGAMMA_MODE_BYPASS);1171 }1172 1173 return result;1174}1175 1176void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)1177{1178 struct pipe_ctx *odm_pipe;1179 int opp_cnt = 1;1180 int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };1181 int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);1182 int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);1183 1184 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {1185 opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;1186 opp_cnt++;1187 }1188 1189 if (opp_cnt > 1)1190 pipe_ctx->stream_res.tg->funcs->set_odm_combine(1191 pipe_ctx->stream_res.tg,1192 opp_inst, opp_cnt,1193 odm_slice_width, last_odm_slice_width);1194 else1195 pipe_ctx->stream_res.tg->funcs->set_odm_bypass(1196 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);1197}1198 1199void dcn20_blank_pixel_data(1200 struct dc *dc,1201 struct pipe_ctx *pipe_ctx,1202 bool blank)1203{1204 struct tg_color black_color = {0};1205 struct stream_resource *stream_res = &pipe_ctx->stream_res;1206 struct dc_stream_state *stream = pipe_ctx->stream;1207 enum dc_color_space color_space = stream->output_color_space;1208 enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;1209 enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;1210 struct pipe_ctx *odm_pipe;1211 struct rect odm_slice_src;1212 1213 if (stream->link->test_pattern_enabled)1214 return;1215 1216 /* get opp dpg blank color */1217 color_space_to_black_color(dc, color_space, &black_color);1218 1219 if (blank) {1220 dc->hwss.set_abm_immediate_disable(pipe_ctx);1221 1222 if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {1223 test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;1224 test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;1225 }1226 } else {1227 test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;1228 }1229 1230 odm_pipe = pipe_ctx;1231 1232 while (odm_pipe->next_odm_pipe) {1233 odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);1234 dc->hwss.set_disp_pattern_generator(dc,1235 odm_pipe,1236 test_pattern,1237 test_pattern_color_space,1238 stream->timing.display_color_depth,1239 &black_color,1240 odm_slice_src.width,1241 odm_slice_src.height,1242 odm_slice_src.x);1243 odm_pipe = odm_pipe->next_odm_pipe;1244 }1245 1246 odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);1247 dc->hwss.set_disp_pattern_generator(dc,1248 odm_pipe,1249 test_pattern,1250 test_pattern_color_space,1251 stream->timing.display_color_depth,1252 &black_color,1253 odm_slice_src.width,1254 odm_slice_src.height,1255 odm_slice_src.x);1256 1257 if (!blank)1258 if (stream_res->abm) {1259 dc->hwss.set_pipe(pipe_ctx);1260 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);1261 }1262}1263 1264 1265static void dcn20_power_on_plane_resources(1266 struct dce_hwseq *hws,1267 struct pipe_ctx *pipe_ctx)1268{1269 DC_LOGGER_INIT(hws->ctx->logger);1270 1271 if (hws->funcs.dpp_root_clock_control)1272 hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true);1273 1274 if (REG(DC_IP_REQUEST_CNTL)) {1275 REG_SET(DC_IP_REQUEST_CNTL, 0,1276 IP_REQUEST_EN, 1);1277 1278 if (hws->funcs.dpp_pg_control)1279 hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);1280 1281 if (hws->funcs.hubp_pg_control)1282 hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);1283 1284 REG_SET(DC_IP_REQUEST_CNTL, 0,1285 IP_REQUEST_EN, 0);1286 DC_LOG_DEBUG(1287 "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst);1288 }1289}1290 1291static void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,1292 struct dc_state *context)1293{1294 //if (dc->debug.sanity_checks) {1295 // dcn10_verify_allow_pstate_change_high(dc);1296 //}1297 dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx);1298 1299 /* enable DCFCLK current DCHUB */1300 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);1301 1302 /* initialize HUBP on power up */1303 pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);1304 1305 /* make sure OPP_PIPE_CLOCK_EN = 1 */1306 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(1307 pipe_ctx->stream_res.opp,1308 true);1309 1310/* TODO: enable/disable in dm as per update type.1311 if (plane_state) {1312 DC_LOG_DC(dc->ctx->logger,1313 "Pipe:%d 0x%x: addr hi:0x%x, "1314 "addr low:0x%x, "1315 "src: %d, %d, %d,"1316 " %d; dst: %d, %d, %d, %d;\n",1317 pipe_ctx->pipe_idx,1318 plane_state,1319 plane_state->address.grph.addr.high_part,1320 plane_state->address.grph.addr.low_part,1321 plane_state->src_rect.x,1322 plane_state->src_rect.y,1323 plane_state->src_rect.width,1324 plane_state->src_rect.height,1325 plane_state->dst_rect.x,1326 plane_state->dst_rect.y,1327 plane_state->dst_rect.width,1328 plane_state->dst_rect.height);1329 1330 DC_LOG_DC(dc->ctx->logger,1331 "Pipe %d: width, height, x, y format:%d\n"1332 "viewport:%d, %d, %d, %d\n"1333 "recout: %d, %d, %d, %d\n",1334 pipe_ctx->pipe_idx,1335 plane_state->format,1336 pipe_ctx->plane_res.scl_data.viewport.width,1337 pipe_ctx->plane_res.scl_data.viewport.height,1338 pipe_ctx->plane_res.scl_data.viewport.x,1339 pipe_ctx->plane_res.scl_data.viewport.y,1340 pipe_ctx->plane_res.scl_data.recout.width,1341 pipe_ctx->plane_res.scl_data.recout.height,1342 pipe_ctx->plane_res.scl_data.recout.x,1343 pipe_ctx->plane_res.scl_data.recout.y);1344 print_rq_dlg_ttu(dc, pipe_ctx);1345 }1346*/1347 if (dc->vm_pa_config.valid) {1348 struct vm_system_aperture_param apt;1349 1350 apt.sys_default.quad_part = 0;1351 1352 apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;1353 apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;1354 1355 // Program system aperture settings1356 pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);1357 }1358 1359 if (!pipe_ctx->top_pipe1360 && pipe_ctx->plane_state1361 && pipe_ctx->plane_state->flip_int_enabled1362 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)1363 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);1364 1365// if (dc->debug.sanity_checks) {1366// dcn10_verify_allow_pstate_change_high(dc);1367// }1368}1369 1370void dcn20_pipe_control_lock(1371 struct dc *dc,1372 struct pipe_ctx *pipe,1373 bool lock)1374{1375 struct pipe_ctx *temp_pipe;1376 bool flip_immediate = false;1377 1378 /* use TG master update lock to lock everything on the TG1379 * therefore only top pipe need to lock1380 */1381 if (!pipe || pipe->top_pipe)1382 return;1383 1384 if (pipe->plane_state != NULL)1385 flip_immediate = pipe->plane_state->flip_immediate;1386 1387 if (pipe->stream_res.gsl_group > 0) {1388 temp_pipe = pipe->bottom_pipe;1389 while (!flip_immediate && temp_pipe) {1390 if (temp_pipe->plane_state != NULL)1391 flip_immediate = temp_pipe->plane_state->flip_immediate;1392 temp_pipe = temp_pipe->bottom_pipe;1393 }1394 }1395 1396 if (flip_immediate && lock) {1397 const int TIMEOUT_FOR_FLIP_PENDING_US = 100000;1398 unsigned int polling_interval_us = 1;1399 int i;1400 1401 temp_pipe = pipe;1402 while (temp_pipe) {1403 if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) {1404 for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) {1405 if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp))1406 break;1407 udelay(polling_interval_us);1408 }1409 1410 /* no reason it should take this long for immediate flips */1411 ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US);1412 }1413 temp_pipe = temp_pipe->bottom_pipe;1414 }1415 }1416 1417 /* In flip immediate and pipe splitting case, we need to use GSL1418 * for synchronization. Only do setup on locking and on flip type change.1419 */1420 if (lock && (pipe->bottom_pipe != NULL || !flip_immediate))1421 if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||1422 (!flip_immediate && pipe->stream_res.gsl_group > 0))1423 dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);1424 1425 if (pipe->plane_state != NULL)1426 flip_immediate = pipe->plane_state->flip_immediate;1427 1428 temp_pipe = pipe->bottom_pipe;1429 while (flip_immediate && temp_pipe) {1430 if (temp_pipe->plane_state != NULL)1431 flip_immediate = temp_pipe->plane_state->flip_immediate;1432 temp_pipe = temp_pipe->bottom_pipe;1433 }1434 1435 if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state &&1436 !flip_immediate)1437 dcn20_setup_gsl_group_as_lock(dc, pipe, false);1438 1439 if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) {1440 union dmub_hw_lock_flags hw_locks = { 0 };1441 struct dmub_hw_lock_inst_flags inst_flags = { 0 };1442 1443 hw_locks.bits.lock_pipe = 1;1444 inst_flags.otg_inst = pipe->stream_res.tg->inst;1445 1446 if (pipe->plane_state != NULL)1447 hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips;1448 1449 dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,1450 lock,1451 &hw_locks,1452 &inst_flags);1453 } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {1454 if (lock)1455 pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);1456 else1457 pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);1458 } else {1459 if (lock)1460 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);1461 else1462 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);1463 }1464}1465 1466static void dcn20_detect_pipe_changes(struct dc_state *old_state,1467 struct dc_state *new_state,1468 struct pipe_ctx *old_pipe,1469 struct pipe_ctx *new_pipe)1470{1471 bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM;1472 bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM;1473 1474 new_pipe->update_flags.raw = 0;1475 1476 /* If non-phantom pipe is being transitioned to a phantom pipe,1477 * set disable and return immediately. This is because the pipe1478 * that was previously in use must be fully disabled before we1479 * can "enable" it as a phantom pipe (since the OTG will certainly1480 * be different). The post_unlock sequence will set the correct1481 * update flags to enable the phantom pipe.1482 */1483 if (old_pipe->plane_state && !old_is_phantom &&1484 new_pipe->plane_state && new_is_phantom) {1485 new_pipe->update_flags.bits.disable = 1;1486 return;1487 }1488 1489 if (resource_is_pipe_type(new_pipe, OTG_MASTER) &&1490 resource_is_odm_topology_changed(new_pipe, old_pipe))1491 /* Detect odm changes */1492 new_pipe->update_flags.bits.odm = 1;1493 1494 /* Exit on unchanged, unused pipe */1495 if (!old_pipe->plane_state && !new_pipe->plane_state)1496 return;1497 /* Detect pipe enable/disable */1498 if (!old_pipe->plane_state && new_pipe->plane_state) {1499 new_pipe->update_flags.bits.enable = 1;1500 new_pipe->update_flags.bits.mpcc = 1;1501 new_pipe->update_flags.bits.dppclk = 1;1502 new_pipe->update_flags.bits.hubp_interdependent = 1;1503 new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;1504 new_pipe->update_flags.bits.unbounded_req = 1;1505 new_pipe->update_flags.bits.gamut_remap = 1;1506 new_pipe->update_flags.bits.scaler = 1;1507 new_pipe->update_flags.bits.viewport = 1;1508 new_pipe->update_flags.bits.det_size = 1;1509 if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE &&1510 new_pipe->stream_res.test_pattern_params.width != 0 &&1511 new_pipe->stream_res.test_pattern_params.height != 0)1512 new_pipe->update_flags.bits.test_pattern_changed = 1;1513 if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {1514 new_pipe->update_flags.bits.odm = 1;1515 new_pipe->update_flags.bits.global_sync = 1;1516 }1517 return;1518 }1519 1520 /* For SubVP we need to unconditionally enable because any phantom pipes are1521 * always removed then newly added for every full updates whenever SubVP is in use.1522 * The remove-add sequence of the phantom pipe always results in the pipe1523 * being blanked in enable_stream_timing (DPG).1524 */1525 if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)1526 new_pipe->update_flags.bits.enable = 1;1527 1528 /* Phantom pipes are effectively disabled, if the pipe was previously phantom1529 * we have to enable1530 */1531 if (old_pipe->plane_state && old_is_phantom &&1532 new_pipe->plane_state && !new_is_phantom)1533 new_pipe->update_flags.bits.enable = 1;1534 1535 if (old_pipe->plane_state && !new_pipe->plane_state) {1536 new_pipe->update_flags.bits.disable = 1;1537 return;1538 }1539 1540 /* Detect plane change */1541 if (old_pipe->plane_state != new_pipe->plane_state) {1542 new_pipe->update_flags.bits.plane_changed = true;1543 }1544 1545 /* Detect top pipe only changes */1546 if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {1547 /* Detect global sync changes */1548 if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset1549 || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start1550 || old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset1551 || old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width)1552 new_pipe->update_flags.bits.global_sync = 1;1553 }1554 1555 if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)1556 new_pipe->update_flags.bits.det_size = 1;1557 1558 /*1559 * Detect opp / tg change, only set on change, not on enable1560 * Assume mpcc inst = pipe index, if not this code needs to be updated1561 * since mpcc is what is affected by these. In fact all of our sequence1562 * makes this assumption at the moment with how hubp reset is matched to1563 * same index mpcc reset.1564 */1565 if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)1566 new_pipe->update_flags.bits.opp_changed = 1;1567 if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)1568 new_pipe->update_flags.bits.tg_changed = 1;1569 1570 /*1571 * Detect mpcc blending changes, only dpp inst and opp matter here,1572 * mpccs getting removed/inserted update connected ones during their own1573 * programming1574 */1575 if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp1576 || old_pipe->stream_res.opp != new_pipe->stream_res.opp)1577 new_pipe->update_flags.bits.mpcc = 1;1578 1579 /* Detect dppclk change */1580 if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)1581 new_pipe->update_flags.bits.dppclk = 1;1582 1583 /* Check for scl update */1584 if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))1585 new_pipe->update_flags.bits.scaler = 1;1586 /* Check for vp update */1587 if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))1588 || memcmp(&old_pipe->plane_res.scl_data.viewport_c,1589 &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))1590 new_pipe->update_flags.bits.viewport = 1;1591 1592 /* Detect dlg/ttu/rq updates */1593 {1594 struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs;1595 struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs;1596 struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs;1597 struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs;1598 1599 /* Detect pipe interdependent updates */1600 if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch ||1601 old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch ||1602 old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c ||1603 old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank ||1604 old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank ||1605 old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip ||1606 old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip ||1607 old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l ||1608 old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c ||1609 old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l ||1610 old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l ||1611 old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c ||1612 old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l ||1613 old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c ||1614 old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 ||1615 old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 ||1616 old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank ||1617 old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) {1618 old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch;1619 old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch;1620 old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c;1621 old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank;1622 old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank;1623 old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip;1624 old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip;1625 old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l;1626 old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c;1627 old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l;1628 old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l;1629 old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c;1630 old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l;1631 old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c;1632 old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0;1633 old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1;1634 old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank;1635 old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip;1636 new_pipe->update_flags.bits.hubp_interdependent = 1;1637 }1638 /* Detect any other updates to ttu/rq/dlg */1639 if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) ||1640 memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) ||1641 memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs)))1642 new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;1643 }1644 1645 if (old_pipe->unbounded_req != new_pipe->unbounded_req)1646 new_pipe->update_flags.bits.unbounded_req = 1;1647 1648 if (memcmp(&old_pipe->stream_res.test_pattern_params,1649 &new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) {1650 new_pipe->update_flags.bits.test_pattern_changed = 1;1651 }1652}1653 1654static void dcn20_update_dchubp_dpp(1655 struct dc *dc,1656 struct pipe_ctx *pipe_ctx,1657 struct dc_state *context)1658{1659 struct dce_hwseq *hws = dc->hwseq;1660 struct hubp *hubp = pipe_ctx->plane_res.hubp;1661 struct dpp *dpp = pipe_ctx->plane_res.dpp;1662 struct dc_plane_state *plane_state = pipe_ctx->plane_state;1663 struct dccg *dccg = dc->res_pool->dccg;1664 bool viewport_changed = false;1665 enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx);1666 1667 if (pipe_ctx->update_flags.bits.dppclk)1668 dpp->funcs->dpp_dppclk_control(dpp, false, true);1669 1670 if (pipe_ctx->update_flags.bits.enable)1671 dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);1672 1673 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG1674 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.1675 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG1676 */1677 if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {1678 hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);1679 1680 hubp->funcs->hubp_setup(1681 hubp,1682 &pipe_ctx->dlg_regs,1683 &pipe_ctx->ttu_regs,1684 &pipe_ctx->rq_regs,1685 &pipe_ctx->pipe_dlg_param);1686 }1687 1688 if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting)1689 hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req);1690 1691 if (pipe_ctx->update_flags.bits.hubp_interdependent)1692 hubp->funcs->hubp_setup_interdependent(1693 hubp,1694 &pipe_ctx->dlg_regs,1695 &pipe_ctx->ttu_regs);1696 1697 if (pipe_ctx->update_flags.bits.enable ||1698 pipe_ctx->update_flags.bits.plane_changed ||1699 plane_state->update_flags.bits.bpp_change ||1700 plane_state->update_flags.bits.input_csc_change ||1701 plane_state->update_flags.bits.color_space_change ||1702 plane_state->update_flags.bits.coeff_reduction_change) {1703 struct dc_bias_and_scale bns_params = plane_state->bias_and_scale;1704 1705 // program the input csc1706 dpp->funcs->dpp_setup(dpp,1707 plane_state->format,1708 EXPANSION_MODE_ZERO,1709 plane_state->input_csc_color_matrix,1710 plane_state->color_space,1711 NULL);1712 1713 if (dpp->funcs->set_cursor_matrix) {1714 dpp->funcs->set_cursor_matrix(dpp,1715 plane_state->color_space,1716 plane_state->cursor_csc_color_matrix);1717 }1718 if (dpp->funcs->dpp_program_bias_and_scale) {1719 //TODO :for CNVC set scale and bias registers if necessary1720 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);1721 }1722 }1723 1724 if (pipe_ctx->update_flags.bits.mpcc1725 || pipe_ctx->update_flags.bits.plane_changed1726 || plane_state->update_flags.bits.global_alpha_change1727 || plane_state->update_flags.bits.per_pixel_alpha_change) {1728 // MPCC inst is equal to pipe index in practice1729 hws->funcs.update_mpcc(dc, pipe_ctx);1730 }1731 1732 if (pipe_ctx->update_flags.bits.scaler ||1733 plane_state->update_flags.bits.scaling_change ||1734 plane_state->update_flags.bits.position_change ||1735 plane_state->update_flags.bits.clip_size_change ||1736 plane_state->update_flags.bits.per_pixel_alpha_change ||1737 pipe_ctx->stream->update_flags.bits.scaling) {1738 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;1739 ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);1740 /* scaler configuration */1741 pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(1742 pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);1743 }1744 1745 if (pipe_ctx->update_flags.bits.viewport ||1746 (context == dc->current_state && plane_state->update_flags.bits.position_change) ||1747 (context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||1748 (context == dc->current_state && plane_state->update_flags.bits.clip_size_change) ||1749 (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {1750 1751 hubp->funcs->mem_program_viewport(1752 hubp,1753 &pipe_ctx->plane_res.scl_data.viewport,1754 &pipe_ctx->plane_res.scl_data.viewport_c);1755 viewport_changed = true;1756 }1757 if (hubp->funcs->hubp_program_mcache_id_and_split_coordinate)1758 hubp->funcs->hubp_program_mcache_id_and_split_coordinate(1759 hubp,1760 &pipe_ctx->mcache_regs);1761 1762 /* Any updates are handled in dc interface, just need to apply existing for plane enable */1763 if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||1764 pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&1765 pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {1766 dc->hwss.set_cursor_attribute(pipe_ctx);1767 dc->hwss.set_cursor_position(pipe_ctx);1768 1769 if (dc->hwss.set_cursor_sdr_white_level)1770 dc->hwss.set_cursor_sdr_white_level(pipe_ctx);1771 }1772 1773 /* Any updates are handled in dc interface, just need1774 * to apply existing for plane enable / opp change */1775 if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed1776 || pipe_ctx->update_flags.bits.plane_changed1777 || pipe_ctx->stream->update_flags.bits.gamut_remap1778 || plane_state->update_flags.bits.gamut_remap_change1779 || pipe_ctx->stream->update_flags.bits.out_csc) {1780 /* dpp/cm gamut remap*/1781 dc->hwss.program_gamut_remap(pipe_ctx);1782 1783 /*call the dcn2 method which uses mpc csc*/1784 dc->hwss.program_output_csc(dc,1785 pipe_ctx,1786 pipe_ctx->stream->output_color_space,1787 pipe_ctx->stream->csc_color_matrix.matrix,1788 hubp->opp_id);1789 }1790 1791 if (pipe_ctx->update_flags.bits.enable ||1792 pipe_ctx->update_flags.bits.plane_changed ||1793 pipe_ctx->update_flags.bits.opp_changed ||1794 plane_state->update_flags.bits.pixel_format_change ||1795 plane_state->update_flags.bits.horizontal_mirror_change ||1796 plane_state->update_flags.bits.rotation_change ||1797 plane_state->update_flags.bits.swizzle_change ||1798 plane_state->update_flags.bits.dcc_change ||1799 plane_state->update_flags.bits.bpp_change ||1800 plane_state->update_flags.bits.scaling_change ||1801 plane_state->update_flags.bits.plane_size_change) {1802 struct plane_size size = plane_state->plane_size;1803 1804 size.surface_size = pipe_ctx->plane_res.scl_data.viewport;1805 hubp->funcs->hubp_program_surface_config(1806 hubp,1807 plane_state->format,1808 &plane_state->tiling_info,1809 &size,1810 plane_state->rotation,1811 &plane_state->dcc,1812 plane_state->horizontal_mirror,1813 0);1814 hubp->power_gated = false;1815 }1816 1817 if (pipe_ctx->update_flags.bits.enable ||1818 pipe_ctx->update_flags.bits.plane_changed ||1819 plane_state->update_flags.bits.addr_update) {1820 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) &&1821 pipe_mall_type == SUBVP_MAIN) {1822 union block_sequence_params params;1823 1824 params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;1825 params.subvp_save_surf_addr.addr = &pipe_ctx->plane_state->address;1826 params.subvp_save_surf_addr.subvp_index = pipe_ctx->subvp_index;1827 hwss_subvp_save_surf_addr(¶ms);1828 }1829 dc->hwss.update_plane_addr(dc, pipe_ctx);1830 }1831 1832 if (pipe_ctx->update_flags.bits.enable)1833 hubp->funcs->set_blank(hubp, false);1834 /* If the stream paired with this plane is phantom, the plane is also phantom */1835 if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable)1836 hubp->funcs->phantom_hubp_post_enable(hubp);1837}1838 1839static int calculate_vready_offset_for_group(struct pipe_ctx *pipe)1840{1841 struct pipe_ctx *other_pipe;1842 int vready_offset = pipe->pipe_dlg_param.vready_offset;1843 1844 /* Always use the largest vready_offset of all connected pipes */1845 for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {1846 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)1847 vready_offset = other_pipe->pipe_dlg_param.vready_offset;1848 }1849 for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {1850 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)1851 vready_offset = other_pipe->pipe_dlg_param.vready_offset;1852 }1853 for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {1854 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)1855 vready_offset = other_pipe->pipe_dlg_param.vready_offset;1856 }1857 for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {1858 if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)1859 vready_offset = other_pipe->pipe_dlg_param.vready_offset;1860 }1861 1862 return vready_offset;1863}1864 1865static void dcn20_program_pipe(1866 struct dc *dc,1867 struct pipe_ctx *pipe_ctx,1868 struct dc_state *context)1869{1870 struct dce_hwseq *hws = dc->hwseq;1871 1872 /* Only need to unblank on top pipe */1873 if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {1874 if (pipe_ctx->update_flags.bits.enable ||1875 pipe_ctx->update_flags.bits.odm ||1876 pipe_ctx->stream->update_flags.bits.abm_level)1877 hws->funcs.blank_pixel_data(dc, pipe_ctx,1878 !pipe_ctx->plane_state ||1879 !pipe_ctx->plane_state->visible);1880 }1881 1882 /* Only update TG on top pipe */1883 if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe1884 && !pipe_ctx->prev_odm_pipe) {1885 pipe_ctx->stream_res.tg->funcs->program_global_sync(1886 pipe_ctx->stream_res.tg,1887 calculate_vready_offset_for_group(pipe_ctx),1888 pipe_ctx->pipe_dlg_param.vstartup_start,1889 pipe_ctx->pipe_dlg_param.vupdate_offset,1890 pipe_ctx->pipe_dlg_param.vupdate_width,1891 pipe_ctx->pipe_dlg_param.pstate_keepout);1892 1893 if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)1894 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);1895 1896 pipe_ctx->stream_res.tg->funcs->set_vtg_params(1897 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);1898 1899 if (hws->funcs.setup_vupdate_interrupt)1900 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);1901 }1902 1903 if (pipe_ctx->update_flags.bits.odm)1904 hws->funcs.update_odm(dc, context, pipe_ctx);1905 1906 if (pipe_ctx->update_flags.bits.enable) {1907 if (hws->funcs.enable_plane)1908 hws->funcs.enable_plane(dc, pipe_ctx, context);1909 else1910 dcn20_enable_plane(dc, pipe_ctx, context);1911 1912 if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)1913 dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);1914 }1915 1916 if (pipe_ctx->update_flags.bits.det_size) {1917 if (dc->res_pool->hubbub->funcs->program_det_size)1918 dc->res_pool->hubbub->funcs->program_det_size(1919 dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);1920 1921 if (dc->res_pool->hubbub->funcs->program_det_segments)1922 dc->res_pool->hubbub->funcs->program_det_segments(1923 dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);1924 }1925 1926 if (pipe_ctx->update_flags.raw ||1927 (pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.raw) ||1928 pipe_ctx->stream->update_flags.raw)1929 dcn20_update_dchubp_dpp(dc, pipe_ctx, context);1930 1931 if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable ||1932 pipe_ctx->plane_state->update_flags.bits.hdr_mult))1933 hws->funcs.set_hdr_multiplier(pipe_ctx);1934 1935 if (hws->funcs.populate_mcm_luts) {1936 if (pipe_ctx->plane_state) {1937 hws->funcs.populate_mcm_luts(dc, pipe_ctx, pipe_ctx->plane_state->mcm_luts,1938 pipe_ctx->plane_state->lut_bank_a);1939 pipe_ctx->plane_state->lut_bank_a = !pipe_ctx->plane_state->lut_bank_a;1940 }1941 }1942 1943 if (pipe_ctx->plane_state &&1944 (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||1945 pipe_ctx->plane_state->update_flags.bits.gamma_change ||1946 pipe_ctx->plane_state->update_flags.bits.lut_3d ||1947 pipe_ctx->update_flags.bits.enable))1948 hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);1949 1950 /* dcn10_translate_regamma_to_hw_format takes 750us to finish1951 * only do gamma programming for powering on, internal memcmp to avoid1952 * updating on slave planes1953 */1954 if (pipe_ctx->update_flags.bits.enable ||1955 pipe_ctx->update_flags.bits.plane_changed ||1956 pipe_ctx->stream->update_flags.bits.out_tf ||1957 (pipe_ctx->plane_state &&1958 pipe_ctx->plane_state->update_flags.bits.output_tf_change))1959 hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);1960 1961 /* If the pipe has been enabled or has a different opp, we1962 * should reprogram the fmt. This deals with cases where1963 * interation between mpc and odm combine on different streams1964 * causes a different pipe to be chosen to odm combine with.1965 */1966 if (pipe_ctx->update_flags.bits.enable1967 || pipe_ctx->update_flags.bits.opp_changed) {1968 1969 pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(1970 pipe_ctx->stream_res.opp,1971 COLOR_SPACE_YCBCR601,1972 pipe_ctx->stream->timing.display_color_depth,1973 pipe_ctx->stream->signal);1974 1975 pipe_ctx->stream_res.opp->funcs->opp_program_fmt(1976 pipe_ctx->stream_res.opp,1977 &pipe_ctx->stream->bit_depth_params,1978 &pipe_ctx->stream->clamping);1979 }1980 1981 /* Set ABM pipe after other pipe configurations done */1982 if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) {1983 if (pipe_ctx->stream_res.abm) {1984 dc->hwss.set_pipe(pipe_ctx);1985 pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,1986 pipe_ctx->stream->abm_level);1987 }1988 }1989 1990 if (pipe_ctx->update_flags.bits.test_pattern_changed) {1991 struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;1992 struct bit_depth_reduction_params params;1993 1994 memset(¶ms, 0, sizeof(params));1995 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms);1996 dc->hwss.set_disp_pattern_generator(dc,1997 pipe_ctx,1998 pipe_ctx->stream_res.test_pattern_params.test_pattern,1999 pipe_ctx->stream_res.test_pattern_params.color_space,2000 pipe_ctx->stream_res.test_pattern_params.color_depth,2001 NULL,2002 pipe_ctx->stream_res.test_pattern_params.width,2003 pipe_ctx->stream_res.test_pattern_params.height,2004 pipe_ctx->stream_res.test_pattern_params.offset);2005 }2006}2007 2008void dcn20_program_front_end_for_ctx(2009 struct dc *dc,2010 struct dc_state *context)2011{2012 int i;2013 struct dce_hwseq *hws = dc->hwseq;2014 DC_LOGGER_INIT(dc->ctx->logger);2015 unsigned int prev_hubp_count = 0;2016 unsigned int hubp_count = 0;2017 struct pipe_ctx *pipe;2018 2019 if (resource_is_pipe_topology_changed(dc->current_state, context))2020 resource_log_pipe_topology_update(dc, context);2021 2022 if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {2023 for (i = 0; i < dc->res_pool->pipe_count; i++) {2024 pipe = &context->res_ctx.pipe_ctx[i];2025 2026 if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->plane_state) {2027 ASSERT(!pipe->plane_state->triplebuffer_flips);2028 /*turn off triple buffer for full update*/2029 dc->hwss.program_triplebuffer(2030 dc, pipe, pipe->plane_state->triplebuffer_flips);2031 }2032 }2033 }2034 2035 for (i = 0; i < dc->res_pool->pipe_count; i++) {2036 if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)2037 prev_hubp_count++;2038 if (context->res_ctx.pipe_ctx[i].plane_state)2039 hubp_count++;2040 }2041 2042 if (prev_hubp_count == 0 && hubp_count > 0) {2043 if (dc->res_pool->hubbub->funcs->force_pstate_change_control)2044 dc->res_pool->hubbub->funcs->force_pstate_change_control(2045 dc->res_pool->hubbub, true, false);2046 udelay(500);2047 }2048 2049 /* Set pipe update flags and lock pipes */2050 for (i = 0; i < dc->res_pool->pipe_count; i++)2051 dcn20_detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],2052 &context->res_ctx.pipe_ctx[i]);2053 2054 /* When disabling phantom pipes, turn on phantom OTG first (so we can get double2055 * buffer updates properly)2056 */2057 for (i = 0; i < dc->res_pool->pipe_count; i++) {2058 struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;2059 2060 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&2061 dc_state_get_pipe_subvp_type(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM) {2062 struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;2063 2064 if (tg->funcs->enable_crtc) {2065 if (dc->hwss.blank_phantom) {2066 int main_pipe_width = 0, main_pipe_height = 0;2067 struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(dc->current_state, dc->current_state->res_ctx.pipe_ctx[i].stream);2068 2069 if (phantom_stream) {2070 main_pipe_width = phantom_stream->dst.width;2071 main_pipe_height = phantom_stream->dst.height;2072 }2073 2074 dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height);2075 }2076 tg->funcs->enable_crtc(tg);2077 }2078 }2079 }2080 /* OTG blank before disabling all front ends */2081 for (i = 0; i < dc->res_pool->pipe_count; i++)2082 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable2083 && !context->res_ctx.pipe_ctx[i].top_pipe2084 && !context->res_ctx.pipe_ctx[i].prev_odm_pipe2085 && context->res_ctx.pipe_ctx[i].stream)2086 hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);2087 2088 /* Disconnect mpcc */2089 for (i = 0; i < dc->res_pool->pipe_count; i++)2090 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable2091 || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {2092 struct hubbub *hubbub = dc->res_pool->hubbub;2093 2094 /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom2095 * then we want to do the programming here (effectively it's being disabled). If we do2096 * the programming later the DET won't be updated until the OTG for the phantom pipe is2097 * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with2098 * DET allocation.2099 */2100 if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||2101 (context->res_ctx.pipe_ctx[i].plane_state && dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM))) {2102 if (hubbub->funcs->program_det_size)2103 hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);2104 if (dc->res_pool->hubbub->funcs->program_det_segments)2105 dc->res_pool->hubbub->funcs->program_det_segments(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);2106 }2107 hws->funcs.plane_atomic_disconnect(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);2108 DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);2109 }2110 2111 /* update ODM for blanked OTG master pipes */2112 for (i = 0; i < dc->res_pool->pipe_count; i++) {2113 pipe = &context->res_ctx.pipe_ctx[i];2114 if (resource_is_pipe_type(pipe, OTG_MASTER) &&2115 !resource_is_pipe_type(pipe, DPP_PIPE) &&2116 pipe->update_flags.bits.odm &&2117 hws->funcs.update_odm)2118 hws->funcs.update_odm(dc, context, pipe);2119 }2120 2121 /*2122 * Program all updated pipes, order matters for mpcc setup. Start with2123 * top pipe and program all pipes that follow in order2124 */2125 for (i = 0; i < dc->res_pool->pipe_count; i++) {2126 pipe = &context->res_ctx.pipe_ctx[i];2127 2128 if (pipe->plane_state && !pipe->top_pipe) {2129 while (pipe) {2130 if (hws->funcs.program_pipe)2131 hws->funcs.program_pipe(dc, pipe, context);2132 else {2133 /* Don't program phantom pipes in the regular front end programming sequence.2134 * There is an MPO transition case where a pipe being used by a video plane is2135 * transitioned directly to be a phantom pipe when closing the MPO video. However2136 * the phantom pipe will program a new HUBP_VTG_SEL (update takes place right away),2137 * but the MPO still exists until the double buffered update of the main pipe so we2138 * will get a frame of underflow if the phantom pipe is programmed here.2139 */2140 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)2141 dcn20_program_pipe(dc, pipe, context);2142 }2143 2144 pipe = pipe->bottom_pipe;2145 }2146 }2147 /* Program secondary blending tree and writeback pipes */2148 pipe = &context->res_ctx.pipe_ctx[i];2149 if (!pipe->top_pipe && !pipe->prev_odm_pipe2150 && pipe->stream && pipe->stream->num_wb_info > 02151 && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)2152 || pipe->stream->update_flags.raw)2153 && hws->funcs.program_all_writeback_pipes_in_tree)2154 hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);2155 2156 /* Avoid underflow by check of pipe line read when adding 2nd plane. */2157 if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&2158 !pipe->top_pipe &&2159 pipe->stream &&2160 pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&2161 dc->current_state->stream_status[0].plane_count == 1 &&2162 context->stream_status[0].plane_count > 1) {2163 pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);2164 }2165 }2166}2167 2168/* post_unlock_reset_opp - the function wait for corresponding double2169 * buffered pending status clear and reset opp head pipe's none double buffered2170 * registers to their initial state.2171 */2172static void post_unlock_reset_opp(struct dc *dc,2173 struct pipe_ctx *opp_head)2174{2175 struct display_stream_compressor *dsc = opp_head->stream_res.dsc;2176 struct dccg *dccg = dc->res_pool->dccg;2177 2178 /*2179 * wait for all DPP pipes in current mpc blending tree completes double2180 * buffered disconnection before resetting OPP2181 */2182 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, opp_head);2183 2184 if (dsc) {2185 bool is_dsc_ungated = false;2186 2187 if (dc->hwseq->funcs.dsc_pg_status)2188 is_dsc_ungated = dc->hwseq->funcs.dsc_pg_status(dc->hwseq, dsc->inst);2189 2190 if (is_dsc_ungated) {2191 /*2192 * seamless update specific where we will postpone non2193 * double buffered DSCCLK disable logic in post unlock2194 * sequence after DSC is disconnected from OPP but not2195 * yet power gated.2196 */2197 dsc->funcs->dsc_wait_disconnect_pending_clear(dsc);2198 dsc->funcs->dsc_disable(dsc);2199 if (dccg->funcs->set_ref_dscclk)2200 dccg->funcs->set_ref_dscclk(dccg, dsc->inst);2201 }2202 }2203}2204 2205void dcn20_post_unlock_program_front_end(2206 struct dc *dc,2207 struct dc_state *context)2208{2209 int i;2210 const unsigned int TIMEOUT_FOR_PIPE_ENABLE_US = 100000;2211 unsigned int polling_interval_us = 1;2212 struct dce_hwseq *hwseq = dc->hwseq;2213 2214 for (i = 0; i < dc->res_pool->pipe_count; i++)2215 if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&2216 !resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))2217 post_unlock_reset_opp(dc,2218 &dc->current_state->res_ctx.pipe_ctx[i]);2219 2220 for (i = 0; i < dc->res_pool->pipe_count; i++)2221 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)2222 dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);2223 2224 /*2225 * If we are enabling a pipe, we need to wait for pending clear as this is a critical2226 * part of the enable operation otherwise, DM may request an immediate flip which2227 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which2228 * is unsupported on DCN.2229 */2230 for (i = 0; i < dc->res_pool->pipe_count; i++) {2231 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];2232 // Don't check flip pending on phantom pipes2233 if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&2234 dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {2235 struct hubp *hubp = pipe->plane_res.hubp;2236 int j = 0;2237 for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us2238 && hubp->funcs->hubp_is_flip_pending(hubp); j++)2239 udelay(polling_interval_us);2240 }2241 }2242 2243 for (i = 0; i < dc->res_pool->pipe_count; i++) {2244 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];2245 struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];2246 2247 /* When going from a smaller ODM slice count to larger, we must ensure double2248 * buffer update completes before we return to ensure we don't reduce DISPCLK2249 * before we've transitioned to 2:1 or 4:12250 */2251 if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&2252 resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&2253 dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {2254 int j = 0;2255 struct timing_generator *tg = pipe->stream_res.tg;2256 2257 2258 if (tg->funcs->get_double_buffer_pending) {2259 for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us2260 && tg->funcs->get_double_buffer_pending(tg); j++)2261 udelay(polling_interval_us);2262 }2263 }2264 }2265 2266 if (dc->res_pool->hubbub->funcs->force_pstate_change_control)2267 dc->res_pool->hubbub->funcs->force_pstate_change_control(2268 dc->res_pool->hubbub, false, false);2269 2270 for (i = 0; i < dc->res_pool->pipe_count; i++) {2271 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];2272 2273 if (pipe->plane_state && !pipe->top_pipe) {2274 /* Program phantom pipe here to prevent a frame of underflow in the MPO transition2275 * case (if a pipe being used for a video plane transitions to a phantom pipe, it2276 * can underflow due to HUBP_VTG_SEL programming if done in the regular front end2277 * programming sequence).2278 */2279 while (pipe) {2280 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {2281 /* When turning on the phantom pipe we want to run through the2282 * entire enable sequence, so apply all the "enable" flags.2283 */2284 if (dc->hwss.apply_update_flags_for_phantom)2285 dc->hwss.apply_update_flags_for_phantom(pipe);2286 if (dc->hwss.update_phantom_vp_position)2287 dc->hwss.update_phantom_vp_position(dc, context, pipe);2288 dcn20_program_pipe(dc, pipe, context);2289 }2290 pipe = pipe->bottom_pipe;2291 }2292 }2293 }2294 2295 if (!hwseq)2296 return;2297 2298 /* P-State support transitions:2299 * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe2300 * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally)2301 * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe2302 * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe2303 * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes2304 */2305 if (hwseq->funcs.update_force_pstate)2306 dc->hwseq->funcs.update_force_pstate(dc, context);2307 2308 /* Only program the MALL registers after all the main and phantom pipes2309 * are done programming.2310 */2311 if (hwseq->funcs.program_mall_pipe_config)2312 hwseq->funcs.program_mall_pipe_config(dc, context);2313 2314 /* WA to apply WM setting*/2315 if (hwseq->wa.DEGVIDCN21)2316 dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);2317 2318 2319 /* WA for stutter underflow during MPO transitions when adding 2nd plane */2320 if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {2321 2322 if (dc->current_state->stream_status[0].plane_count == 1 &&2323 context->stream_status[0].plane_count > 1) {2324 2325 struct timing_generator *tg = dc->res_pool->timing_generators[0];2326 2327 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);2328 2329 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;2330 hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = tg->funcs->get_frame_count(tg);2331 }2332 }2333}2334 2335void dcn20_prepare_bandwidth(2336 struct dc *dc,2337 struct dc_state *context)2338{2339 struct hubbub *hubbub = dc->res_pool->hubbub;2340 unsigned int compbuf_size_kb = 0;2341 unsigned int cache_wm_a = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns;2342 unsigned int i;2343 2344 dc->clk_mgr->funcs->update_clocks(2345 dc->clk_mgr,2346 context,2347 false);2348 2349 for (i = 0; i < dc->res_pool->pipe_count; i++) {2350 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];2351 2352 // At optimize don't restore the original watermark value2353 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {2354 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U;2355 break;2356 }2357 }2358 2359 /* program dchubbub watermarks:2360 * For assigning wm_optimized_required, use |= operator since we don't want2361 * to clear the value if the optimize has not happened yet2362 */2363 dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub,2364 &context->bw_ctx.bw.dcn.watermarks,2365 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,2366 false);2367 2368 // Restore the real watermark so we can commit the value to DMCUB2369 // DMCUB uses the "original" watermark value in SubVP MCLK switch2370 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a;2371 2372 /* decrease compbuf size */2373 if (hubbub->funcs->program_compbuf_size) {2374 if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) {2375 compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes;2376 dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.dml.ip.min_comp_buffer_size_kbytes);2377 } else {2378 compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb;2379 dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.bw.dcn.compbuf_size_kb);2380 }2381 2382 hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false);2383 }2384}2385 2386void dcn20_optimize_bandwidth(2387 struct dc *dc,2388 struct dc_state *context)2389{2390 struct hubbub *hubbub = dc->res_pool->hubbub;2391 int i;2392 2393 for (i = 0; i < dc->res_pool->pipe_count; i++) {2394 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];2395 2396 // At optimize don't need to restore the original watermark value2397 if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {2398 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U;2399 break;2400 }2401 }2402 2403 /* program dchubbub watermarks */2404 hubbub->funcs->program_watermarks(hubbub,2405 &context->bw_ctx.bw.dcn.watermarks,2406 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,2407 true);2408 2409 if (dc->clk_mgr->dc_mode_softmax_enabled)2410 if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&2411 context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)2412 dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);2413 2414 /* increase compbuf size */2415 if (hubbub->funcs->program_compbuf_size)2416 hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);2417 2418 if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {2419 dc_dmub_srv_p_state_delegate(dc,2420 true, context);2421 context->bw_ctx.bw.dcn.clk.p_state_change_support = true;2422 dc->clk_mgr->clks.fw_based_mclk_switching = true;2423 } else {2424 dc->clk_mgr->clks.fw_based_mclk_switching = false;2425 }2426 2427 dc->clk_mgr->funcs->update_clocks(2428 dc->clk_mgr,2429 context,2430 true);2431 if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW &&2432 !dc->debug.disable_extblankadj) {2433 for (i = 0; i < dc->res_pool->pipe_count; ++i) {2434 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];2435 2436 if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank2437 && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max2438 && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)2439 pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,2440 pipe_ctx->dlg_regs.min_dst_y_next_start);2441 }2442 }2443}2444 2445bool dcn20_update_bandwidth(2446 struct dc *dc,2447 struct dc_state *context)2448{2449 int i;2450 struct dce_hwseq *hws = dc->hwseq;2451 2452 /* recalculate DML parameters */2453 if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false))2454 return false;2455 2456 /* apply updated bandwidth parameters */2457 dc->hwss.prepare_bandwidth(dc, context);2458 2459 /* update hubp configs for all pipes */2460 for (i = 0; i < dc->res_pool->pipe_count; i++) {2461 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];2462 2463 if (pipe_ctx->plane_state == NULL)2464 continue;2465 2466 if (pipe_ctx->top_pipe == NULL) {2467 bool blank = !is_pipe_tree_visible(pipe_ctx);2468 2469 pipe_ctx->stream_res.tg->funcs->program_global_sync(2470 pipe_ctx->stream_res.tg,2471 calculate_vready_offset_for_group(pipe_ctx),2472 pipe_ctx->pipe_dlg_param.vstartup_start,2473 pipe_ctx->pipe_dlg_param.vupdate_offset,2474 pipe_ctx->pipe_dlg_param.vupdate_width,2475 pipe_ctx->pipe_dlg_param.pstate_keepout);2476 2477 pipe_ctx->stream_res.tg->funcs->set_vtg_params(2478 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);2479 2480 if (pipe_ctx->prev_odm_pipe == NULL)2481 hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);2482 2483 if (hws->funcs.setup_vupdate_interrupt)2484 hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);2485 }2486 2487 pipe_ctx->plane_res.hubp->funcs->hubp_setup(2488 pipe_ctx->plane_res.hubp,2489 &pipe_ctx->dlg_regs,2490 &pipe_ctx->ttu_regs,2491 &pipe_ctx->rq_regs,2492 &pipe_ctx->pipe_dlg_param);2493 }2494 2495 return true;2496}2497 2498void dcn20_enable_writeback(2499 struct dc *dc,2500 struct dc_writeback_info *wb_info,2501 struct dc_state *context)2502{2503 struct dwbc *dwb;2504 struct mcif_wb *mcif_wb;2505 struct timing_generator *optc;2506 2507 ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);2508 ASSERT(wb_info->wb_enabled);2509 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];2510 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];2511 2512 /* set the OPTC source mux */2513 optc = dc->res_pool->timing_generators[dwb->otg_inst];2514 optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst);2515 /* set MCIF_WB buffer and arbitration configuration */2516 mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);2517 mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);2518 /* Enable MCIF_WB */2519 mcif_wb->funcs->enable_mcif(mcif_wb);2520 /* Enable DWB */2521 dwb->funcs->enable(dwb, &wb_info->dwb_params);2522 /* TODO: add sequence to enable/disable warmup */2523}2524 2525void dcn20_disable_writeback(2526 struct dc *dc,2527 unsigned int dwb_pipe_inst)2528{2529 struct dwbc *dwb;2530 struct mcif_wb *mcif_wb;2531 2532 ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);2533 dwb = dc->res_pool->dwbc[dwb_pipe_inst];2534 mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];2535 2536 dwb->funcs->disable(dwb);2537 mcif_wb->funcs->disable_mcif(mcif_wb);2538}2539 2540bool dcn20_wait_for_blank_complete(2541 struct output_pixel_processor *opp)2542{2543 int counter;2544 2545 if (!opp)2546 return false;2547 2548 for (counter = 0; counter < 1000; counter++) {2549 if (!opp->funcs->dpg_is_pending(opp))2550 break;2551 2552 udelay(100);2553 }2554 2555 if (counter == 1000) {2556 dm_error("DC: failed to blank crtc!\n");2557 return false;2558 }2559 2560 return opp->funcs->dpg_is_blanked(opp);2561}2562 2563bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)2564{2565 struct hubp *hubp = pipe_ctx->plane_res.hubp;2566 2567 if (!hubp)2568 return false;2569 return hubp->funcs->dmdata_status_done(hubp);2570}2571 2572void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)2573{2574 struct dce_hwseq *hws = dc->hwseq;2575 2576 if (pipe_ctx->stream_res.dsc) {2577 struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;2578 2579 hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);2580 while (odm_pipe) {2581 hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);2582 odm_pipe = odm_pipe->next_odm_pipe;2583 }2584 }2585}2586 2587void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)2588{2589 struct dce_hwseq *hws = dc->hwseq;2590 2591 if (pipe_ctx->stream_res.dsc) {2592 struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;2593 2594 hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);2595 while (odm_pipe) {2596 hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);2597 odm_pipe = odm_pipe->next_odm_pipe;2598 }2599 }2600}2601 2602void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)2603{2604 struct dc_dmdata_attributes attr = { 0 };2605 struct hubp *hubp = pipe_ctx->plane_res.hubp;2606 2607 attr.dmdata_mode = DMDATA_HW_MODE;2608 attr.dmdata_size =2609 dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;2610 attr.address.quad_part =2611 pipe_ctx->stream->dmdata_address.quad_part;2612 attr.dmdata_dl_delta = 0;2613 attr.dmdata_qos_mode = 0;2614 attr.dmdata_qos_level = 0;2615 attr.dmdata_repeat = 1; /* always repeat */2616 attr.dmdata_updated = 1;2617 attr.dmdata_sw_data = NULL;2618 2619 hubp->funcs->dmdata_set_attributes(hubp, &attr);2620}2621 2622void dcn20_init_vm_ctx(2623 struct dce_hwseq *hws,2624 struct dc *dc,2625 struct dc_virtual_addr_space_config *va_config,2626 int vmid)2627{2628 struct dcn_hubbub_virt_addr_config config;2629 2630 if (vmid == 0) {2631 ASSERT(0); /* VMID cannot be 0 for vm context */2632 return;2633 }2634 2635 config.page_table_start_addr = va_config->page_table_start_addr;2636 config.page_table_end_addr = va_config->page_table_end_addr;2637 config.page_table_block_size = va_config->page_table_block_size_in_bytes;2638 config.page_table_depth = va_config->page_table_depth;2639 config.page_table_base_addr = va_config->page_table_base_addr;2640 2641 dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid);2642}2643 2644int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)2645{2646 struct dcn_hubbub_phys_addr_config config;2647 2648 config.system_aperture.fb_top = pa_config->system_aperture.fb_top;2649 config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset;2650 config.system_aperture.fb_base = pa_config->system_aperture.fb_base;2651 config.system_aperture.agp_top = pa_config->system_aperture.agp_top;2652 config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot;2653 config.system_aperture.agp_base = pa_config->system_aperture.agp_base;2654 config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr;2655 config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr;2656 config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;2657 config.page_table_default_page_addr = pa_config->page_table_default_page_addr;2658 2659 return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config);2660}2661 2662static bool patch_address_for_sbs_tb_stereo(2663 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)2664{2665 struct dc_plane_state *plane_state = pipe_ctx->plane_state;2666 bool sec_split = pipe_ctx->top_pipe &&2667 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;2668 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&2669 (pipe_ctx->stream->timing.timing_3d_format ==2670 TIMING_3D_FORMAT_SIDE_BY_SIDE ||2671 pipe_ctx->stream->timing.timing_3d_format ==2672 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {2673 *addr = plane_state->address.grph_stereo.left_addr;2674 plane_state->address.grph_stereo.left_addr =2675 plane_state->address.grph_stereo.right_addr;2676 return true;2677 }2678 2679 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&2680 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {2681 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;2682 plane_state->address.grph_stereo.right_addr =2683 plane_state->address.grph_stereo.left_addr;2684 plane_state->address.grph_stereo.right_meta_addr =2685 plane_state->address.grph_stereo.left_meta_addr;2686 }2687 return false;2688}2689 2690void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)2691{2692 bool addr_patched = false;2693 PHYSICAL_ADDRESS_LOC addr;2694 struct dc_plane_state *plane_state = pipe_ctx->plane_state;2695 2696 if (plane_state == NULL)2697 return;2698 2699 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);2700 2701 // Call Helper to track VMID use2702 vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst);2703 2704 pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(2705 pipe_ctx->plane_res.hubp,2706 &plane_state->address,2707 plane_state->flip_immediate);2708 2709 plane_state->status.requested_address = plane_state->address;2710 2711 if (plane_state->flip_immediate)2712 plane_state->status.current_address = plane_state->address;2713 2714 if (addr_patched)2715 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;2716}2717 2718void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,2719 struct dc_link_settings *link_settings)2720{2721 struct encoder_unblank_param params = {0};2722 struct dc_stream_state *stream = pipe_ctx->stream;2723 struct dc_link *link = stream->link;2724 struct dce_hwseq *hws = link->dc->hwseq;2725 struct pipe_ctx *odm_pipe;2726 bool is_two_pixels_per_container =2727 pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);2728 2729 params.opp_cnt = 1;2730 2731 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {2732 params.opp_cnt++;2733 }2734 /* only 3 items below are used by unblank */2735 params.timing = pipe_ctx->stream->timing;2736 2737 params.link_settings.link_rate = link_settings->link_rate;2738 2739 if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {2740 /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */2741 pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(2742 pipe_ctx->stream_res.hpo_dp_stream_enc,2743 pipe_ctx->stream_res.tg->inst);2744 } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {2745 if (is_two_pixels_per_container || params.opp_cnt > 1)2746 params.timing.pix_clk_100hz /= 2;2747 pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(2748 pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);2749 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);2750 }2751 2752 if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {2753 hws->funcs.edp_backlight_control(link, true);2754 }2755}2756 2757void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)2758{2759 struct timing_generator *tg = pipe_ctx->stream_res.tg;2760 int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);2761 2762 if (start_line < 0)2763 start_line = 0;2764 2765 if (tg->funcs->setup_vertical_interrupt2)2766 tg->funcs->setup_vertical_interrupt2(tg, start_line);2767}2768 2769void dcn20_reset_back_end_for_pipe(2770 struct dc *dc,2771 struct pipe_ctx *pipe_ctx,2772 struct dc_state *context)2773{2774 int i;2775 struct dc_link *link = pipe_ctx->stream->link;2776 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);2777 2778 DC_LOGGER_INIT(dc->ctx->logger);2779 if (pipe_ctx->stream_res.stream_enc == NULL) {2780 pipe_ctx->stream = NULL;2781 return;2782 }2783 2784 /* DPMS may already disable or */2785 /* dpms_off status is incorrect due to fastboot2786 * feature. When system resume from S4 with second2787 * screen only, the dpms_off would be true but2788 * VBIOS lit up eDP, so check link status too.2789 */2790 if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)2791 dc->link_srv->set_dpms_off(pipe_ctx);2792 else if (pipe_ctx->stream_res.audio)2793 dc->hwss.disable_audio_stream(pipe_ctx);2794 2795 /* free acquired resources */2796 if (pipe_ctx->stream_res.audio) {2797 /*disable az_endpoint*/2798 pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);2799 2800 /*free audio*/2801 if (dc->caps.dynamic_audio == true) {2802 /*we have to dynamic arbitrate the audio endpoints*/2803 /*we free the resource, need reset is_audio_acquired*/2804 update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,2805 pipe_ctx->stream_res.audio, false);2806 pipe_ctx->stream_res.audio = NULL;2807 }2808 }2809 2810 /* by upper caller loop, parent pipe: pipe0, will be reset last.2811 * back end share by all pipes and will be disable only when disable2812 * parent pipe.2813 */2814 if (pipe_ctx->top_pipe == NULL) {2815 2816 dc->hwss.set_abm_immediate_disable(pipe_ctx);2817 2818 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);2819 2820 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);2821 if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)2822 pipe_ctx->stream_res.tg->funcs->set_odm_bypass(2823 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);2824 2825 if (pipe_ctx->stream_res.tg->funcs->set_drr)2826 pipe_ctx->stream_res.tg->funcs->set_drr(2827 pipe_ctx->stream_res.tg, NULL);2828 /* TODO - convert symclk_ref_cnts for otg to a bit map to solve2829 * the case where the same symclk is shared across multiple otg2830 * instances2831 */2832 if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))2833 link->phy_state.symclk_ref_cnts.otg = 0;2834 if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {2835 link_hwss->disable_link_output(link,2836 &pipe_ctx->link_res, pipe_ctx->stream->signal);2837 link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;2838 }2839 }2840 2841 for (i = 0; i < dc->res_pool->pipe_count; i++)2842 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)2843 break;2844 2845 if (i == dc->res_pool->pipe_count)2846 return;2847 2848/*2849 * In case of a dangling plane, setting this to NULL unconditionally2850 * causes failures during reset hw ctx where, if stream is NULL,2851 * it is expected that the pipe_ctx pointers to pipes and plane are NULL.2852 */2853 pipe_ctx->stream = NULL;2854 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",2855 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);2856}2857 2858void dcn20_reset_hw_ctx_wrap(2859 struct dc *dc,2860 struct dc_state *context)2861{2862 int i;2863 struct dce_hwseq *hws = dc->hwseq;2864 2865 /* Reset Back End*/2866 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {2867 struct pipe_ctx *pipe_ctx_old =2868 &dc->current_state->res_ctx.pipe_ctx[i];2869 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];2870 2871 if (!pipe_ctx_old->stream)2872 continue;2873 2874 if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)2875 continue;2876 2877 if (!pipe_ctx->stream ||2878 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {2879 struct clock_source *old_clk = pipe_ctx_old->clock_source;2880 2881 dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);2882 if (hws->funcs.enable_stream_gating)2883 hws->funcs.enable_stream_gating(dc, pipe_ctx_old);2884 if (old_clk)2885 old_clk->funcs->cs_power_down(old_clk);2886 }2887 }2888}2889 2890void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)2891{2892 struct hubp *hubp = pipe_ctx->plane_res.hubp;2893 struct mpcc_blnd_cfg blnd_cfg = {0};2894 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;2895 int mpcc_id;2896 struct mpcc *new_mpcc;2897 struct mpc *mpc = dc->res_pool->mpc;2898 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);2899 2900 blnd_cfg.overlap_only = false;2901 blnd_cfg.global_gain = 0xff;2902 2903 if (per_pixel_alpha) {2904 blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;2905 if (pipe_ctx->plane_state->global_alpha) {2906 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;2907 blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;2908 } else {2909 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;2910 }2911 } else {2912 blnd_cfg.pre_multiplied_alpha = false;2913 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;2914 }2915 2916 if (pipe_ctx->plane_state->global_alpha)2917 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;2918 else2919 blnd_cfg.global_alpha = 0xff;2920 2921 blnd_cfg.background_color_bpc = 4;2922 blnd_cfg.bottom_gain_mode = 0;2923 blnd_cfg.top_gain = 0x1f000;2924 blnd_cfg.bottom_inside_gain = 0x1f000;2925 blnd_cfg.bottom_outside_gain = 0x1f000;2926 2927 if (pipe_ctx->plane_state->format2928 == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)2929 blnd_cfg.pre_multiplied_alpha = false;2930 2931 /*2932 * TODO: remove hack2933 * Note: currently there is a bug in init_hw such that2934 * on resume from hibernate, BIOS sets up MPCC0, and2935 * we do mpcc_remove but the mpcc cannot go to idle2936 * after remove. This cause us to pick mpcc1 here,2937 * which causes a pstate hang for yet unknown reason.2938 */2939 mpcc_id = hubp->inst;2940 2941 /* If there is no full update, don't need to touch MPC tree*/2942 if (!pipe_ctx->plane_state->update_flags.bits.full_update &&2943 !pipe_ctx->update_flags.bits.mpcc) {2944 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);2945 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);2946 return;2947 }2948 2949 /* check if this MPCC is already being used */2950 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);2951 /* remove MPCC if being used */2952 if (new_mpcc != NULL)2953 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);2954 else2955 if (dc->debug.sanity_checks)2956 mpc->funcs->assert_mpcc_idle_before_connect(2957 dc->res_pool->mpc, mpcc_id);2958 2959 /* Call MPC to insert new plane */2960 new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,2961 mpc_tree_params,2962 &blnd_cfg,2963 NULL,2964 NULL,2965 hubp->inst,2966 mpcc_id);2967 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);2968 2969 ASSERT(new_mpcc != NULL);2970 hubp->opp_id = pipe_ctx->stream_res.opp->inst;2971 hubp->mpcc_id = mpcc_id;2972}2973 2974void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)2975{2976 enum dc_lane_count lane_count =2977 pipe_ctx->stream->link->cur_link_settings.lane_count;2978 2979 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;2980 struct dc_link *link = pipe_ctx->stream->link;2981 2982 uint32_t active_total_with_borders;2983 uint32_t early_control = 0;2984 struct timing_generator *tg = pipe_ctx->stream_res.tg;2985 const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);2986 struct dc *dc = pipe_ctx->stream->ctx->dc;2987 struct dtbclk_dto_params dto_params = {0};2988 struct dccg *dccg = dc->res_pool->dccg;2989 enum phyd32clk_clock_source phyd32clk;2990 int dp_hpo_inst;2991 2992 struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);2993 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;2994 2995 if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {2996 dto_params.otg_inst = tg->inst;2997 dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;2998 dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);2999 dto_params.timing = &pipe_ctx->stream->timing;3000 dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);3001 dccg->funcs->set_dtbclk_dto(dccg, &dto_params);3002 dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;3003 dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst);3004 3005 phyd32clk = get_phyd32clk_src(link);3006 dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);3007 } else {3008 if (dccg->funcs->enable_symclk_se)3009 dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,3010 link_enc->transmitter - TRANSMITTER_UNIPHY_A);3011 }3012 3013 if (dc->res_pool->dccg->funcs->set_pixel_rate_div)3014 dc->res_pool->dccg->funcs->set_pixel_rate_div(3015 dc->res_pool->dccg,3016 pipe_ctx->stream_res.tg->inst,3017 pipe_ctx->pixel_rate_divider.div_factor1,3018 pipe_ctx->pixel_rate_divider.div_factor2);3019 3020 link_hwss->setup_stream_encoder(pipe_ctx);3021 3022 if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {3023 if (dc->hwss.program_dmdata_engine)3024 dc->hwss.program_dmdata_engine(pipe_ctx);3025 }3026 3027 dc->hwss.update_info_frame(pipe_ctx);3028 3029 if (dc_is_dp_signal(pipe_ctx->stream->signal))3030 dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);3031 3032 /* enable early control to avoid corruption on DP monitor*/3033 active_total_with_borders =3034 timing->h_addressable3035 + timing->h_border_left3036 + timing->h_border_right;3037 3038 if (lane_count != 0)3039 early_control = active_total_with_borders % lane_count;3040 3041 if (early_control == 0)3042 early_control = lane_count;3043 3044 tg->funcs->set_early_control(tg, early_control);3045}3046 3047void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx)3048{3049 struct dc_stream_state *stream = pipe_ctx->stream;3050 struct hubp *hubp = pipe_ctx->plane_res.hubp;3051 bool enable = false;3052 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;3053 enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal)3054 ? dmdata_dp3055 : dmdata_hdmi;3056 3057 /* if using dynamic meta, don't set up generic infopackets */3058 if (pipe_ctx->stream->dmdata_address.quad_part != 0) {3059 pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;3060 enable = true;3061 }3062 3063 if (!hubp)3064 return;3065 3066 if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)3067 return;3068 3069 stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,3070 hubp->inst, mode);3071}3072 3073void dcn20_fpga_init_hw(struct dc *dc)3074{3075 int i, j;3076 struct dce_hwseq *hws = dc->hwseq;3077 struct resource_pool *res_pool = dc->res_pool;3078 struct dc_state *context = dc->current_state;3079 3080 if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)3081 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);3082 3083 // Initialize the dccg3084 if (res_pool->dccg->funcs->dccg_init)3085 res_pool->dccg->funcs->dccg_init(res_pool->dccg);3086 3087 //Enable ability to power gate / don't force power on permanently3088 hws->funcs.enable_power_gating_plane(hws, true);3089 3090 // Specific to FPGA dccg and registers3091 REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);3092 REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);3093 3094 hws->funcs.dccg_init(hws);3095 3096 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);3097 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);3098 if (REG(REFCLK_CNTL))3099 REG_WRITE(REFCLK_CNTL, 0);3100 //3101 3102 3103 /* Blank pixel data with OPP DPG */3104 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {3105 struct timing_generator *tg = dc->res_pool->timing_generators[i];3106 3107 if (tg->funcs->is_tg_enabled(tg))3108 dcn20_init_blank(dc, tg);3109 }3110 3111 for (i = 0; i < res_pool->timing_generator_count; i++) {3112 struct timing_generator *tg = dc->res_pool->timing_generators[i];3113 3114 if (tg->funcs->is_tg_enabled(tg))3115 tg->funcs->lock(tg);3116 }3117 3118 for (i = 0; i < dc->res_pool->pipe_count; i++) {3119 struct dpp *dpp = res_pool->dpps[i];3120 3121 dpp->funcs->dpp_reset(dpp);3122 }3123 3124 /* Reset all MPCC muxes */3125 res_pool->mpc->funcs->mpc_init(res_pool->mpc);3126 3127 /* initialize OPP mpc_tree parameter */3128 for (i = 0; i < dc->res_pool->pipe_count; i++) {3129 res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;3130 res_pool->opps[i]->mpc_tree_params.opp_list = NULL;3131 for (j = 0; j < MAX_PIPES; j++)3132 res_pool->opps[i]->mpcc_disconnect_pending[j] = false;3133 }3134 3135 for (i = 0; i < dc->res_pool->pipe_count; i++) {3136 struct timing_generator *tg = dc->res_pool->timing_generators[i];3137 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];3138 struct hubp *hubp = dc->res_pool->hubps[i];3139 struct dpp *dpp = dc->res_pool->dpps[i];3140 3141 pipe_ctx->stream_res.tg = tg;3142 pipe_ctx->pipe_idx = i;3143 3144 pipe_ctx->plane_res.hubp = hubp;3145 pipe_ctx->plane_res.dpp = dpp;3146 pipe_ctx->plane_res.mpcc_inst = dpp->inst;3147 hubp->mpcc_id = dpp->inst;3148 hubp->opp_id = OPP_ID_INVALID;3149 hubp->power_gated = false;3150 pipe_ctx->stream_res.opp = NULL;3151 3152 hubp->funcs->hubp_init(hubp);3153 3154 //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;3155 //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;3156 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;3157 pipe_ctx->stream_res.opp = dc->res_pool->opps[i];3158 /*to do*/3159 hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);3160 }3161 3162 /* initialize DWB pointer to MCIF_WB */3163 for (i = 0; i < res_pool->res_cap->num_dwb; i++)3164 res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];3165 3166 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {3167 struct timing_generator *tg = dc->res_pool->timing_generators[i];3168 3169 if (tg->funcs->is_tg_enabled(tg))3170 tg->funcs->unlock(tg);3171 }3172 3173 for (i = 0; i < dc->res_pool->pipe_count; i++) {3174 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];3175 3176 dc->hwss.disable_plane(dc, context, pipe_ctx);3177 3178 pipe_ctx->stream_res.tg = NULL;3179 pipe_ctx->plane_res.hubp = NULL;3180 }3181 3182 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {3183 struct timing_generator *tg = dc->res_pool->timing_generators[i];3184 3185 tg->funcs->tg_init(tg);3186 }3187 3188 if (dc->res_pool->hubbub->funcs->init_crb)3189 dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);3190}3191 3192void dcn20_set_disp_pattern_generator(const struct dc *dc,3193 struct pipe_ctx *pipe_ctx,3194 enum controller_dp_test_pattern test_pattern,3195 enum controller_dp_color_space color_space,3196 enum dc_color_depth color_depth,3197 const struct tg_color *solid_color,3198 int width, int height, int offset)3199{3200 pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern,3201 color_space, color_depth, solid_color, width, height, offset);3202}3203