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