1 /* 2 * Copyright 2016 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * 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 OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 #include <linux/delay.h> 26 27 #include "dm_services.h" 28 #include "dm_helpers.h" 29 #include "core_types.h" 30 #include "resource.h" 31 #include "dcn20/dcn20_resource.h" 32 #include "dce110/dce110_hw_sequencer.h" 33 #include "dcn10/dcn10_hw_sequencer.h" 34 #include "dcn20_hwseq.h" 35 #include "dce/dce_hwseq.h" 36 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 37 #include "dcn20/dcn20_dsc.h" 38 #endif 39 #include "abm.h" 40 #include "clk_mgr.h" 41 #include "dmcu.h" 42 #include "hubp.h" 43 #include "timing_generator.h" 44 #include "opp.h" 45 #include "ipp.h" 46 #include "mpc.h" 47 #include "mcif_wb.h" 48 #include "reg_helper.h" 49 #include "dcn10/dcn10_cm_common.h" 50 #include "dcn10/dcn10_hubbub.h" 51 #include "dcn10/dcn10_optc.h" 52 #include "dc_link_dp.h" 53 #include "vm_helper.h" 54 #include "dccg.h" 55 56 #define DC_LOGGER_INIT(logger) 57 58 #define CTX \ 59 hws->ctx 60 #define REG(reg)\ 61 hws->regs->reg 62 63 #undef FN 64 #define FN(reg_name, field_name) \ 65 hws->shifts->field_name, hws->masks->field_name 66 67 static void bios_golden_init(struct dc *dc) 68 { 69 struct dc_bios *bp = dc->ctx->dc_bios; 70 int i; 71 72 /* initialize dcn global */ 73 bp->funcs->enable_disp_power_gating(bp, 74 CONTROLLER_ID_D0, ASIC_PIPE_INIT); 75 76 for (i = 0; i < dc->res_pool->pipe_count; i++) { 77 /* initialize dcn per pipe */ 78 bp->funcs->enable_disp_power_gating(bp, 79 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); 80 } 81 } 82 83 static void enable_power_gating_plane( 84 struct dce_hwseq *hws, 85 bool enable) 86 { 87 bool force_on = 1; /* disable power gating */ 88 89 if (enable) 90 force_on = 0; 91 92 /* DCHUBP0/1/2/3/4/5 */ 93 REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); 94 REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); 95 REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); 96 REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); 97 if (REG(DOMAIN8_PG_CONFIG)) 98 REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); 99 if (REG(DOMAIN10_PG_CONFIG)) 100 REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); 101 102 /* DPP0/1/2/3/4/5 */ 103 REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); 104 REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); 105 REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); 106 REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); 107 if (REG(DOMAIN9_PG_CONFIG)) 108 REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); 109 if (REG(DOMAIN11_PG_CONFIG)) 110 REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); 111 112 /* DCS0/1/2/3/4/5 */ 113 REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on); 114 REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on); 115 REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on); 116 if (REG(DOMAIN19_PG_CONFIG)) 117 REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); 118 if (REG(DOMAIN20_PG_CONFIG)) 119 REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); 120 if (REG(DOMAIN21_PG_CONFIG)) 121 REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); 122 } 123 124 void dcn20_dccg_init(struct dce_hwseq *hws) 125 { 126 /* 127 * set MICROSECOND_TIME_BASE_DIV 128 * 100Mhz refclk -> 0x120264 129 * 27Mhz refclk -> 0x12021b 130 * 48Mhz refclk -> 0x120230 131 * 132 */ 133 REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264); 134 135 /* 136 * set MILLISECOND_TIME_BASE_DIV 137 * 100Mhz refclk -> 0x1186a0 138 * 27Mhz refclk -> 0x106978 139 * 48Mhz refclk -> 0x10bb80 140 * 141 */ 142 REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0); 143 144 /* This value is dependent on the hardware pipeline delay so set once per SOC */ 145 REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c); 146 } 147 void dcn20_display_init(struct dc *dc) 148 { 149 struct dce_hwseq *hws = dc->hwseq; 150 151 /* RBBMIF 152 * disable RBBMIF timeout detection for all clients 153 * Ensure RBBMIF does not drop register accesses due to the per-client timeout 154 */ 155 REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); 156 REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); 157 158 /* DCCG */ 159 dcn20_dccg_init(hws); 160 161 /* Disable all memory low power mode. All memories are enabled. */ 162 REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 1); 163 164 /* DCHUB/MMHUBBUB 165 * set global timer refclk divider 166 * 100Mhz refclk -> 2 167 * 27Mhz refclk -> 1 168 * 48Mhz refclk -> 1 169 */ 170 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); 171 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); 172 REG_WRITE(REFCLK_CNTL, 0); 173 174 /* OPTC 175 * OTG_CONTROL.OTG_DISABLE_POINT_CNTL = 0x3; will be set during optc2_enable_crtc 176 */ 177 178 /* AZ 179 * default value is 0x64 for 100Mhz ref clock, if the ref clock is 100Mhz, no need to program this regiser, 180 * if not, it should be programmed according to the ref clock 181 */ 182 REG_UPDATE(AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, 0x64); 183 /* Enable controller clock gating */ 184 REG_WRITE(AZALIA_CONTROLLER_CLOCK_GATING, 0x1); 185 } 186 187 static void disable_vga( 188 struct dce_hwseq *hws) 189 { 190 REG_WRITE(D1VGA_CONTROL, 0); 191 REG_WRITE(D2VGA_CONTROL, 0); 192 REG_WRITE(D3VGA_CONTROL, 0); 193 REG_WRITE(D4VGA_CONTROL, 0); 194 REG_WRITE(D5VGA_CONTROL, 0); 195 REG_WRITE(D6VGA_CONTROL, 0); 196 } 197 198 void dcn20_program_tripleBuffer( 199 const struct dc *dc, 200 struct pipe_ctx *pipe_ctx, 201 bool enableTripleBuffer) 202 { 203 if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { 204 pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( 205 pipe_ctx->plane_res.hubp, 206 enableTripleBuffer); 207 } 208 } 209 210 /* Blank pixel data during initialization */ 211 void dcn20_init_blank( 212 struct dc *dc, 213 struct timing_generator *tg) 214 { 215 enum dc_color_space color_space; 216 struct tg_color black_color = {0}; 217 struct output_pixel_processor *opp = NULL; 218 struct output_pixel_processor *bottom_opp = NULL; 219 uint32_t num_opps, opp_id_src0, opp_id_src1; 220 uint32_t otg_active_width, otg_active_height; 221 222 /* program opp dpg blank color */ 223 color_space = COLOR_SPACE_SRGB; 224 color_space_to_black_color(dc, color_space, &black_color); 225 226 /* get the OTG active size */ 227 tg->funcs->get_otg_active_size(tg, 228 &otg_active_width, 229 &otg_active_height); 230 231 /* get the OPTC source */ 232 tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); 233 ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); 234 opp = dc->res_pool->opps[opp_id_src0]; 235 236 if (num_opps == 2) { 237 otg_active_width = otg_active_width / 2; 238 ASSERT(opp_id_src1 < dc->res_pool->res_cap->num_opp); 239 bottom_opp = dc->res_pool->opps[opp_id_src1]; 240 } 241 242 opp->funcs->opp_set_disp_pattern_generator( 243 opp, 244 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, 245 COLOR_DEPTH_UNDEFINED, 246 &black_color, 247 otg_active_width, 248 otg_active_height); 249 250 if (num_opps == 2) { 251 bottom_opp->funcs->opp_set_disp_pattern_generator( 252 bottom_opp, 253 CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, 254 COLOR_DEPTH_UNDEFINED, 255 &black_color, 256 otg_active_width, 257 otg_active_height); 258 } 259 260 dcn20_hwss_wait_for_blank_complete(opp); 261 } 262 263 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 264 static void dcn20_dsc_pg_control( 265 struct dce_hwseq *hws, 266 unsigned int dsc_inst, 267 bool power_on) 268 { 269 uint32_t power_gate = power_on ? 0 : 1; 270 uint32_t pwr_status = power_on ? 0 : 2; 271 uint32_t org_ip_request_cntl = 0; 272 273 if (hws->ctx->dc->debug.disable_dsc_power_gate) 274 return; 275 276 if (REG(DOMAIN16_PG_CONFIG) == 0) 277 return; 278 279 REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); 280 if (org_ip_request_cntl == 0) 281 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); 282 283 switch (dsc_inst) { 284 case 0: /* DSC0 */ 285 REG_UPDATE(DOMAIN16_PG_CONFIG, 286 DOMAIN16_POWER_GATE, power_gate); 287 288 REG_WAIT(DOMAIN16_PG_STATUS, 289 DOMAIN16_PGFSM_PWR_STATUS, pwr_status, 290 1, 1000); 291 break; 292 case 1: /* DSC1 */ 293 REG_UPDATE(DOMAIN17_PG_CONFIG, 294 DOMAIN17_POWER_GATE, power_gate); 295 296 REG_WAIT(DOMAIN17_PG_STATUS, 297 DOMAIN17_PGFSM_PWR_STATUS, pwr_status, 298 1, 1000); 299 break; 300 case 2: /* DSC2 */ 301 REG_UPDATE(DOMAIN18_PG_CONFIG, 302 DOMAIN18_POWER_GATE, power_gate); 303 304 REG_WAIT(DOMAIN18_PG_STATUS, 305 DOMAIN18_PGFSM_PWR_STATUS, pwr_status, 306 1, 1000); 307 break; 308 case 3: /* DSC3 */ 309 REG_UPDATE(DOMAIN19_PG_CONFIG, 310 DOMAIN19_POWER_GATE, power_gate); 311 312 REG_WAIT(DOMAIN19_PG_STATUS, 313 DOMAIN19_PGFSM_PWR_STATUS, pwr_status, 314 1, 1000); 315 break; 316 case 4: /* DSC4 */ 317 REG_UPDATE(DOMAIN20_PG_CONFIG, 318 DOMAIN20_POWER_GATE, power_gate); 319 320 REG_WAIT(DOMAIN20_PG_STATUS, 321 DOMAIN20_PGFSM_PWR_STATUS, pwr_status, 322 1, 1000); 323 break; 324 case 5: /* DSC5 */ 325 REG_UPDATE(DOMAIN21_PG_CONFIG, 326 DOMAIN21_POWER_GATE, power_gate); 327 328 REG_WAIT(DOMAIN21_PG_STATUS, 329 DOMAIN21_PGFSM_PWR_STATUS, pwr_status, 330 1, 1000); 331 break; 332 default: 333 BREAK_TO_DEBUGGER(); 334 break; 335 } 336 337 if (org_ip_request_cntl == 0) 338 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); 339 } 340 #endif 341 342 static void dcn20_dpp_pg_control( 343 struct dce_hwseq *hws, 344 unsigned int dpp_inst, 345 bool power_on) 346 { 347 uint32_t power_gate = power_on ? 0 : 1; 348 uint32_t pwr_status = power_on ? 0 : 2; 349 350 if (hws->ctx->dc->debug.disable_dpp_power_gate) 351 return; 352 if (REG(DOMAIN1_PG_CONFIG) == 0) 353 return; 354 355 switch (dpp_inst) { 356 case 0: /* DPP0 */ 357 REG_UPDATE(DOMAIN1_PG_CONFIG, 358 DOMAIN1_POWER_GATE, power_gate); 359 360 REG_WAIT(DOMAIN1_PG_STATUS, 361 DOMAIN1_PGFSM_PWR_STATUS, pwr_status, 362 1, 1000); 363 break; 364 case 1: /* DPP1 */ 365 REG_UPDATE(DOMAIN3_PG_CONFIG, 366 DOMAIN3_POWER_GATE, power_gate); 367 368 REG_WAIT(DOMAIN3_PG_STATUS, 369 DOMAIN3_PGFSM_PWR_STATUS, pwr_status, 370 1, 1000); 371 break; 372 case 2: /* DPP2 */ 373 REG_UPDATE(DOMAIN5_PG_CONFIG, 374 DOMAIN5_POWER_GATE, power_gate); 375 376 REG_WAIT(DOMAIN5_PG_STATUS, 377 DOMAIN5_PGFSM_PWR_STATUS, pwr_status, 378 1, 1000); 379 break; 380 case 3: /* DPP3 */ 381 REG_UPDATE(DOMAIN7_PG_CONFIG, 382 DOMAIN7_POWER_GATE, power_gate); 383 384 REG_WAIT(DOMAIN7_PG_STATUS, 385 DOMAIN7_PGFSM_PWR_STATUS, pwr_status, 386 1, 1000); 387 break; 388 case 4: /* DPP4 */ 389 REG_UPDATE(DOMAIN9_PG_CONFIG, 390 DOMAIN9_POWER_GATE, power_gate); 391 392 REG_WAIT(DOMAIN9_PG_STATUS, 393 DOMAIN9_PGFSM_PWR_STATUS, pwr_status, 394 1, 1000); 395 break; 396 case 5: /* DPP5 */ 397 /* 398 * Do not power gate DPP5, should be left at HW default, power on permanently. 399 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard 400 * reset. 401 * REG_UPDATE(DOMAIN11_PG_CONFIG, 402 * DOMAIN11_POWER_GATE, power_gate); 403 * 404 * REG_WAIT(DOMAIN11_PG_STATUS, 405 * DOMAIN11_PGFSM_PWR_STATUS, pwr_status, 406 * 1, 1000); 407 */ 408 break; 409 default: 410 BREAK_TO_DEBUGGER(); 411 break; 412 } 413 } 414 415 416 static void dcn20_hubp_pg_control( 417 struct dce_hwseq *hws, 418 unsigned int hubp_inst, 419 bool power_on) 420 { 421 uint32_t power_gate = power_on ? 0 : 1; 422 uint32_t pwr_status = power_on ? 0 : 2; 423 424 if (hws->ctx->dc->debug.disable_hubp_power_gate) 425 return; 426 if (REG(DOMAIN0_PG_CONFIG) == 0) 427 return; 428 429 switch (hubp_inst) { 430 case 0: /* DCHUBP0 */ 431 REG_UPDATE(DOMAIN0_PG_CONFIG, 432 DOMAIN0_POWER_GATE, power_gate); 433 434 REG_WAIT(DOMAIN0_PG_STATUS, 435 DOMAIN0_PGFSM_PWR_STATUS, pwr_status, 436 1, 1000); 437 break; 438 case 1: /* DCHUBP1 */ 439 REG_UPDATE(DOMAIN2_PG_CONFIG, 440 DOMAIN2_POWER_GATE, power_gate); 441 442 REG_WAIT(DOMAIN2_PG_STATUS, 443 DOMAIN2_PGFSM_PWR_STATUS, pwr_status, 444 1, 1000); 445 break; 446 case 2: /* DCHUBP2 */ 447 REG_UPDATE(DOMAIN4_PG_CONFIG, 448 DOMAIN4_POWER_GATE, power_gate); 449 450 REG_WAIT(DOMAIN4_PG_STATUS, 451 DOMAIN4_PGFSM_PWR_STATUS, pwr_status, 452 1, 1000); 453 break; 454 case 3: /* DCHUBP3 */ 455 REG_UPDATE(DOMAIN6_PG_CONFIG, 456 DOMAIN6_POWER_GATE, power_gate); 457 458 REG_WAIT(DOMAIN6_PG_STATUS, 459 DOMAIN6_PGFSM_PWR_STATUS, pwr_status, 460 1, 1000); 461 break; 462 case 4: /* DCHUBP4 */ 463 REG_UPDATE(DOMAIN8_PG_CONFIG, 464 DOMAIN8_POWER_GATE, power_gate); 465 466 REG_WAIT(DOMAIN8_PG_STATUS, 467 DOMAIN8_PGFSM_PWR_STATUS, pwr_status, 468 1, 1000); 469 break; 470 case 5: /* DCHUBP5 */ 471 /* 472 * Do not power gate DCHUB5, should be left at HW default, power on permanently. 473 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard 474 * reset. 475 * REG_UPDATE(DOMAIN10_PG_CONFIG, 476 * DOMAIN10_POWER_GATE, power_gate); 477 * 478 * REG_WAIT(DOMAIN10_PG_STATUS, 479 * DOMAIN10_PGFSM_PWR_STATUS, pwr_status, 480 * 1, 1000); 481 */ 482 break; 483 default: 484 BREAK_TO_DEBUGGER(); 485 break; 486 } 487 } 488 489 490 491 static void dcn20_plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) 492 { 493 struct dce_hwseq *hws = dc->hwseq; 494 struct dpp *dpp = pipe_ctx->plane_res.dpp; 495 496 DC_LOGGER_INIT(dc->ctx->logger); 497 498 if (REG(DC_IP_REQUEST_CNTL)) { 499 REG_SET(DC_IP_REQUEST_CNTL, 0, 500 IP_REQUEST_EN, 1); 501 dcn20_dpp_pg_control(hws, dpp->inst, false); 502 dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); 503 dpp->funcs->dpp_reset(dpp); 504 REG_SET(DC_IP_REQUEST_CNTL, 0, 505 IP_REQUEST_EN, 0); 506 DC_LOG_DEBUG( 507 "Power gated front end %d\n", pipe_ctx->pipe_idx); 508 } 509 } 510 511 512 513 /* disable HW used by plane. 514 * note: cannot disable until disconnect is complete 515 */ 516 static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) 517 { 518 struct hubp *hubp = pipe_ctx->plane_res.hubp; 519 struct dpp *dpp = pipe_ctx->plane_res.dpp; 520 521 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); 522 523 /* In flip immediate with pipe splitting case GSL is used for 524 * synchronization so we must disable it when the plane is disabled. 525 */ 526 if (pipe_ctx->stream_res.gsl_group != 0) 527 dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); 528 529 dc->hwss.set_flip_control_gsl(pipe_ctx, false); 530 531 hubp->funcs->hubp_clk_cntl(hubp, false); 532 533 dpp->funcs->dpp_dppclk_control(dpp, false, false); 534 535 hubp->power_gated = true; 536 dc->optimized_required = false; /* We're powering off, no need to optimize */ 537 538 dcn20_plane_atomic_power_down(dc, pipe_ctx); 539 540 pipe_ctx->stream = NULL; 541 memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); 542 memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); 543 pipe_ctx->top_pipe = NULL; 544 pipe_ctx->bottom_pipe = NULL; 545 pipe_ctx->plane_state = NULL; 546 } 547 548 549 void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) 550 { 551 DC_LOGGER_INIT(dc->ctx->logger); 552 553 if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) 554 return; 555 556 dcn20_plane_atomic_disable(dc, pipe_ctx); 557 558 DC_LOG_DC("Power down front end %d\n", 559 pipe_ctx->pipe_idx); 560 } 561 562 static void dcn20_init_hw(struct dc *dc) 563 { 564 int i, j; 565 struct abm *abm = dc->res_pool->abm; 566 struct dmcu *dmcu = dc->res_pool->dmcu; 567 struct dce_hwseq *hws = dc->hwseq; 568 struct dc_bios *dcb = dc->ctx->dc_bios; 569 struct resource_pool *res_pool = dc->res_pool; 570 struct dc_state *context = dc->current_state; 571 struct dc_firmware_info fw_info = { { 0 } }; 572 573 if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) 574 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); 575 576 // Initialize the dccg 577 if (res_pool->dccg->funcs->dccg_init) 578 res_pool->dccg->funcs->dccg_init(res_pool->dccg); 579 580 //Enable ability to power gate / don't force power on permanently 581 enable_power_gating_plane(dc->hwseq, true); 582 583 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 584 REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); 585 REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); 586 587 dcn20_dccg_init(hws); 588 589 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); 590 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); 591 REG_WRITE(REFCLK_CNTL, 0); 592 } else { 593 if (!dcb->funcs->is_accelerated_mode(dcb)) { 594 bios_golden_init(dc); 595 if (dc->ctx->dc_bios->funcs->get_firmware_info( 596 dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) { 597 res_pool->ref_clocks.xtalin_clock_inKhz = fw_info.pll_info.crystal_frequency; 598 599 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 600 if (res_pool->dccg && res_pool->hubbub) { 601 602 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, 603 fw_info.pll_info.crystal_frequency, 604 &res_pool->ref_clocks.dccg_ref_clock_inKhz); 605 606 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, 607 res_pool->ref_clocks.dccg_ref_clock_inKhz, 608 &res_pool->ref_clocks.dchub_ref_clock_inKhz); 609 } else { 610 // Not all ASICs have DCCG sw component 611 res_pool->ref_clocks.dccg_ref_clock_inKhz = 612 res_pool->ref_clocks.xtalin_clock_inKhz; 613 res_pool->ref_clocks.dchub_ref_clock_inKhz = 614 res_pool->ref_clocks.xtalin_clock_inKhz; 615 } 616 } 617 } else 618 ASSERT_CRITICAL(false); 619 disable_vga(dc->hwseq); 620 } 621 622 for (i = 0; i < dc->link_count; i++) { 623 /* Power up AND update implementation according to the 624 * required signal (which may be different from the 625 * default signal on connector). 626 */ 627 struct dc_link *link = dc->links[i]; 628 629 link->link_enc->funcs->hw_init(link->link_enc); 630 } 631 } 632 633 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 634 /* Power gate DSCs */ 635 for (i = 0; i < res_pool->res_cap->num_dsc; i++) 636 dcn20_dsc_pg_control(hws, res_pool->dscs[i]->inst, false); 637 #endif 638 639 /* Blank pixel data with OPP DPG */ 640 for (i = 0; i < dc->res_pool->timing_generator_count; i++) { 641 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 642 643 if (tg->funcs->is_tg_enabled(tg)) { 644 dcn20_init_blank(dc, tg); 645 } 646 } 647 648 for (i = 0; i < res_pool->timing_generator_count; i++) { 649 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 650 651 if (tg->funcs->is_tg_enabled(tg)) 652 tg->funcs->lock(tg); 653 } 654 655 for (i = 0; i < dc->res_pool->pipe_count; i++) { 656 struct dpp *dpp = res_pool->dpps[i]; 657 658 dpp->funcs->dpp_reset(dpp); 659 } 660 661 /* Reset all MPCC muxes */ 662 res_pool->mpc->funcs->mpc_init(res_pool->mpc); 663 664 /* initialize OPP mpc_tree parameter */ 665 for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { 666 res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; 667 res_pool->opps[i]->mpc_tree_params.opp_list = NULL; 668 for (j = 0; j < MAX_PIPES; j++) 669 res_pool->opps[i]->mpcc_disconnect_pending[j] = false; 670 } 671 672 for (i = 0; i < dc->res_pool->pipe_count; i++) { 673 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 674 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 675 struct hubp *hubp = dc->res_pool->hubps[i]; 676 struct dpp *dpp = dc->res_pool->dpps[i]; 677 678 pipe_ctx->stream_res.tg = tg; 679 pipe_ctx->pipe_idx = i; 680 681 pipe_ctx->plane_res.hubp = hubp; 682 pipe_ctx->plane_res.dpp = dpp; 683 pipe_ctx->plane_res.mpcc_inst = dpp->inst; 684 hubp->mpcc_id = dpp->inst; 685 hubp->opp_id = OPP_ID_INVALID; 686 hubp->power_gated = false; 687 pipe_ctx->stream_res.opp = NULL; 688 689 hubp->funcs->hubp_init(hubp); 690 691 //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; 692 //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; 693 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; 694 pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; 695 /*to do*/ 696 hwss1_plane_atomic_disconnect(dc, pipe_ctx); 697 } 698 699 /* initialize DWB pointer to MCIF_WB */ 700 for (i = 0; i < res_pool->res_cap->num_dwb; i++) 701 res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; 702 703 for (i = 0; i < dc->res_pool->timing_generator_count; i++) { 704 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 705 706 if (tg->funcs->is_tg_enabled(tg)) 707 tg->funcs->unlock(tg); 708 } 709 710 for (i = 0; i < dc->res_pool->pipe_count; i++) { 711 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 712 713 dc->hwss.disable_plane(dc, pipe_ctx); 714 715 pipe_ctx->stream_res.tg = NULL; 716 pipe_ctx->plane_res.hubp = NULL; 717 } 718 719 for (i = 0; i < dc->res_pool->timing_generator_count; i++) { 720 struct timing_generator *tg = dc->res_pool->timing_generators[i]; 721 722 tg->funcs->tg_init(tg); 723 } 724 725 /* end of FPGA. Below if real ASIC */ 726 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) 727 return; 728 729 730 for (i = 0; i < res_pool->audio_count; i++) { 731 struct audio *audio = res_pool->audios[i]; 732 733 audio->funcs->hw_init(audio); 734 } 735 736 if (abm != NULL) { 737 abm->funcs->init_backlight(abm); 738 abm->funcs->abm_init(abm); 739 } 740 741 if (dmcu != NULL) 742 dmcu->funcs->dmcu_init(dmcu); 743 744 if (abm != NULL && dmcu != NULL) 745 abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); 746 747 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ 748 REG_WRITE(DIO_MEM_PWR_CTRL, 0); 749 750 if (!dc->debug.disable_clock_gate) { 751 /* enable all DCN clock gating */ 752 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); 753 754 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); 755 756 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); 757 } 758 759 } 760 761 enum dc_status dcn20_enable_stream_timing( 762 struct pipe_ctx *pipe_ctx, 763 struct dc_state *context, 764 struct dc *dc) 765 { 766 struct dc_stream_state *stream = pipe_ctx->stream; 767 struct drr_params params = {0}; 768 unsigned int event_triggers = 0; 769 770 771 #if defined(CONFIG_DRM_AMD_DC_DCN2_0) 772 struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); 773 #endif 774 775 /* by upper caller loop, pipe0 is parent pipe and be called first. 776 * back end is set up by for pipe0. Other children pipe share back end 777 * with pipe 0. No program is needed. 778 */ 779 if (pipe_ctx->top_pipe != NULL) 780 return DC_OK; 781 782 /* TODO check if timing_changed, disable stream if timing changed */ 783 784 if (odm_pipe) 785 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 786 pipe_ctx->stream_res.tg, 787 odm_pipe->stream_res.opp->inst, 788 pipe_ctx->stream->timing.h_addressable/2, 789 pipe_ctx->stream->timing.pixel_encoding); 790 /* HW program guide assume display already disable 791 * by unplug sequence. OTG assume stop. 792 */ 793 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); 794 795 if (false == pipe_ctx->clock_source->funcs->program_pix_clk( 796 pipe_ctx->clock_source, 797 &pipe_ctx->stream_res.pix_clk_params, 798 &pipe_ctx->pll_settings)) { 799 BREAK_TO_DEBUGGER(); 800 return DC_ERROR_UNEXPECTED; 801 } 802 803 pipe_ctx->stream_res.tg->funcs->program_timing( 804 pipe_ctx->stream_res.tg, 805 &stream->timing, 806 pipe_ctx->pipe_dlg_param.vready_offset, 807 pipe_ctx->pipe_dlg_param.vstartup_start, 808 pipe_ctx->pipe_dlg_param.vupdate_offset, 809 pipe_ctx->pipe_dlg_param.vupdate_width, 810 pipe_ctx->stream->signal, 811 true); 812 813 if (pipe_ctx->stream_res.tg->funcs->setup_global_lock) 814 pipe_ctx->stream_res.tg->funcs->setup_global_lock( 815 pipe_ctx->stream_res.tg); 816 817 if (odm_pipe) 818 odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( 819 odm_pipe->stream_res.opp, 820 true); 821 822 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 823 pipe_ctx->stream_res.opp, 824 true); 825 826 dc->hwss.blank_pixel_data(dc, pipe_ctx, true); 827 828 /* VTG is within DCHUB command block. DCFCLK is always on */ 829 if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { 830 BREAK_TO_DEBUGGER(); 831 return DC_ERROR_UNEXPECTED; 832 } 833 834 dcn20_hwss_wait_for_blank_complete(pipe_ctx->stream_res.opp); 835 836 params.vertical_total_min = stream->adjust.v_total_min; 837 params.vertical_total_max = stream->adjust.v_total_max; 838 if (pipe_ctx->stream_res.tg->funcs->set_drr) 839 pipe_ctx->stream_res.tg->funcs->set_drr( 840 pipe_ctx->stream_res.tg, ¶ms); 841 842 // DRR should set trigger event to monitor surface update event 843 if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) 844 event_triggers = 0x80; 845 if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) 846 pipe_ctx->stream_res.tg->funcs->set_static_screen_control( 847 pipe_ctx->stream_res.tg, event_triggers); 848 849 /* TODO program crtc source select for non-virtual signal*/ 850 /* TODO program FMT */ 851 /* TODO setup link_enc */ 852 /* TODO set stream attributes */ 853 /* TODO program audio */ 854 /* TODO enable stream if timing changed */ 855 /* TODO unblank stream if DP */ 856 857 return DC_OK; 858 } 859 860 void dcn20_program_output_csc(struct dc *dc, 861 struct pipe_ctx *pipe_ctx, 862 enum dc_color_space colorspace, 863 uint16_t *matrix, 864 int opp_id) 865 { 866 struct mpc *mpc = dc->res_pool->mpc; 867 enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; 868 869 if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { 870 if (mpc->funcs->set_output_csc != NULL) 871 mpc->funcs->set_output_csc(mpc, 872 opp_id, 873 matrix, 874 ocsc_mode); 875 } else { 876 if (mpc->funcs->set_ocsc_default != NULL) 877 mpc->funcs->set_ocsc_default(mpc, 878 opp_id, 879 colorspace, 880 ocsc_mode); 881 } 882 } 883 884 bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, 885 const struct dc_stream_state *stream) 886 { 887 int mpcc_id = pipe_ctx->plane_res.hubp->inst; 888 struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; 889 struct pwl_params *params = NULL; 890 /* 891 * program OGAM only for the top pipe 892 * if there is a pipe split then fix diagnostic is required: 893 * how to pass OGAM parameter for stream. 894 * if programming for all pipes is required then remove condition 895 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic. 896 */ 897 if ((pipe_ctx->top_pipe == NULL || dc_res_is_odm_head_pipe(pipe_ctx)) 898 && mpc->funcs->set_output_gamma && stream->out_transfer_func) { 899 if (stream->out_transfer_func->type == TF_TYPE_HWPWL) 900 params = &stream->out_transfer_func->pwl; 901 else if (pipe_ctx->stream->out_transfer_func->type == 902 TF_TYPE_DISTRIBUTED_POINTS && 903 cm_helper_translate_curve_to_hw_format( 904 stream->out_transfer_func, 905 &mpc->blender_params, false)) 906 params = &mpc->blender_params; 907 /* 908 * there is no ROM 909 */ 910 if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) 911 BREAK_TO_DEBUGGER(); 912 } 913 /* 914 * if above if is not executed then 'params' equal to 0 and set in bypass 915 */ 916 mpc->funcs->set_output_gamma(mpc, mpcc_id, params); 917 918 return true; 919 } 920 921 static bool dcn20_set_blend_lut( 922 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) 923 { 924 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 925 bool result = true; 926 struct pwl_params *blend_lut = NULL; 927 928 if (plane_state->blend_tf) { 929 if (plane_state->blend_tf->type == TF_TYPE_HWPWL) 930 blend_lut = &plane_state->blend_tf->pwl; 931 else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { 932 cm_helper_translate_curve_to_hw_format( 933 plane_state->blend_tf, 934 &dpp_base->regamma_params, false); 935 blend_lut = &dpp_base->regamma_params; 936 } 937 } 938 result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); 939 940 return result; 941 } 942 943 static bool dcn20_set_shaper_3dlut( 944 struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) 945 { 946 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 947 bool result = true; 948 struct pwl_params *shaper_lut = NULL; 949 950 if (plane_state->in_shaper_func) { 951 if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) 952 shaper_lut = &plane_state->in_shaper_func->pwl; 953 else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { 954 cm_helper_translate_curve_to_hw_format( 955 plane_state->in_shaper_func, 956 &dpp_base->shaper_params, true); 957 shaper_lut = &dpp_base->shaper_params; 958 } 959 } 960 961 result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); 962 if (plane_state->lut3d_func && 963 plane_state->lut3d_func->state.bits.initialized == 1) 964 result = dpp_base->funcs->dpp_program_3dlut(dpp_base, 965 &plane_state->lut3d_func->lut_3d); 966 else 967 result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); 968 969 if (plane_state->lut3d_func && 970 plane_state->lut3d_func->state.bits.initialized == 1 && 971 plane_state->lut3d_func->hdr_multiplier != 0) 972 dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, 973 plane_state->lut3d_func->hdr_multiplier); 974 else 975 dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, 0x1f000); 976 977 return result; 978 } 979 980 bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, 981 const struct dc_plane_state *plane_state) 982 { 983 struct dpp *dpp_base = pipe_ctx->plane_res.dpp; 984 const struct dc_transfer_func *tf = NULL; 985 bool result = true; 986 bool use_degamma_ram = false; 987 988 if (dpp_base == NULL || plane_state == NULL) 989 return false; 990 991 dcn20_set_shaper_3dlut(pipe_ctx, plane_state); 992 dcn20_set_blend_lut(pipe_ctx, plane_state); 993 994 if (plane_state->in_transfer_func) 995 tf = plane_state->in_transfer_func; 996 997 998 if (tf == NULL) { 999 dpp_base->funcs->dpp_set_degamma(dpp_base, 1000 IPP_DEGAMMA_MODE_BYPASS); 1001 return true; 1002 } 1003 1004 if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS) 1005 use_degamma_ram = true; 1006 1007 if (use_degamma_ram == true) { 1008 if (tf->type == TF_TYPE_HWPWL) 1009 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, 1010 &tf->pwl); 1011 else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) { 1012 cm_helper_translate_curve_to_degamma_hw_format(tf, 1013 &dpp_base->degamma_params); 1014 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, 1015 &dpp_base->degamma_params); 1016 } 1017 return true; 1018 } 1019 /* handle here the optimized cases when de-gamma ROM could be used. 1020 * 1021 */ 1022 if (tf->type == TF_TYPE_PREDEFINED) { 1023 switch (tf->tf) { 1024 case TRANSFER_FUNCTION_SRGB: 1025 dpp_base->funcs->dpp_set_degamma(dpp_base, 1026 IPP_DEGAMMA_MODE_HW_sRGB); 1027 break; 1028 case TRANSFER_FUNCTION_BT709: 1029 dpp_base->funcs->dpp_set_degamma(dpp_base, 1030 IPP_DEGAMMA_MODE_HW_xvYCC); 1031 break; 1032 case TRANSFER_FUNCTION_LINEAR: 1033 dpp_base->funcs->dpp_set_degamma(dpp_base, 1034 IPP_DEGAMMA_MODE_BYPASS); 1035 break; 1036 case TRANSFER_FUNCTION_PQ: 1037 default: 1038 result = false; 1039 break; 1040 } 1041 } else if (tf->type == TF_TYPE_BYPASS) 1042 dpp_base->funcs->dpp_set_degamma(dpp_base, 1043 IPP_DEGAMMA_MODE_BYPASS); 1044 else { 1045 /* 1046 * if we are here, we did not handle correctly. 1047 * fix is required for this use case 1048 */ 1049 BREAK_TO_DEBUGGER(); 1050 dpp_base->funcs->dpp_set_degamma(dpp_base, 1051 IPP_DEGAMMA_MODE_BYPASS); 1052 } 1053 1054 return result; 1055 } 1056 1057 static void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) 1058 { 1059 struct pipe_ctx *combine_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); 1060 1061 if (combine_pipe) 1062 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 1063 pipe_ctx->stream_res.tg, 1064 combine_pipe->stream_res.opp->inst, 1065 pipe_ctx->plane_res.scl_data.h_active, 1066 pipe_ctx->stream->timing.pixel_encoding); 1067 else 1068 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 1069 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); 1070 } 1071 1072 void dcn20_blank_pixel_data( 1073 struct dc *dc, 1074 struct pipe_ctx *pipe_ctx, 1075 bool blank) 1076 { 1077 struct tg_color black_color = {0}; 1078 struct stream_resource *stream_res = &pipe_ctx->stream_res; 1079 struct dc_stream_state *stream = pipe_ctx->stream; 1080 enum dc_color_space color_space = stream->output_color_space; 1081 enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; 1082 struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); 1083 1084 int width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; 1085 int height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; 1086 1087 /* get opp dpg blank color */ 1088 color_space_to_black_color(dc, color_space, &black_color); 1089 1090 if (bot_odm_pipe) 1091 width = width / 2; 1092 1093 if (blank) { 1094 if (stream_res->abm) 1095 stream_res->abm->funcs->set_abm_immediate_disable(stream_res->abm); 1096 1097 if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) 1098 test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; 1099 } else { 1100 test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; 1101 } 1102 1103 stream_res->opp->funcs->opp_set_disp_pattern_generator( 1104 stream_res->opp, 1105 test_pattern, 1106 stream->timing.display_color_depth, 1107 &black_color, 1108 width, 1109 height); 1110 1111 if (bot_odm_pipe) { 1112 bot_odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator( 1113 bot_odm_pipe->stream_res.opp, 1114 dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE ? 1115 CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern, 1116 stream->timing.display_color_depth, 1117 &black_color, 1118 width, 1119 height); 1120 } 1121 1122 if (!blank) 1123 if (stream_res->abm) { 1124 stream_res->abm->funcs->set_pipe(stream_res->abm, stream_res->tg->inst + 1); 1125 stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); 1126 } 1127 } 1128 1129 1130 static void dcn20_power_on_plane( 1131 struct dce_hwseq *hws, 1132 struct pipe_ctx *pipe_ctx) 1133 { 1134 DC_LOGGER_INIT(hws->ctx->logger); 1135 if (REG(DC_IP_REQUEST_CNTL)) { 1136 REG_SET(DC_IP_REQUEST_CNTL, 0, 1137 IP_REQUEST_EN, 1); 1138 dcn20_dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true); 1139 dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true); 1140 REG_SET(DC_IP_REQUEST_CNTL, 0, 1141 IP_REQUEST_EN, 0); 1142 DC_LOG_DEBUG( 1143 "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst); 1144 } 1145 } 1146 1147 void dcn20_enable_plane( 1148 struct dc *dc, 1149 struct pipe_ctx *pipe_ctx, 1150 struct dc_state *context) 1151 { 1152 //if (dc->debug.sanity_checks) { 1153 // dcn10_verify_allow_pstate_change_high(dc); 1154 //} 1155 dcn20_power_on_plane(dc->hwseq, pipe_ctx); 1156 1157 /* enable DCFCLK current DCHUB */ 1158 pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); 1159 1160 /* make sure OPP_PIPE_CLOCK_EN = 1 */ 1161 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 1162 pipe_ctx->stream_res.opp, 1163 true); 1164 1165 /* TODO: enable/disable in dm as per update type. 1166 if (plane_state) { 1167 DC_LOG_DC(dc->ctx->logger, 1168 "Pipe:%d 0x%x: addr hi:0x%x, " 1169 "addr low:0x%x, " 1170 "src: %d, %d, %d," 1171 " %d; dst: %d, %d, %d, %d;\n", 1172 pipe_ctx->pipe_idx, 1173 plane_state, 1174 plane_state->address.grph.addr.high_part, 1175 plane_state->address.grph.addr.low_part, 1176 plane_state->src_rect.x, 1177 plane_state->src_rect.y, 1178 plane_state->src_rect.width, 1179 plane_state->src_rect.height, 1180 plane_state->dst_rect.x, 1181 plane_state->dst_rect.y, 1182 plane_state->dst_rect.width, 1183 plane_state->dst_rect.height); 1184 1185 DC_LOG_DC(dc->ctx->logger, 1186 "Pipe %d: width, height, x, y format:%d\n" 1187 "viewport:%d, %d, %d, %d\n" 1188 "recout: %d, %d, %d, %d\n", 1189 pipe_ctx->pipe_idx, 1190 plane_state->format, 1191 pipe_ctx->plane_res.scl_data.viewport.width, 1192 pipe_ctx->plane_res.scl_data.viewport.height, 1193 pipe_ctx->plane_res.scl_data.viewport.x, 1194 pipe_ctx->plane_res.scl_data.viewport.y, 1195 pipe_ctx->plane_res.scl_data.recout.width, 1196 pipe_ctx->plane_res.scl_data.recout.height, 1197 pipe_ctx->plane_res.scl_data.recout.x, 1198 pipe_ctx->plane_res.scl_data.recout.y); 1199 print_rq_dlg_ttu(dc, pipe_ctx); 1200 } 1201 */ 1202 if (dc->vm_pa_config.valid) { 1203 struct vm_system_aperture_param apt; 1204 1205 apt.sys_default.quad_part = 0; 1206 1207 apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr; 1208 apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr; 1209 1210 // Program system aperture settings 1211 pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); 1212 } 1213 1214 // if (dc->debug.sanity_checks) { 1215 // dcn10_verify_allow_pstate_change_high(dc); 1216 // } 1217 } 1218 1219 1220 static void dcn20_program_pipe( 1221 struct dc *dc, 1222 struct pipe_ctx *pipe_ctx, 1223 struct dc_state *context) 1224 { 1225 pipe_ctx->plane_state->update_flags.bits.full_update = 1226 context->commit_hints.full_update_needed ? 1 : pipe_ctx->plane_state->update_flags.bits.full_update; 1227 1228 if (pipe_ctx->plane_state->update_flags.bits.full_update) 1229 dcn20_enable_plane(dc, pipe_ctx, context); 1230 1231 update_dchubp_dpp(dc, pipe_ctx, context); 1232 1233 set_hdr_multiplier(pipe_ctx); 1234 1235 if (pipe_ctx->plane_state->update_flags.bits.full_update || 1236 pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || 1237 pipe_ctx->plane_state->update_flags.bits.gamma_change) 1238 dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); 1239 1240 /* dcn10_translate_regamma_to_hw_format takes 750us to finish 1241 * only do gamma programming for full update. 1242 * TODO: This can be further optimized/cleaned up 1243 * Always call this for now since it does memcmp inside before 1244 * doing heavy calculation and programming 1245 */ 1246 if (pipe_ctx->plane_state->update_flags.bits.full_update) 1247 dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); 1248 } 1249 1250 static void dcn20_program_all_pipe_in_tree( 1251 struct dc *dc, 1252 struct pipe_ctx *pipe_ctx, 1253 struct dc_state *context) 1254 { 1255 if (pipe_ctx->top_pipe == NULL) { 1256 bool blank = !is_pipe_tree_visible(pipe_ctx); 1257 1258 pipe_ctx->stream_res.tg->funcs->program_global_sync( 1259 pipe_ctx->stream_res.tg, 1260 pipe_ctx->pipe_dlg_param.vready_offset, 1261 pipe_ctx->pipe_dlg_param.vstartup_start, 1262 pipe_ctx->pipe_dlg_param.vupdate_offset, 1263 pipe_ctx->pipe_dlg_param.vupdate_width); 1264 1265 pipe_ctx->stream_res.tg->funcs->set_vtg_params( 1266 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); 1267 1268 dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); 1269 1270 if (dc->hwss.update_odm) 1271 dc->hwss.update_odm(dc, context, pipe_ctx); 1272 } 1273 1274 if (pipe_ctx->plane_state != NULL) 1275 dcn20_program_pipe(dc, pipe_ctx, context); 1276 1277 if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) 1278 dcn20_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); 1279 } 1280 1281 void dcn20_pipe_control_lock_global( 1282 struct dc *dc, 1283 struct pipe_ctx *pipe, 1284 bool lock) 1285 { 1286 if (lock) { 1287 pipe->stream_res.tg->funcs->lock_doublebuffer_enable( 1288 pipe->stream_res.tg); 1289 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); 1290 } else { 1291 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); 1292 pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, 1293 CRTC_STATE_VACTIVE); 1294 pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, 1295 CRTC_STATE_VBLANK); 1296 pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, 1297 CRTC_STATE_VACTIVE); 1298 pipe->stream_res.tg->funcs->lock_doublebuffer_disable( 1299 pipe->stream_res.tg); 1300 } 1301 } 1302 1303 void dcn20_pipe_control_lock( 1304 struct dc *dc, 1305 struct pipe_ctx *pipe, 1306 bool lock) 1307 { 1308 bool flip_immediate = false; 1309 1310 /* use TG master update lock to lock everything on the TG 1311 * therefore only top pipe need to lock 1312 */ 1313 if (pipe->top_pipe) 1314 return; 1315 1316 if (pipe->plane_state != NULL) 1317 flip_immediate = pipe->plane_state->flip_immediate; 1318 1319 if (flip_immediate && lock) { 1320 while (pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->plane_res.hubp)) { 1321 udelay(1); 1322 } 1323 1324 if (pipe->bottom_pipe != NULL) 1325 while (pipe->bottom_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->bottom_pipe->plane_res.hubp)) { 1326 udelay(1); 1327 } 1328 } 1329 1330 /* In flip immediate and pipe splitting case, we need to use GSL 1331 * for synchronization. Only do setup on locking and on flip type change. 1332 */ 1333 if (lock && pipe->bottom_pipe != NULL) 1334 if ((flip_immediate && pipe->stream_res.gsl_group == 0) || 1335 (!flip_immediate && pipe->stream_res.gsl_group > 0)) 1336 dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate); 1337 1338 if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { 1339 if (lock) 1340 pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); 1341 else 1342 pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); 1343 } else { 1344 if (lock) 1345 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); 1346 else 1347 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); 1348 } 1349 } 1350 1351 static void dcn20_apply_ctx_for_surface( 1352 struct dc *dc, 1353 const struct dc_stream_state *stream, 1354 int num_planes, 1355 struct dc_state *context) 1356 { 1357 1358 int i; 1359 struct timing_generator *tg; 1360 bool removed_pipe[6] = { false }; 1361 bool interdependent_update = false; 1362 struct pipe_ctx *top_pipe_to_program = 1363 find_top_pipe_for_stream(dc, context, stream); 1364 DC_LOGGER_INIT(dc->ctx->logger); 1365 1366 if (!top_pipe_to_program) 1367 return; 1368 1369 /* Carry over GSL groups in case the context is changing. */ 1370 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1371 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1372 struct pipe_ctx *old_pipe_ctx = 1373 &dc->current_state->res_ctx.pipe_ctx[i]; 1374 1375 if (pipe_ctx->stream == stream && 1376 pipe_ctx->stream == old_pipe_ctx->stream) 1377 pipe_ctx->stream_res.gsl_group = 1378 old_pipe_ctx->stream_res.gsl_group; 1379 } 1380 1381 tg = top_pipe_to_program->stream_res.tg; 1382 1383 interdependent_update = top_pipe_to_program->plane_state && 1384 top_pipe_to_program->plane_state->update_flags.bits.full_update; 1385 1386 if (interdependent_update) 1387 lock_all_pipes(dc, context, true); 1388 else 1389 dcn20_pipe_control_lock(dc, top_pipe_to_program, true); 1390 1391 if (num_planes == 0) { 1392 /* OTG blank before remove all front end */ 1393 dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); 1394 } 1395 1396 /* Disconnect unused mpcc */ 1397 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1398 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1399 struct pipe_ctx *old_pipe_ctx = 1400 &dc->current_state->res_ctx.pipe_ctx[i]; 1401 /* 1402 * Powergate reused pipes that are not powergated 1403 * fairly hacky right now, using opp_id as indicator 1404 * TODO: After move dc_post to dc_update, this will 1405 * be removed. 1406 */ 1407 if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { 1408 if (old_pipe_ctx->stream_res.tg == tg && 1409 old_pipe_ctx->plane_res.hubp && 1410 old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID) 1411 dcn20_disable_plane(dc, old_pipe_ctx); 1412 } 1413 1414 if ((!pipe_ctx->plane_state || 1415 pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) && 1416 old_pipe_ctx->plane_state && 1417 old_pipe_ctx->stream_res.tg == tg) { 1418 1419 dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); 1420 removed_pipe[i] = true; 1421 1422 DC_LOG_DC("Reset mpcc for pipe %d\n", 1423 old_pipe_ctx->pipe_idx); 1424 } 1425 } 1426 1427 if (num_planes > 0) 1428 dcn20_program_all_pipe_in_tree(dc, top_pipe_to_program, context); 1429 1430 /* Program secondary blending tree and writeback pipes */ 1431 if ((stream->num_wb_info > 0) && (dc->hwss.program_all_writeback_pipes_in_tree)) 1432 dc->hwss.program_all_writeback_pipes_in_tree(dc, stream, context); 1433 1434 if (interdependent_update) 1435 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1436 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1437 1438 /* Skip inactive pipes and ones already updated */ 1439 if (!pipe_ctx->stream || pipe_ctx->stream == stream || 1440 !pipe_ctx->plane_state || !tg->funcs->is_tg_enabled(tg)) 1441 continue; 1442 1443 pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( 1444 pipe_ctx->plane_res.hubp, 1445 &pipe_ctx->dlg_regs, 1446 &pipe_ctx->ttu_regs); 1447 } 1448 1449 if (interdependent_update) 1450 lock_all_pipes(dc, context, false); 1451 else 1452 dcn20_pipe_control_lock(dc, top_pipe_to_program, false); 1453 1454 for (i = 0; i < dc->res_pool->pipe_count; i++) 1455 if (removed_pipe[i]) 1456 dcn20_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); 1457 } 1458 1459 1460 void dcn20_prepare_bandwidth( 1461 struct dc *dc, 1462 struct dc_state *context) 1463 { 1464 struct hubbub *hubbub = dc->res_pool->hubbub; 1465 1466 dc->clk_mgr->funcs->update_clocks( 1467 dc->clk_mgr, 1468 context, 1469 false); 1470 1471 /* program dchubbub watermarks */ 1472 hubbub->funcs->program_watermarks(hubbub, 1473 &context->bw_ctx.bw.dcn.watermarks, 1474 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, 1475 false); 1476 } 1477 1478 void dcn20_optimize_bandwidth( 1479 struct dc *dc, 1480 struct dc_state *context) 1481 { 1482 struct hubbub *hubbub = dc->res_pool->hubbub; 1483 1484 /* program dchubbub watermarks */ 1485 hubbub->funcs->program_watermarks(hubbub, 1486 &context->bw_ctx.bw.dcn.watermarks, 1487 dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, 1488 true); 1489 1490 dc->clk_mgr->funcs->update_clocks( 1491 dc->clk_mgr, 1492 context, 1493 true); 1494 } 1495 1496 bool dcn20_update_bandwidth( 1497 struct dc *dc, 1498 struct dc_state *context) 1499 { 1500 int i; 1501 1502 /* recalculate DML parameters */ 1503 if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) 1504 return false; 1505 1506 /* apply updated bandwidth parameters */ 1507 dc->hwss.prepare_bandwidth(dc, context); 1508 1509 /* update hubp configs for all pipes */ 1510 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1511 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1512 1513 if (pipe_ctx->plane_state == NULL) 1514 continue; 1515 1516 if (pipe_ctx->top_pipe == NULL) { 1517 bool blank = !is_pipe_tree_visible(pipe_ctx); 1518 1519 pipe_ctx->stream_res.tg->funcs->program_global_sync( 1520 pipe_ctx->stream_res.tg, 1521 pipe_ctx->pipe_dlg_param.vready_offset, 1522 pipe_ctx->pipe_dlg_param.vstartup_start, 1523 pipe_ctx->pipe_dlg_param.vupdate_offset, 1524 pipe_ctx->pipe_dlg_param.vupdate_width); 1525 1526 pipe_ctx->stream_res.tg->funcs->set_vtg_params( 1527 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); 1528 1529 dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); 1530 } 1531 1532 pipe_ctx->plane_res.hubp->funcs->hubp_setup( 1533 pipe_ctx->plane_res.hubp, 1534 &pipe_ctx->dlg_regs, 1535 &pipe_ctx->ttu_regs, 1536 &pipe_ctx->rq_regs, 1537 &pipe_ctx->pipe_dlg_param); 1538 } 1539 1540 return true; 1541 } 1542 1543 static void dcn20_enable_writeback( 1544 struct dc *dc, 1545 const struct dc_stream_status *stream_status, 1546 struct dc_writeback_info *wb_info) 1547 { 1548 struct dwbc *dwb; 1549 struct mcif_wb *mcif_wb; 1550 struct timing_generator *optc; 1551 1552 ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); 1553 ASSERT(wb_info->wb_enabled); 1554 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 1555 mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; 1556 1557 /* set the OPTC source mux */ 1558 ASSERT(stream_status->primary_otg_inst < MAX_PIPES); 1559 optc = dc->res_pool->timing_generators[stream_status->primary_otg_inst]; 1560 optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst); 1561 /* set MCIF_WB buffer and arbitration configuration */ 1562 mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height); 1563 mcif_wb->funcs->config_mcif_arb(mcif_wb, &dc->current_state->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); 1564 /* Enable MCIF_WB */ 1565 mcif_wb->funcs->enable_mcif(mcif_wb); 1566 /* Enable DWB */ 1567 dwb->funcs->enable(dwb, &wb_info->dwb_params); 1568 /* TODO: add sequence to enable/disable warmup */ 1569 } 1570 1571 void dcn20_disable_writeback( 1572 struct dc *dc, 1573 unsigned int dwb_pipe_inst) 1574 { 1575 struct dwbc *dwb; 1576 struct mcif_wb *mcif_wb; 1577 1578 ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); 1579 dwb = dc->res_pool->dwbc[dwb_pipe_inst]; 1580 mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; 1581 1582 dwb->funcs->disable(dwb); 1583 mcif_wb->funcs->disable_mcif(mcif_wb); 1584 } 1585 1586 bool dcn20_hwss_wait_for_blank_complete( 1587 struct output_pixel_processor *opp) 1588 { 1589 int counter; 1590 1591 for (counter = 0; counter < 1000; counter++) { 1592 if (opp->funcs->dpg_is_blanked(opp)) 1593 break; 1594 1595 udelay(100); 1596 } 1597 1598 if (counter == 1000) { 1599 dm_error("DC: failed to blank crtc!\n"); 1600 return false; 1601 } 1602 1603 return true; 1604 } 1605 1606 bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx) 1607 { 1608 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1609 1610 if (!hubp) 1611 return false; 1612 return hubp->funcs->dmdata_status_done(hubp); 1613 } 1614 1615 static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) 1616 { 1617 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 1618 struct dce_hwseq *hws = dc->hwseq; 1619 struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); 1620 1621 if (pipe_ctx->stream_res.dsc) { 1622 dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true); 1623 if (bot_odm_pipe) 1624 dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, true); 1625 } 1626 #endif 1627 } 1628 1629 static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) 1630 { 1631 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 1632 struct dce_hwseq *hws = dc->hwseq; 1633 struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); 1634 1635 if (pipe_ctx->stream_res.dsc) { 1636 dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false); 1637 if (bot_odm_pipe) 1638 dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, false); 1639 } 1640 #endif 1641 } 1642 1643 void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) 1644 { 1645 struct dc_dmdata_attributes attr = { 0 }; 1646 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1647 1648 attr.dmdata_mode = DMDATA_HW_MODE; 1649 attr.dmdata_size = 1650 dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; 1651 attr.address.quad_part = 1652 pipe_ctx->stream->dmdata_address.quad_part; 1653 attr.dmdata_dl_delta = 0; 1654 attr.dmdata_qos_mode = 0; 1655 attr.dmdata_qos_level = 0; 1656 attr.dmdata_repeat = 1; /* always repeat */ 1657 attr.dmdata_updated = 1; 1658 attr.dmdata_sw_data = NULL; 1659 1660 hubp->funcs->dmdata_set_attributes(hubp, &attr); 1661 } 1662 1663 void dcn20_disable_stream(struct pipe_ctx *pipe_ctx, int option) 1664 { 1665 dce110_disable_stream(pipe_ctx, option); 1666 } 1667 1668 static void dcn20_init_vm_ctx( 1669 struct dce_hwseq *hws, 1670 struct dc *dc, 1671 struct dc_virtual_addr_space_config *va_config, 1672 int vmid) 1673 { 1674 struct dcn_hubbub_virt_addr_config config; 1675 1676 if (vmid == 0) { 1677 ASSERT(0); /* VMID cannot be 0 for vm context */ 1678 return; 1679 } 1680 1681 config.page_table_start_addr = va_config->page_table_start_addr; 1682 config.page_table_end_addr = va_config->page_table_end_addr; 1683 config.page_table_block_size = va_config->page_table_block_size_in_bytes; 1684 config.page_table_depth = va_config->page_table_depth; 1685 config.page_table_base_addr = va_config->page_table_base_addr; 1686 1687 dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid); 1688 } 1689 1690 static int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) 1691 { 1692 struct dcn_hubbub_phys_addr_config config; 1693 1694 config.system_aperture.fb_top = pa_config->system_aperture.fb_top; 1695 config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; 1696 config.system_aperture.fb_base = pa_config->system_aperture.fb_base; 1697 config.system_aperture.agp_top = pa_config->system_aperture.agp_top; 1698 config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; 1699 config.system_aperture.agp_base = pa_config->system_aperture.agp_base; 1700 config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; 1701 config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; 1702 config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; 1703 1704 return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); 1705 } 1706 1707 static bool patch_address_for_sbs_tb_stereo( 1708 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) 1709 { 1710 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1711 bool sec_split = pipe_ctx->top_pipe && 1712 pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; 1713 if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && 1714 (pipe_ctx->stream->timing.timing_3d_format == 1715 TIMING_3D_FORMAT_SIDE_BY_SIDE || 1716 pipe_ctx->stream->timing.timing_3d_format == 1717 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { 1718 *addr = plane_state->address.grph_stereo.left_addr; 1719 plane_state->address.grph_stereo.left_addr = 1720 plane_state->address.grph_stereo.right_addr; 1721 return true; 1722 } 1723 1724 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && 1725 plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { 1726 plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; 1727 plane_state->address.grph_stereo.right_addr = 1728 plane_state->address.grph_stereo.left_addr; 1729 } 1730 return false; 1731 } 1732 1733 1734 static void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) 1735 { 1736 bool addr_patched = false; 1737 PHYSICAL_ADDRESS_LOC addr; 1738 struct dc_plane_state *plane_state = pipe_ctx->plane_state; 1739 1740 if (plane_state == NULL) 1741 return; 1742 1743 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); 1744 1745 // Call Helper to track VMID use 1746 vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst); 1747 1748 pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( 1749 pipe_ctx->plane_res.hubp, 1750 &plane_state->address, 1751 plane_state->flip_immediate); 1752 1753 plane_state->status.requested_address = plane_state->address; 1754 1755 if (plane_state->flip_immediate) 1756 plane_state->status.current_address = plane_state->address; 1757 1758 if (addr_patched) 1759 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; 1760 } 1761 1762 void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, 1763 struct dc_link_settings *link_settings) 1764 { 1765 struct encoder_unblank_param params = { { 0 } }; 1766 struct dc_stream_state *stream = pipe_ctx->stream; 1767 struct dc_link *link = stream->link; 1768 params.odm = dc_res_get_odm_bottom_pipe(pipe_ctx); 1769 1770 /* only 3 items below are used by unblank */ 1771 params.timing = pipe_ctx->stream->timing; 1772 1773 params.link_settings.link_rate = link_settings->link_rate; 1774 1775 if (dc_is_dp_signal(pipe_ctx->stream->signal)) { 1776 if (optc1_is_two_pixels_per_containter(&stream->timing) || params.odm) 1777 params.timing.pix_clk_100hz /= 2; 1778 pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( 1779 pipe_ctx->stream_res.stream_enc, params.odm); 1780 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); 1781 } 1782 1783 if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { 1784 link->dc->hwss.edp_backlight_control(link, true); 1785 } 1786 } 1787 1788 void dcn20_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) 1789 { 1790 struct timing_generator *tg = pipe_ctx->stream_res.tg; 1791 int start_line = get_vupdate_offset_from_vsync(pipe_ctx); 1792 1793 if (start_line < 0) 1794 start_line = 0; 1795 1796 if (tg->funcs->setup_vertical_interrupt2) 1797 tg->funcs->setup_vertical_interrupt2(tg, start_line); 1798 } 1799 1800 static void dcn20_reset_back_end_for_pipe( 1801 struct dc *dc, 1802 struct pipe_ctx *pipe_ctx, 1803 struct dc_state *context) 1804 { 1805 int i; 1806 DC_LOGGER_INIT(dc->ctx->logger); 1807 if (pipe_ctx->stream_res.stream_enc == NULL) { 1808 pipe_ctx->stream = NULL; 1809 return; 1810 } 1811 1812 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { 1813 /* DPMS may already disable */ 1814 if (!pipe_ctx->stream->dpms_off) 1815 core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); 1816 else if (pipe_ctx->stream_res.audio) { 1817 dc->hwss.disable_audio_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); 1818 } 1819 } 1820 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 1821 else if (pipe_ctx->stream_res.dsc) { 1822 dp_set_dsc_enable(pipe_ctx, false); 1823 } 1824 #endif 1825 1826 /* by upper caller loop, parent pipe: pipe0, will be reset last. 1827 * back end share by all pipes and will be disable only when disable 1828 * parent pipe. 1829 */ 1830 if (pipe_ctx->top_pipe == NULL) { 1831 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); 1832 1833 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); 1834 if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) 1835 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 1836 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); 1837 } 1838 1839 for (i = 0; i < dc->res_pool->pipe_count; i++) 1840 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) 1841 break; 1842 1843 if (i == dc->res_pool->pipe_count) 1844 return; 1845 1846 pipe_ctx->stream = NULL; 1847 DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", 1848 pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); 1849 } 1850 1851 static void dcn20_reset_hw_ctx_wrap( 1852 struct dc *dc, 1853 struct dc_state *context) 1854 { 1855 int i; 1856 1857 /* Reset Back End*/ 1858 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { 1859 struct pipe_ctx *pipe_ctx_old = 1860 &dc->current_state->res_ctx.pipe_ctx[i]; 1861 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1862 1863 if (!pipe_ctx_old->stream) 1864 continue; 1865 1866 if (pipe_ctx_old->top_pipe) 1867 continue; 1868 1869 if (!pipe_ctx->stream || 1870 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { 1871 struct clock_source *old_clk = pipe_ctx_old->clock_source; 1872 1873 dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); 1874 if (dc->hwss.enable_stream_gating) 1875 dc->hwss.enable_stream_gating(dc, pipe_ctx); 1876 if (old_clk) 1877 old_clk->funcs->cs_power_down(old_clk); 1878 } 1879 } 1880 } 1881 1882 static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) 1883 { 1884 struct hubp *hubp = pipe_ctx->plane_res.hubp; 1885 struct mpcc_blnd_cfg blnd_cfg = { {0} }; 1886 bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; 1887 int mpcc_id; 1888 struct mpcc *new_mpcc; 1889 struct mpc *mpc = dc->res_pool->mpc; 1890 struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); 1891 1892 // input to MPCC is always RGB, by default leave black_color at 0 1893 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { 1894 dcn10_get_hdr_visual_confirm_color( 1895 pipe_ctx, &blnd_cfg.black_color); 1896 } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { 1897 dcn10_get_surface_visual_confirm_color( 1898 pipe_ctx, &blnd_cfg.black_color); 1899 } 1900 1901 if (per_pixel_alpha) 1902 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; 1903 else 1904 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; 1905 1906 blnd_cfg.overlap_only = false; 1907 blnd_cfg.global_gain = 0xff; 1908 1909 if (pipe_ctx->plane_state->global_alpha) 1910 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; 1911 else 1912 blnd_cfg.global_alpha = 0xff; 1913 1914 blnd_cfg.background_color_bpc = 4; 1915 blnd_cfg.bottom_gain_mode = 0; 1916 blnd_cfg.top_gain = 0x1f000; 1917 blnd_cfg.bottom_inside_gain = 0x1f000; 1918 blnd_cfg.bottom_outside_gain = 0x1f000; 1919 blnd_cfg.pre_multiplied_alpha = per_pixel_alpha; 1920 1921 /* 1922 * TODO: remove hack 1923 * Note: currently there is a bug in init_hw such that 1924 * on resume from hibernate, BIOS sets up MPCC0, and 1925 * we do mpcc_remove but the mpcc cannot go to idle 1926 * after remove. This cause us to pick mpcc1 here, 1927 * which causes a pstate hang for yet unknown reason. 1928 */ 1929 mpcc_id = hubp->inst; 1930 1931 /* If there is no full update, don't need to touch MPC tree*/ 1932 if (!pipe_ctx->plane_state->update_flags.bits.full_update) { 1933 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); 1934 return; 1935 } 1936 1937 /* check if this MPCC is already being used */ 1938 new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); 1939 /* remove MPCC if being used */ 1940 if (new_mpcc != NULL) 1941 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); 1942 else 1943 if (dc->debug.sanity_checks) 1944 mpc->funcs->assert_mpcc_idle_before_connect( 1945 dc->res_pool->mpc, mpcc_id); 1946 1947 /* Call MPC to insert new plane */ 1948 new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, 1949 mpc_tree_params, 1950 &blnd_cfg, 1951 NULL, 1952 NULL, 1953 hubp->inst, 1954 mpcc_id); 1955 1956 ASSERT(new_mpcc != NULL); 1957 hubp->opp_id = pipe_ctx->stream_res.opp->inst; 1958 hubp->mpcc_id = mpcc_id; 1959 } 1960 1961 static int find_free_gsl_group(const struct dc *dc) 1962 { 1963 if (dc->res_pool->gsl_groups.gsl_0 == 0) 1964 return 1; 1965 if (dc->res_pool->gsl_groups.gsl_1 == 0) 1966 return 2; 1967 if (dc->res_pool->gsl_groups.gsl_2 == 0) 1968 return 3; 1969 1970 return 0; 1971 } 1972 1973 /* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) 1974 * This is only used to lock pipes in pipe splitting case with immediate flip 1975 * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate, 1976 * so we get tearing with freesync since we cannot flip multiple pipes 1977 * atomically. 1978 * We use GSL for this: 1979 * - immediate flip: find first available GSL group if not already assigned 1980 * program gsl with that group, set current OTG as master 1981 * and always us 0x4 = AND of flip_ready from all pipes 1982 * - vsync flip: disable GSL if used 1983 * 1984 * Groups in stream_res are stored as +1 from HW registers, i.e. 1985 * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1 1986 * Using a magic value like -1 would require tracking all inits/resets 1987 */ 1988 void dcn20_setup_gsl_group_as_lock( 1989 const struct dc *dc, 1990 struct pipe_ctx *pipe_ctx, 1991 bool enable) 1992 { 1993 struct gsl_params gsl; 1994 int group_idx; 1995 1996 memset(&gsl, 0, sizeof(struct gsl_params)); 1997 1998 if (enable) { 1999 /* return if group already assigned since GSL was set up 2000 * for vsync flip, we would unassign so it can't be "left over" 2001 */ 2002 if (pipe_ctx->stream_res.gsl_group > 0) 2003 return; 2004 2005 group_idx = find_free_gsl_group(dc); 2006 ASSERT(group_idx != 0); 2007 pipe_ctx->stream_res.gsl_group = group_idx; 2008 2009 /* set gsl group reg field and mark resource used */ 2010 switch (group_idx) { 2011 case 1: 2012 gsl.gsl0_en = 1; 2013 dc->res_pool->gsl_groups.gsl_0 = 1; 2014 break; 2015 case 2: 2016 gsl.gsl1_en = 1; 2017 dc->res_pool->gsl_groups.gsl_1 = 1; 2018 break; 2019 case 3: 2020 gsl.gsl2_en = 1; 2021 dc->res_pool->gsl_groups.gsl_2 = 1; 2022 break; 2023 default: 2024 BREAK_TO_DEBUGGER(); 2025 return; // invalid case 2026 } 2027 gsl.gsl_master_en = 1; 2028 } else { 2029 group_idx = pipe_ctx->stream_res.gsl_group; 2030 if (group_idx == 0) 2031 return; // if not in use, just return 2032 2033 pipe_ctx->stream_res.gsl_group = 0; 2034 2035 /* unset gsl group reg field and mark resource free */ 2036 switch (group_idx) { 2037 case 1: 2038 gsl.gsl0_en = 0; 2039 dc->res_pool->gsl_groups.gsl_0 = 0; 2040 break; 2041 case 2: 2042 gsl.gsl1_en = 0; 2043 dc->res_pool->gsl_groups.gsl_1 = 0; 2044 break; 2045 case 3: 2046 gsl.gsl2_en = 0; 2047 dc->res_pool->gsl_groups.gsl_2 = 0; 2048 break; 2049 default: 2050 BREAK_TO_DEBUGGER(); 2051 return; 2052 } 2053 gsl.gsl_master_en = 0; 2054 } 2055 2056 /* at this point we want to program whether it's to enable or disable */ 2057 if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL && 2058 pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) { 2059 pipe_ctx->stream_res.tg->funcs->set_gsl( 2060 pipe_ctx->stream_res.tg, 2061 &gsl); 2062 2063 pipe_ctx->stream_res.tg->funcs->set_gsl_source_select( 2064 pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); 2065 } else 2066 BREAK_TO_DEBUGGER(); 2067 } 2068 2069 static void dcn20_set_flip_control_gsl( 2070 struct pipe_ctx *pipe_ctx, 2071 bool flip_immediate) 2072 { 2073 if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl) 2074 pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl( 2075 pipe_ctx->plane_res.hubp, flip_immediate); 2076 2077 } 2078 2079 static void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) 2080 { 2081 enum dc_lane_count lane_count = 2082 pipe_ctx->stream->link->cur_link_settings.lane_count; 2083 2084 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; 2085 struct dc_link *link = pipe_ctx->stream->link; 2086 2087 uint32_t active_total_with_borders; 2088 uint32_t early_control = 0; 2089 struct timing_generator *tg = pipe_ctx->stream_res.tg; 2090 2091 /* For MST, there are multiply stream go to only one link. 2092 * connect DIG back_end to front_end while enable_stream and 2093 * disconnect them during disable_stream 2094 * BY this, it is logic clean to separate stream and link 2095 */ 2096 link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, 2097 pipe_ctx->stream_res.stream_enc->id, true); 2098 2099 if (link->dc->hwss.program_dmdata_engine) 2100 link->dc->hwss.program_dmdata_engine(pipe_ctx); 2101 2102 link->dc->hwss.update_info_frame(pipe_ctx); 2103 2104 /* enable early control to avoid corruption on DP monitor*/ 2105 active_total_with_borders = 2106 timing->h_addressable 2107 + timing->h_border_left 2108 + timing->h_border_right; 2109 2110 if (lane_count != 0) 2111 early_control = active_total_with_borders % lane_count; 2112 2113 if (early_control == 0) 2114 early_control = lane_count; 2115 2116 tg->funcs->set_early_control(tg, early_control); 2117 2118 /* enable audio only within mode set */ 2119 if (pipe_ctx->stream_res.audio != NULL) { 2120 if (dc_is_dp_signal(pipe_ctx->stream->signal)) 2121 pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); 2122 } 2123 } 2124 2125 static void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) 2126 { 2127 struct dc_stream_state *stream = pipe_ctx->stream; 2128 struct hubp *hubp = pipe_ctx->plane_res.hubp; 2129 bool enable = false; 2130 struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; 2131 enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) 2132 ? dmdata_dp 2133 : dmdata_hdmi; 2134 2135 /* if using dynamic meta, don't set up generic infopackets */ 2136 if (pipe_ctx->stream->dmdata_address.quad_part != 0) { 2137 pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; 2138 enable = true; 2139 } 2140 2141 if (!hubp) 2142 return; 2143 2144 if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) 2145 return; 2146 2147 stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, 2148 hubp->inst, mode); 2149 } 2150 2151 void dcn20_hw_sequencer_construct(struct dc *dc) 2152 { 2153 dcn10_hw_sequencer_construct(dc); 2154 dc->hwss.init_hw = dcn20_init_hw; 2155 dc->hwss.init_pipes = NULL; 2156 dc->hwss.unblank_stream = dcn20_unblank_stream; 2157 dc->hwss.update_plane_addr = dcn20_update_plane_addr; 2158 dc->hwss.disable_plane = dcn20_disable_plane, 2159 dc->hwss.enable_stream_timing = dcn20_enable_stream_timing; 2160 dc->hwss.program_triplebuffer = dcn20_program_tripleBuffer; 2161 dc->hwss.set_input_transfer_func = dcn20_set_input_transfer_func; 2162 dc->hwss.set_output_transfer_func = dcn20_set_output_transfer_func; 2163 dc->hwss.apply_ctx_for_surface = dcn20_apply_ctx_for_surface; 2164 dc->hwss.pipe_control_lock = dcn20_pipe_control_lock; 2165 dc->hwss.pipe_control_lock_global = dcn20_pipe_control_lock_global; 2166 dc->hwss.optimize_bandwidth = dcn20_optimize_bandwidth; 2167 dc->hwss.prepare_bandwidth = dcn20_prepare_bandwidth; 2168 dc->hwss.update_bandwidth = dcn20_update_bandwidth; 2169 dc->hwss.enable_writeback = dcn20_enable_writeback; 2170 dc->hwss.disable_writeback = dcn20_disable_writeback; 2171 dc->hwss.program_output_csc = dcn20_program_output_csc; 2172 dc->hwss.update_odm = dcn20_update_odm; 2173 dc->hwss.blank_pixel_data = dcn20_blank_pixel_data; 2174 dc->hwss.dmdata_status_done = dcn20_dmdata_status_done; 2175 dc->hwss.program_dmdata_engine = dcn20_program_dmdata_engine; 2176 dc->hwss.enable_stream = dcn20_enable_stream; 2177 dc->hwss.disable_stream = dcn20_disable_stream; 2178 dc->hwss.init_sys_ctx = dcn20_init_sys_ctx; 2179 dc->hwss.init_vm_ctx = dcn20_init_vm_ctx; 2180 dc->hwss.disable_stream_gating = dcn20_disable_stream_gating; 2181 dc->hwss.enable_stream_gating = dcn20_enable_stream_gating; 2182 dc->hwss.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt; 2183 dc->hwss.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap; 2184 dc->hwss.update_mpcc = dcn20_update_mpcc; 2185 dc->hwss.set_flip_control_gsl = dcn20_set_flip_control_gsl; 2186 dc->hwss.did_underflow_occur = dcn10_did_underflow_occur; 2187 } 2188