1 /* 2 * Copyright 2012-15 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 26 #include "dm_services.h" 27 #include "basics/dc_common.h" 28 #include "dc.h" 29 #include "core_types.h" 30 #include "resource.h" 31 #include "ipp.h" 32 #include "timing_generator.h" 33 #include "dc_dmub_srv.h" 34 #include "dc_state_priv.h" 35 #include "dc_stream_priv.h" 36 37 #define DC_LOGGER dc->ctx->logger 38 #ifndef MIN 39 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) 40 #endif 41 #ifndef MAX 42 #define MAX(x, y) ((x > y) ? x : y) 43 #endif 44 45 #include "dc_fpu.h" 46 47 #if !defined(DC_RUN_WITH_PREEMPTION_ENABLED) 48 #define DC_RUN_WITH_PREEMPTION_ENABLED(code) code 49 #endif // !DC_RUN_WITH_PREEMPTION_ENABLED 50 51 52 /******************************************************************************* 53 * Private functions 54 ******************************************************************************/ 55 void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink) 56 { 57 unsigned int pix_clk; 58 if (sink->sink_signal == SIGNAL_TYPE_NONE) 59 stream->signal = stream->link->connector_signal; 60 else 61 stream->signal = sink->sink_signal; 62 63 if (dc_is_dvi_signal(stream->signal)) { 64 if (stream->ctx->dc->caps.dual_link_dvi && 65 (stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK && 66 sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) 67 stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; 68 else 69 stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; 70 } 71 if (dc_is_hdmi_frl_signal(stream->signal)) { 72 pix_clk = stream->timing.pix_clk_100hz / 10; 73 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) 74 pix_clk /= 2; 75 76 // YCbCr422 to use assume 12-bit interface always, clock stays the same 77 if (stream->timing.pixel_encoding != PIXEL_ENCODING_YCBCR422) { 78 switch (stream->timing.display_color_depth) { 79 case COLOR_DEPTH_666: 80 case COLOR_DEPTH_888: 81 break; 82 case COLOR_DEPTH_101010: 83 pix_clk = pix_clk * 10 / 8; 84 break; 85 case COLOR_DEPTH_121212: 86 pix_clk = pix_clk * 12 / 8; 87 break; 88 default: 89 break; 90 } 91 } 92 if (pix_clk != 0 && pix_clk < HDMI2_TMDS_MAX_PIXEL_CLOCK) 93 stream->signal = SIGNAL_TYPE_HDMI_TYPE_A; 94 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420 && 95 stream->timing.h_addressable > 4096) 96 stream->signal = SIGNAL_TYPE_HDMI_FRL; 97 if (stream->timing.rid != 0) 98 stream->signal = SIGNAL_TYPE_HDMI_FRL; 99 100 if (stream->link->frl_flags.force_frl_always || 101 stream->link->frl_flags.force_frl_max 102 || stream->link->frl_flags.force_frl_dsc) 103 stream->signal = SIGNAL_TYPE_HDMI_FRL; 104 } 105 } 106 107 bool dc_stream_construct(struct dc_stream_state *stream, 108 struct dc_sink *dc_sink_data) 109 { 110 uint32_t i = 0; 111 112 stream->sink = dc_sink_data; 113 dc_sink_retain(dc_sink_data); 114 115 stream->ctx = dc_sink_data->ctx; 116 stream->link = dc_sink_data->link; 117 stream->sink_patches = dc_sink_data->edid_caps.panel_patch; 118 stream->converter_disable_audio = dc_sink_data->converter_disable_audio; 119 stream->qs_bit = dc_sink_data->edid_caps.qs_bit; 120 stream->qy_bit = dc_sink_data->edid_caps.qy_bit; 121 122 /* Copy audio modes */ 123 /* TODO - Remove this translation */ 124 for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++) { 125 stream->audio_info.modes[i].channel_count = dc_sink_data->edid_caps.audio_modes[i].channel_count; 126 stream->audio_info.modes[i].format_code = dc_sink_data->edid_caps.audio_modes[i].format_code; 127 stream->audio_info.modes[i].sample_rates.all = dc_sink_data->edid_caps.audio_modes[i].sample_rate; 128 stream->audio_info.modes[i].sample_size = dc_sink_data->edid_caps.audio_modes[i].sample_size; 129 } 130 stream->audio_info.mode_count = dc_sink_data->edid_caps.audio_mode_count; 131 stream->audio_info.audio_latency = dc_sink_data->edid_caps.audio_latency; 132 stream->audio_info.video_latency = dc_sink_data->edid_caps.video_latency; 133 memmove( 134 stream->audio_info.display_name, 135 dc_sink_data->edid_caps.display_name, 136 AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS); 137 stream->audio_info.manufacture_id = dc_sink_data->edid_caps.manufacturer_id; 138 stream->audio_info.product_id = dc_sink_data->edid_caps.product_id; 139 stream->audio_info.flags.all = dc_sink_data->edid_caps.speaker_flags; 140 141 if (dc_sink_data->dc_container_id != NULL) { 142 struct dc_container_id *dc_container_id = dc_sink_data->dc_container_id; 143 144 stream->audio_info.port_id[0] = dc_container_id->portId[0]; 145 stream->audio_info.port_id[1] = dc_container_id->portId[1]; 146 } else { 147 /* TODO - WindowDM has implemented, 148 other DMs need Unhardcode port_id */ 149 stream->audio_info.port_id[0] = 0x5558859e; 150 stream->audio_info.port_id[1] = 0xd989449; 151 } 152 153 /* EDID CAP translation for HDMI 2.0 */ 154 stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble; 155 156 memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg)); 157 stream->timing.dsc_cfg.num_slices_h = 0; 158 stream->timing.dsc_cfg.num_slices_v = 0; 159 stream->timing.dsc_cfg.bits_per_pixel = 128; 160 stream->timing.dsc_cfg.block_pred_enable = 1; 161 stream->timing.dsc_cfg.linebuf_depth = 9; 162 stream->timing.dsc_cfg.version_minor = 2; 163 stream->timing.dsc_cfg.ycbcr422_simple = 0; 164 165 update_stream_signal(stream, dc_sink_data); 166 167 stream->out_transfer_func.type = TF_TYPE_BYPASS; 168 169 dc_stream_assign_stream_id(stream); 170 171 return true; 172 } 173 174 void dc_stream_destruct(struct dc_stream_state *stream) 175 { 176 dc_sink_release(stream->sink); 177 } 178 179 void dc_stream_assign_stream_id(struct dc_stream_state *stream) 180 { 181 /* MSB is reserved to indicate phantoms */ 182 stream->stream_id = stream->ctx->dc_stream_id_count; 183 stream->ctx->dc_stream_id_count++; 184 } 185 186 void dc_stream_retain(struct dc_stream_state *stream) 187 { 188 kref_get(&stream->refcount); 189 } 190 191 static void dc_stream_free(struct kref *kref) 192 { 193 struct dc_stream_state *stream = container_of(kref, struct dc_stream_state, refcount); 194 195 dc_stream_destruct(stream); 196 kfree(stream->update_scratch); 197 kfree(stream); 198 } 199 200 void dc_stream_release(struct dc_stream_state *stream) 201 { 202 if (stream != NULL) { 203 kref_put(&stream->refcount, dc_stream_free); 204 } 205 } 206 207 struct dc_stream_state *dc_create_stream_for_sink( 208 struct dc_sink *sink) 209 { 210 struct dc_stream_state *stream = NULL; 211 212 if (sink == NULL) 213 goto fail; 214 215 DC_RUN_WITH_PREEMPTION_ENABLED(stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC)); 216 217 if (stream == NULL) 218 goto fail; 219 220 DC_RUN_WITH_PREEMPTION_ENABLED(stream->update_scratch = 221 kzalloc((int32_t) dc_update_scratch_space_size(), 222 GFP_ATOMIC)); 223 224 if (stream->update_scratch == NULL) 225 goto fail; 226 227 if (dc_stream_construct(stream, sink) == false) 228 goto fail; 229 230 kref_init(&stream->refcount); 231 232 return stream; 233 234 fail: 235 if (stream) { 236 kfree(stream->update_scratch); 237 kfree(stream); 238 } 239 240 return NULL; 241 } 242 243 struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) 244 { 245 struct dc_stream_state *new_stream; 246 247 new_stream = kmemdup(stream, sizeof(struct dc_stream_state), GFP_KERNEL); 248 if (!new_stream) 249 return NULL; 250 251 // Scratch is not meant to be reused across copies, as might have self-referential pointers 252 new_stream->update_scratch = kzalloc( 253 (int32_t) dc_update_scratch_space_size(), 254 GFP_KERNEL 255 ); 256 if (!new_stream->update_scratch) { 257 kfree(new_stream); 258 return NULL; 259 } 260 261 if (new_stream->sink) 262 dc_sink_retain(new_stream->sink); 263 264 dc_stream_assign_stream_id(new_stream); 265 266 /* If using dynamic encoder assignment, wait till stream committed to assign encoder. */ 267 if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign && 268 !new_stream->ctx->dc->config.unify_link_enc_assignment) 269 new_stream->link_enc = NULL; 270 271 kref_init(&new_stream->refcount); 272 273 return new_stream; 274 } 275 276 /** 277 * dc_stream_get_status() - Get current stream status of the given stream state 278 * @stream: The stream to get the stream status for. 279 * 280 * The given stream is expected to exist in dc->current_state. Otherwise, NULL 281 * will be returned. 282 */ 283 struct dc_stream_status *dc_stream_get_status( 284 struct dc_stream_state *stream) 285 { 286 struct dc *dc = stream->ctx->dc; 287 return dc_state_get_stream_status(dc->current_state, stream); 288 } 289 290 const struct dc_stream_status *dc_stream_get_status_const( 291 const struct dc_stream_state *stream) 292 { 293 struct dc *dc = stream->ctx->dc; 294 return dc_state_get_stream_status(dc->current_state, stream); 295 } 296 297 struct dc_link *dc_stream_get_link( 298 const struct dc_stream_state *stream) 299 { 300 return stream->link; 301 } 302 303 void program_cursor_attributes( 304 struct dc *dc, 305 struct dc_stream_state *stream) 306 { 307 uint8_t i; 308 struct resource_context *res_ctx; 309 struct pipe_ctx *pipe_to_program = NULL; 310 bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); 311 312 if (!stream) 313 return; 314 315 res_ctx = &dc->current_state->res_ctx; 316 317 for (i = 0; i < MAX_PIPES; i++) { 318 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; 319 320 if (pipe_ctx->stream != stream) 321 continue; 322 323 if (!pipe_to_program) { 324 pipe_to_program = pipe_ctx; 325 326 if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) { 327 dc->hwss.begin_cursor_offload_update(dc, pipe_ctx); 328 } else { 329 dc->hwss.cursor_lock(dc, pipe_to_program, true); 330 if (pipe_to_program->next_odm_pipe) 331 dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true); 332 } 333 } 334 335 dc->hwss.set_cursor_attribute(pipe_ctx); 336 if (dc->ctx->dmub_srv) 337 dc_send_update_cursor_info_to_dmu(pipe_ctx, i); 338 if (dc->hwss.set_cursor_sdr_white_level) 339 dc->hwss.set_cursor_sdr_white_level(pipe_ctx); 340 if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) 341 dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx); 342 } 343 344 if (pipe_to_program) { 345 if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) { 346 dc->hwss.commit_cursor_offload_update(dc, pipe_to_program); 347 } else { 348 dc->hwss.cursor_lock(dc, pipe_to_program, false); 349 if (pipe_to_program->next_odm_pipe) 350 dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false); 351 } 352 } 353 } 354 355 /* 356 * dc_stream_check_cursor_attributes() - Check validitity of cursor attributes and surface address 357 */ 358 bool dc_stream_check_cursor_attributes( 359 const struct dc_stream_state *stream, 360 struct dc_state *state, 361 const struct dc_cursor_attributes *attributes) 362 { 363 const struct dc *dc; 364 365 unsigned int max_cursor_size; 366 367 if (NULL == stream) { 368 dm_error("DC: dc_stream is NULL!\n"); 369 return false; 370 } 371 if (NULL == attributes) { 372 dm_error("DC: attributes is NULL!\n"); 373 return false; 374 } 375 376 if (attributes->address.quad_part == 0) { 377 dm_output_to_console("DC: Cursor address is 0!\n"); 378 return false; 379 } 380 381 dc = stream->ctx->dc; 382 383 /* SubVP is not compatible with HW cursor larger than what can fit in cursor SRAM. 384 * Therefore, if cursor is greater than this, fallback to SW cursor. 385 */ 386 if (dc->debug.allow_sw_cursor_fallback && dc->res_pool->funcs->get_max_hw_cursor_size) { 387 max_cursor_size = dc->res_pool->funcs->get_max_hw_cursor_size(dc, state, stream); 388 max_cursor_size = max_cursor_size * max_cursor_size * 4; 389 390 if (attributes->height * attributes->width * 4 > max_cursor_size) { 391 return false; 392 } 393 } 394 395 return true; 396 } 397 398 /* 399 * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address 400 */ 401 bool dc_stream_set_cursor_attributes( 402 struct dc_stream_state *stream, 403 const struct dc_cursor_attributes *attributes) 404 { 405 bool result = false; 406 407 if (!stream) 408 return false; 409 410 if (dc_stream_check_cursor_attributes(stream, stream->ctx->dc->current_state, attributes)) { 411 stream->cursor_attributes = *attributes; 412 result = true; 413 } 414 415 return result; 416 } 417 418 bool dc_stream_program_cursor_attributes( 419 struct dc_stream_state *stream, 420 const struct dc_cursor_attributes *attributes) 421 { 422 struct dc *dc; 423 bool reset_idle_optimizations = false; 424 425 if (!stream) 426 return false; 427 428 dc = stream->ctx->dc; 429 430 if (dc_stream_set_cursor_attributes(stream, attributes)) { 431 dc_z10_restore(dc); 432 /* disable idle optimizations while updating cursor */ 433 if (dc->idle_optimizations_allowed) { 434 dc_allow_idle_optimizations(dc, false); 435 reset_idle_optimizations = true; 436 } 437 438 program_cursor_attributes(dc, stream); 439 440 /* re-enable idle optimizations if necessary */ 441 if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle) 442 dc_allow_idle_optimizations(dc, true); 443 444 return true; 445 } 446 447 return false; 448 } 449 450 void program_cursor_position( 451 struct dc *dc, 452 struct dc_stream_state *stream) 453 { 454 uint8_t i; 455 struct resource_context *res_ctx; 456 struct pipe_ctx *pipe_to_program = NULL; 457 bool enable_cursor_offload = dc_dmub_srv_is_cursor_offload_enabled(dc); 458 459 if (!stream) 460 return; 461 462 res_ctx = &dc->current_state->res_ctx; 463 464 for (i = 0; i < MAX_PIPES; i++) { 465 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; 466 467 if (pipe_ctx->stream != stream || 468 (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || 469 !pipe_ctx->plane_state || 470 (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) || 471 (!pipe_ctx->plane_res.ipp && !pipe_ctx->plane_res.dpp)) 472 continue; 473 474 if (!pipe_to_program) { 475 pipe_to_program = pipe_ctx; 476 477 if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) 478 dc->hwss.begin_cursor_offload_update(dc, pipe_ctx); 479 else 480 dc->hwss.cursor_lock(dc, pipe_to_program, true); 481 } 482 483 dc->hwss.set_cursor_position(pipe_ctx); 484 if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) 485 dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx); 486 487 if (dc->ctx->dmub_srv) 488 dc_send_update_cursor_info_to_dmu(pipe_ctx, i); 489 } 490 491 if (pipe_to_program) { 492 if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) 493 dc->hwss.commit_cursor_offload_update(dc, pipe_to_program); 494 else 495 dc->hwss.cursor_lock(dc, pipe_to_program, false); 496 } 497 } 498 499 bool dc_stream_set_cursor_position( 500 struct dc_stream_state *stream, 501 const struct dc_cursor_position *position) 502 { 503 if (NULL == stream) { 504 dm_error("DC: dc_stream is NULL!\n"); 505 return false; 506 } 507 508 if (NULL == position) { 509 dm_error("DC: cursor position is NULL!\n"); 510 return false; 511 } 512 513 stream->cursor_position = *position; 514 515 516 return true; 517 } 518 519 bool dc_stream_program_cursor_position( 520 struct dc_stream_state *stream, 521 const struct dc_cursor_position *position) 522 { 523 struct dc *dc; 524 bool reset_idle_optimizations = false; 525 const struct dc_cursor_position *old_position; 526 527 if (!stream) 528 return false; 529 530 old_position = &stream->cursor_position; 531 dc = stream->ctx->dc; 532 533 if (dc_stream_set_cursor_position(stream, position)) { 534 dc_z10_restore(dc); 535 536 /* disable idle optimizations if enabling cursor */ 537 if (dc->idle_optimizations_allowed && 538 (!old_position->enable || dc->debug.exit_idle_opt_for_cursor_updates) && 539 position->enable) { 540 dc_allow_idle_optimizations(dc, false); 541 reset_idle_optimizations = true; 542 } 543 544 program_cursor_position(dc, stream); 545 /* re-enable idle optimizations if necessary */ 546 if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle) 547 dc_allow_idle_optimizations(dc, true); 548 549 /* apply/update visual confirm */ 550 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR) { 551 /* update software state */ 552 unsigned int i; 553 554 for (i = 0; i < dc->res_pool->pipe_count; i++) { 555 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 556 557 /* adjust visual confirm color for all pipes with current stream */ 558 if (stream == pipe_ctx->stream) { 559 get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); 560 561 /* programming hardware */ 562 if (pipe_ctx->plane_state) 563 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, 564 pipe_ctx->plane_res.hubp->mpcc_id); 565 } 566 } 567 } 568 569 if (stream->drr_trigger_mode == DRR_TRIGGER_ON_FLIP_AND_CURSOR) { 570 /* apply manual trigger */ 571 unsigned int i; 572 573 for (i = 0; i < dc->res_pool->pipe_count; i++) { 574 struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 575 576 /* trigger event on first pipe with current stream */ 577 if (stream == pipe_ctx->stream && 578 pipe_ctx->stream_res.tg->funcs->program_manual_trigger) { 579 pipe_ctx->stream_res.tg->funcs->program_manual_trigger( 580 pipe_ctx->stream_res.tg); 581 break; 582 } 583 } 584 } 585 586 return true; 587 } 588 589 return false; 590 } 591 592 bool dc_stream_add_writeback(struct dc *dc, 593 struct dc_stream_state *stream, 594 struct dc_writeback_info *wb_info) 595 { 596 bool isDrc = false; 597 unsigned int i = 0; 598 struct dwbc *dwb; 599 600 if (stream == NULL) { 601 dm_error("DC: dc_stream is NULL!\n"); 602 return false; 603 } 604 605 if (wb_info == NULL) { 606 dm_error("DC: dc_writeback_info is NULL!\n"); 607 return false; 608 } 609 610 if (wb_info->dwb_pipe_inst >= MAX_DWB_PIPES) { 611 dm_error("DC: writeback pipe is invalid!\n"); 612 return false; 613 } 614 615 dc_exit_ips_for_hw_access(dc); 616 617 wb_info->dwb_params.out_transfer_func = &stream->out_transfer_func; 618 619 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 620 dwb->dwb_is_drc = false; 621 622 /* recalculate and apply DML parameters */ 623 624 for (i = 0; i < stream->num_wb_info; i++) { 625 /*dynamic update*/ 626 if (stream->writeback_info[i].wb_enabled && 627 stream->writeback_info[i].dwb_pipe_inst == wb_info->dwb_pipe_inst) { 628 stream->writeback_info[i] = *wb_info; 629 isDrc = true; 630 } 631 } 632 633 if (!isDrc) { 634 ASSERT(stream->num_wb_info + 1 <= MAX_DWB_PIPES); 635 stream->writeback_info[stream->num_wb_info++] = *wb_info; 636 } 637 638 if (dc->hwss.enable_writeback) { 639 struct dc_stream_status *stream_status = dc_stream_get_status(stream); 640 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 641 if (stream_status) 642 dwb->otg_inst = stream_status->primary_otg_inst; 643 } 644 645 if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { 646 dm_error("DC: update_bandwidth failed!\n"); 647 return false; 648 } 649 650 /* enable writeback */ 651 if (dc->hwss.enable_writeback) { 652 dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; 653 654 if (dwb->funcs->is_enabled(dwb)) { 655 /* writeback pipe already enabled, only need to update */ 656 dc->hwss.update_writeback(dc, wb_info, dc->current_state); 657 } else { 658 /* Enable writeback pipe from scratch*/ 659 dc->hwss.enable_writeback(dc, wb_info, dc->current_state); 660 } 661 } 662 663 return true; 664 } 665 666 bool dc_stream_fc_disable_writeback(struct dc *dc, 667 struct dc_stream_state *stream, 668 uint32_t dwb_pipe_inst) 669 { 670 struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; 671 672 if (stream == NULL) { 673 dm_error("DC: dc_stream is NULL!\n"); 674 return false; 675 } 676 677 if (dwb_pipe_inst >= MAX_DWB_PIPES) { 678 dm_error("DC: writeback pipe is invalid!\n"); 679 return false; 680 } 681 682 if (stream->num_wb_info > MAX_DWB_PIPES) { 683 dm_error("DC: num_wb_info is invalid!\n"); 684 return false; 685 } 686 687 dc_exit_ips_for_hw_access(dc); 688 689 if (dwb->funcs->set_fc_enable) 690 dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE); 691 692 return true; 693 } 694 695 /** 696 * dc_stream_remove_writeback() - Disables writeback and removes writeback info. 697 * @dc: Display core control structure. 698 * @stream: Display core stream state. 699 * @dwb_pipe_inst: Display writeback pipe. 700 * 701 * Return: returns true on success, false otherwise. 702 */ 703 bool dc_stream_remove_writeback(struct dc *dc, 704 struct dc_stream_state *stream, 705 uint32_t dwb_pipe_inst) 706 { 707 unsigned int i, j; 708 if (stream == NULL) { 709 dm_error("DC: dc_stream is NULL!\n"); 710 return false; 711 } 712 713 if (dwb_pipe_inst >= MAX_DWB_PIPES) { 714 dm_error("DC: writeback pipe is invalid!\n"); 715 return false; 716 } 717 718 if (stream->num_wb_info > MAX_DWB_PIPES) { 719 dm_error("DC: num_wb_info is invalid!\n"); 720 return false; 721 } 722 723 /* remove writeback info for disabled writeback pipes from stream */ 724 for (i = 0, j = 0; i < stream->num_wb_info; i++) { 725 if (stream->writeback_info[i].wb_enabled) { 726 727 if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) 728 stream->writeback_info[i].wb_enabled = false; 729 730 /* trim the array */ 731 if (j < i) { 732 memcpy(&stream->writeback_info[j], &stream->writeback_info[i], 733 sizeof(struct dc_writeback_info)); 734 j++; 735 } 736 } 737 } 738 stream->num_wb_info = j; 739 740 /* recalculate and apply DML parameters */ 741 if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { 742 dm_error("DC: update_bandwidth failed!\n"); 743 return false; 744 } 745 746 dc_exit_ips_for_hw_access(dc); 747 748 /* disable writeback */ 749 if (dc->hwss.disable_writeback) { 750 struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; 751 752 if (dwb->funcs->is_enabled(dwb)) 753 dc->hwss.disable_writeback(dc, dwb_pipe_inst); 754 } 755 756 return true; 757 } 758 759 uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) 760 { 761 uint8_t i; 762 struct dc *dc = stream->ctx->dc; 763 struct resource_context *res_ctx = 764 &dc->current_state->res_ctx; 765 766 dc_exit_ips_for_hw_access(dc); 767 768 for (i = 0; i < MAX_PIPES; i++) { 769 struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; 770 771 if (res_ctx->pipe_ctx[i].stream != stream || !tg) 772 continue; 773 774 return tg->funcs->get_frame_count(tg); 775 } 776 777 return 0; 778 } 779 780 bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream, 781 const uint8_t *custom_sdp_message, 782 unsigned int sdp_message_size) 783 { 784 int i; 785 struct dc *dc; 786 struct resource_context *res_ctx; 787 788 if (stream == NULL) { 789 dm_error("DC: dc_stream is NULL!\n"); 790 return false; 791 } 792 793 dc = stream->ctx->dc; 794 res_ctx = &dc->current_state->res_ctx; 795 796 dc_exit_ips_for_hw_access(dc); 797 798 for (i = 0; i < MAX_PIPES; i++) { 799 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; 800 801 if (pipe_ctx->stream != stream) 802 continue; 803 804 if (dc->hwss.send_immediate_sdp_message != NULL) 805 dc->hwss.send_immediate_sdp_message(pipe_ctx, 806 custom_sdp_message, 807 sdp_message_size); 808 else 809 DC_LOG_WARNING("%s:send_immediate_sdp_message not implemented on this ASIC\n", 810 __func__); 811 812 } 813 814 return true; 815 } 816 817 bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, 818 uint32_t *v_blank_start, 819 uint32_t *v_blank_end, 820 uint32_t *h_position, 821 uint32_t *v_position) 822 { 823 uint8_t i; 824 bool ret = false; 825 struct dc *dc; 826 struct resource_context *res_ctx; 827 828 if (!stream->ctx) 829 return false; 830 831 dc = stream->ctx->dc; 832 res_ctx = &dc->current_state->res_ctx; 833 834 dc_exit_ips_for_hw_access(dc); 835 836 for (i = 0; i < MAX_PIPES; i++) { 837 struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; 838 839 if (res_ctx->pipe_ctx[i].stream != stream || !tg) 840 continue; 841 842 tg->funcs->get_scanoutpos(tg, 843 v_blank_start, 844 v_blank_end, 845 h_position, 846 v_position); 847 848 ret = true; 849 break; 850 } 851 852 return ret; 853 } 854 855 bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) 856 { 857 struct pipe_ctx *pipe = NULL; 858 int i; 859 860 if (!dc->hwss.dmdata_status_done) 861 return false; 862 863 for (i = 0; i < MAX_PIPES; i++) { 864 pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 865 if (pipe->stream == stream) 866 break; 867 } 868 /* Stream not found, by default we'll assume HUBP fetched dm data */ 869 if (i == MAX_PIPES) 870 return true; 871 872 dc_exit_ips_for_hw_access(dc); 873 874 return dc->hwss.dmdata_status_done(pipe); 875 } 876 877 bool dc_stream_set_dynamic_metadata(struct dc *dc, 878 struct dc_stream_state *stream, 879 struct dc_dmdata_attributes *attr) 880 { 881 struct pipe_ctx *pipe_ctx = NULL; 882 struct hubp *hubp; 883 int i; 884 885 /* Dynamic metadata is only supported on HDMI or DP */ 886 if (!dc_is_hdmi_signal(stream->signal) && !dc_is_dp_signal(stream->signal)) 887 return false; 888 889 /* Check hardware support */ 890 if (!dc->hwss.program_dmdata_engine) 891 return false; 892 893 for (i = 0; i < MAX_PIPES; i++) { 894 pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; 895 if (pipe_ctx->stream == stream) 896 break; 897 } 898 899 if (i == MAX_PIPES) 900 return false; 901 902 hubp = pipe_ctx->plane_res.hubp; 903 if (hubp == NULL) 904 return false; 905 906 pipe_ctx->stream->dmdata_address = attr->address; 907 908 dc_exit_ips_for_hw_access(dc); 909 910 dc->hwss.program_dmdata_engine(pipe_ctx); 911 912 if (hubp->funcs->dmdata_set_attributes != NULL && 913 pipe_ctx->stream->dmdata_address.quad_part != 0) { 914 hubp->funcs->dmdata_set_attributes(hubp, attr); 915 } 916 917 return true; 918 } 919 920 enum dc_status dc_stream_add_dsc_to_resource(struct dc *dc, 921 struct dc_state *state, 922 struct dc_stream_state *stream) 923 { 924 if (dc->res_pool->funcs->add_dsc_to_stream_resource) { 925 return dc->res_pool->funcs->add_dsc_to_stream_resource(dc, state, stream); 926 } else { 927 return DC_NO_DSC_RESOURCE; 928 } 929 } 930 931 struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream) 932 { 933 int i = 0; 934 935 for (i = 0; i < MAX_PIPES; i++) { 936 struct pipe_ctx *pipe = &stream->ctx->dc->current_state->res_ctx.pipe_ctx[i]; 937 938 if (pipe->stream == stream) 939 return pipe; 940 } 941 942 return NULL; 943 } 944 945 void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) 946 { 947 DC_LOG_DC( 948 "core_stream 0x%p: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n", 949 stream, 950 stream->src.x, 951 stream->src.y, 952 stream->src.width, 953 stream->src.height, 954 stream->dst.x, 955 stream->dst.y, 956 stream->dst.width, 957 stream->dst.height, 958 stream->output_color_space); 959 DC_LOG_DC( 960 "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixel_encoding:%s, color_depth:%s\n", 961 stream->timing.pix_clk_100hz / 10, 962 stream->timing.h_total, 963 stream->timing.v_total, 964 dc_pixel_encoding_to_str(stream->timing.pixel_encoding), 965 dc_color_depth_to_str(stream->timing.display_color_depth)); 966 DC_LOG_DC( 967 "\tlink: %d\n", 968 stream->link->link_index); 969 970 DC_LOG_DC( 971 "\tdsc: %d, mst_pbn: %d\n", 972 stream->timing.flags.DSC, 973 stream->timing.dsc_cfg.mst_pbn); 974 975 if (stream->sink) { 976 if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL && 977 stream->sink->sink_signal != SIGNAL_TYPE_NONE) { 978 979 DC_LOG_DC( 980 "\tsignal: %x dispname: %s manufacturer_id: 0x%x product_id: 0x%x\n", 981 stream->signal, 982 stream->sink->edid_caps.display_name, 983 stream->sink->edid_caps.manufacturer_id, 984 stream->sink->edid_caps.product_id); 985 } 986 } 987 } 988 989 /* 990 * dc_stream_get_3dlut() 991 * Requirements: 992 * 1. Is stream already owns an RMCM instance, return it. 993 * 2. If it doesn't and we don't need to allocate, return NULL. 994 * 3. If there's a free RMCM instance, assign to stream and return it. 995 * 4. If no free RMCM instances, return NULL. 996 */ 997 998 struct dc_rmcm_3dlut *dc_stream_get_3dlut_for_stream( 999 const struct dc *dc, 1000 const struct dc_stream_state *stream, 1001 bool allocate_one) 1002 { 1003 unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts; 1004 1005 // see if one is allocated for this stream 1006 for (unsigned int i = 0; i < num_rmcm; i++) { 1007 if (dc->res_pool->rmcm_3dlut[i].isInUse && 1008 dc->res_pool->rmcm_3dlut[i].stream == stream) 1009 return &dc->res_pool->rmcm_3dlut[i]; 1010 } 1011 1012 //case: not found one, and dont need to allocate 1013 if (!allocate_one) 1014 return NULL; 1015 1016 //see if there is an unused 3dlut, allocate 1017 for (unsigned int i = 0; i < num_rmcm; i++) { 1018 if (!dc->res_pool->rmcm_3dlut[i].isInUse) { 1019 dc->res_pool->rmcm_3dlut[i].isInUse = true; 1020 dc->res_pool->rmcm_3dlut[i].stream = stream; 1021 return &dc->res_pool->rmcm_3dlut[i]; 1022 } 1023 } 1024 1025 //dont have a 3dlut 1026 return NULL; 1027 } 1028 1029 1030 void dc_stream_release_3dlut_for_stream( 1031 const struct dc *dc, 1032 const struct dc_stream_state *stream) 1033 { 1034 struct dc_rmcm_3dlut *rmcm_3dlut = 1035 dc_stream_get_3dlut_for_stream(dc, stream, false); 1036 1037 if (rmcm_3dlut) { 1038 rmcm_3dlut->isInUse = false; 1039 rmcm_3dlut->stream = NULL; 1040 rmcm_3dlut->protection_bits = 0; 1041 } 1042 } 1043 1044 1045 void dc_stream_init_rmcm_3dlut(struct dc *dc) 1046 { 1047 unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts; 1048 1049 for (unsigned int i = 0; i < num_rmcm; i++) { 1050 dc->res_pool->rmcm_3dlut[i].isInUse = false; 1051 dc->res_pool->rmcm_3dlut[i].stream = NULL; 1052 dc->res_pool->rmcm_3dlut[i].protection_bits = 0; 1053 } 1054 } 1055 1056 /* 1057 * Finds the greatest index in refresh_rate_hz that contains a value <= refresh 1058 */ 1059 static int dc_stream_get_nearest_smallest_index(struct dc_stream_state *stream, int refresh) 1060 { 1061 for (int i = 0; i < (LUMINANCE_DATA_TABLE_SIZE - 1); ++i) { 1062 if ((stream->lumin_data.refresh_rate_hz[i] <= refresh) && (refresh < stream->lumin_data.refresh_rate_hz[i + 1])) { 1063 return i; 1064 } 1065 } 1066 return 9; 1067 } 1068 1069 /* 1070 * Finds a corresponding brightness for a given refresh rate between 2 given indices, where index1 < index2 1071 */ 1072 static int dc_stream_get_brightness_millinits_linear_interpolation (struct dc_stream_state *stream, 1073 int index1, 1074 int index2, 1075 int refresh_hz) 1076 { 1077 long long slope = 0; 1078 long long y_intercept = 0; 1079 long long brightness_millinits = 0; 1080 1081 if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) { 1082 slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) / 1083 (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]); 1084 } 1085 1086 y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2]; 1087 brightness_millinits = y_intercept + (long long)refresh_hz * slope; 1088 1089 return (int)brightness_millinits; 1090 } 1091 1092 /* 1093 * Finds a corresponding refresh rate for a given brightness between 2 given indices, where index1 < index2 1094 */ 1095 static int dc_stream_get_refresh_hz_linear_interpolation (struct dc_stream_state *stream, 1096 int index1, 1097 int index2, 1098 int brightness_millinits) 1099 { 1100 long long slope = 1; 1101 long long y_intercept = 0; 1102 long long refresh_hz = 0; 1103 1104 if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) { 1105 slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) / 1106 (stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]); 1107 } 1108 1109 y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2]; 1110 refresh_hz = div64_s64((brightness_millinits - y_intercept), slope); 1111 1112 return (int)refresh_hz; 1113 } 1114 1115 /* 1116 * Finds the current brightness in millinits given a refresh rate 1117 */ 1118 static int dc_stream_get_brightness_millinits_from_refresh (struct dc_stream_state *stream, int refresh_hz) 1119 { 1120 int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, refresh_hz); 1121 int nearest_smallest_value = stream->lumin_data.refresh_rate_hz[nearest_smallest_index]; 1122 1123 if (nearest_smallest_value == refresh_hz) 1124 return stream->lumin_data.luminance_millinits[nearest_smallest_index]; 1125 1126 if (nearest_smallest_index >= 9) 1127 return dc_stream_get_brightness_millinits_linear_interpolation(stream, nearest_smallest_index - 1, nearest_smallest_index, refresh_hz); 1128 1129 if (nearest_smallest_value == stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1]) 1130 return stream->lumin_data.luminance_millinits[nearest_smallest_index]; 1131 1132 return dc_stream_get_brightness_millinits_linear_interpolation(stream, nearest_smallest_index, nearest_smallest_index + 1, refresh_hz); 1133 } 1134 1135 /* 1136 * Finds the lowest/highest refresh rate (depending on search_for_max_increase) 1137 * that can be achieved from starting_refresh_hz while staying 1138 * within flicker criteria 1139 */ 1140 static int dc_stream_calculate_flickerless_refresh_rate(struct dc_stream_state *stream, 1141 int current_brightness, 1142 int starting_refresh_hz, 1143 bool is_gaming, 1144 bool search_for_max_increase) 1145 { 1146 int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, starting_refresh_hz); 1147 1148 int flicker_criteria_millinits = is_gaming ? 1149 stream->lumin_data.flicker_criteria_milli_nits_GAMING : 1150 stream->lumin_data.flicker_criteria_milli_nits_STATIC; 1151 1152 int safe_upper_bound = current_brightness + flicker_criteria_millinits; 1153 int safe_lower_bound = current_brightness - flicker_criteria_millinits; 1154 int lumin_millinits_temp = 0; 1155 1156 int offset = -1; 1157 if (search_for_max_increase) { 1158 offset = 1; 1159 } 1160 1161 /* 1162 * Increments up or down by 1 depending on search_for_max_increase 1163 */ 1164 for (int i = nearest_smallest_index; (i > 0 && !search_for_max_increase) || (i < (LUMINANCE_DATA_TABLE_SIZE - 1) && search_for_max_increase); i += offset) { 1165 1166 lumin_millinits_temp = stream->lumin_data.luminance_millinits[i + offset]; 1167 1168 if ((lumin_millinits_temp >= safe_upper_bound) || (lumin_millinits_temp <= safe_lower_bound)) { 1169 1170 if (stream->lumin_data.refresh_rate_hz[i + offset] == stream->lumin_data.refresh_rate_hz[i]) 1171 return stream->lumin_data.refresh_rate_hz[i]; 1172 1173 int target_brightness = (stream->lumin_data.luminance_millinits[i + offset] >= (current_brightness + flicker_criteria_millinits)) ? 1174 current_brightness + flicker_criteria_millinits : 1175 current_brightness - flicker_criteria_millinits; 1176 1177 int refresh = 0; 1178 1179 /* 1180 * Need the second input to be < third input for dc_stream_get_refresh_hz_linear_interpolation 1181 */ 1182 if (search_for_max_increase) 1183 refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i, i + offset, target_brightness); 1184 else 1185 refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i + offset, i, target_brightness); 1186 1187 if (refresh == stream->lumin_data.refresh_rate_hz[i + offset]) 1188 return stream->lumin_data.refresh_rate_hz[i + offset]; 1189 1190 return refresh; 1191 } 1192 } 1193 1194 if (search_for_max_increase) 1195 return (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, stream->timing.v_total*(long long)stream->timing.h_total); 1196 else 1197 return stream->lumin_data.refresh_rate_hz[0]; 1198 } 1199 1200 /* 1201 * Gets the max delta luminance within a specified refresh range 1202 */ 1203 static int dc_stream_get_max_delta_lumin_millinits(struct dc_stream_state *stream, int hz1, int hz2, bool isGaming) 1204 { 1205 int lower_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz1); 1206 int higher_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz2); 1207 1208 int min = lower_refresh_brightness; 1209 int max = higher_refresh_brightness; 1210 1211 /* 1212 * Static screen, therefore no need to scan through array 1213 */ 1214 if (!isGaming) { 1215 if (lower_refresh_brightness >= higher_refresh_brightness) { 1216 return lower_refresh_brightness - higher_refresh_brightness; 1217 } 1218 return higher_refresh_brightness - lower_refresh_brightness; 1219 } 1220 1221 min = MIN(lower_refresh_brightness, higher_refresh_brightness); 1222 max = MAX(lower_refresh_brightness, higher_refresh_brightness); 1223 1224 int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, hz1); 1225 1226 for (; nearest_smallest_index < (LUMINANCE_DATA_TABLE_SIZE - 1) && 1227 stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1] <= hz2 ; nearest_smallest_index++) { 1228 min = MIN(min, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]); 1229 max = MAX(max, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]); 1230 } 1231 1232 return (max - min); 1233 } 1234 1235 /* 1236 * Determines the max flickerless instant vtotal delta for a stream. 1237 * Determines vtotal increase/decrease based on the bool "increase" 1238 */ 1239 static unsigned int dc_stream_get_max_flickerless_instant_vtotal_delta(struct dc_stream_state *stream, bool is_gaming, bool increase) 1240 { 1241 if (stream->timing.v_total * stream->timing.h_total == 0) 1242 return 0; 1243 1244 int current_refresh_hz = (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, stream->timing.v_total*(long long)stream->timing.h_total); 1245 1246 int safe_refresh_hz = dc_stream_calculate_flickerless_refresh_rate(stream, 1247 dc_stream_get_brightness_millinits_from_refresh(stream, current_refresh_hz), 1248 current_refresh_hz, 1249 is_gaming, 1250 increase); 1251 1252 int safe_refresh_v_total = (int)div64_s64((long long)stream->timing.pix_clk_100hz*100, safe_refresh_hz*(long long)stream->timing.h_total); 1253 1254 if (increase) 1255 return (((int) stream->timing.v_total - safe_refresh_v_total) >= 0) ? (stream->timing.v_total - safe_refresh_v_total) : 0; 1256 1257 return ((safe_refresh_v_total - (int) stream->timing.v_total) >= 0) ? (safe_refresh_v_total - stream->timing.v_total) : 0; 1258 } 1259 1260 /* 1261 * Finds the highest refresh rate that can be achieved 1262 * from starting_refresh_hz while staying within flicker criteria 1263 */ 1264 int dc_stream_calculate_max_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming) 1265 { 1266 if (!stream->lumin_data.is_valid) 1267 return 0; 1268 1269 int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz); 1270 1271 return dc_stream_calculate_flickerless_refresh_rate(stream, 1272 current_brightness, 1273 starting_refresh_hz, 1274 is_gaming, 1275 true); 1276 } 1277 1278 /* 1279 * Finds the lowest refresh rate that can be achieved 1280 * from starting_refresh_hz while staying within flicker criteria 1281 */ 1282 int dc_stream_calculate_min_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming) 1283 { 1284 if (!stream->lumin_data.is_valid) 1285 return 0; 1286 1287 int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz); 1288 1289 return dc_stream_calculate_flickerless_refresh_rate(stream, 1290 current_brightness, 1291 starting_refresh_hz, 1292 is_gaming, 1293 false); 1294 } 1295 1296 /* 1297 * Determines if there will be a flicker when moving between 2 refresh rates 1298 */ 1299 bool dc_stream_is_refresh_rate_range_flickerless(struct dc_stream_state *stream, int hz1, int hz2, bool is_gaming) 1300 { 1301 1302 /* 1303 * Assume that we wont flicker if there is invalid data 1304 */ 1305 if (!stream->lumin_data.is_valid) 1306 return false; 1307 1308 int dl = dc_stream_get_max_delta_lumin_millinits(stream, hz1, hz2, is_gaming); 1309 1310 int flicker_criteria_millinits = (is_gaming) ? 1311 stream->lumin_data.flicker_criteria_milli_nits_GAMING : 1312 stream->lumin_data.flicker_criteria_milli_nits_STATIC; 1313 1314 return (dl <= flicker_criteria_millinits); 1315 } 1316 1317 /* 1318 * Determines the max instant vtotal delta increase that can be applied without 1319 * flickering for a given stream 1320 */ 1321 unsigned int dc_stream_get_max_flickerless_instant_vtotal_decrease(struct dc_stream_state *stream, 1322 bool is_gaming) 1323 { 1324 if (!stream->lumin_data.is_valid) 1325 return 0; 1326 1327 return dc_stream_get_max_flickerless_instant_vtotal_delta(stream, is_gaming, true); 1328 } 1329 1330 /* 1331 * Determines the max instant vtotal delta decrease that can be applied without 1332 * flickering for a given stream 1333 */ 1334 unsigned int dc_stream_get_max_flickerless_instant_vtotal_increase(struct dc_stream_state *stream, 1335 bool is_gaming) 1336 { 1337 if (!stream->lumin_data.is_valid) 1338 return 0; 1339 1340 return dc_stream_get_max_flickerless_instant_vtotal_delta(stream, is_gaming, false); 1341 } 1342 1343 bool dc_stream_is_cursor_limit_pending(struct dc *dc, struct dc_stream_state *stream) 1344 { 1345 bool is_limit_pending = false; 1346 1347 if (dc->current_state) 1348 is_limit_pending = dc_state_get_stream_cursor_subvp_limit(stream, dc->current_state); 1349 1350 return is_limit_pending; 1351 } 1352 1353 bool dc_stream_can_clear_cursor_limit(struct dc *dc, struct dc_stream_state *stream) 1354 { 1355 bool can_clear_limit = false; 1356 1357 if (dc->current_state) 1358 can_clear_limit = dc_state_get_stream_cursor_subvp_limit(stream, dc->current_state) && 1359 (stream->hw_cursor_req || 1360 !stream->cursor_position.enable || 1361 dc_stream_check_cursor_attributes(stream, dc->current_state, &stream->cursor_attributes)); 1362 1363 return can_clear_limit; 1364 } 1365