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