1 /* 2 * Copyright 2016 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dm_services.h" 27 #include "dc.h" 28 #include "mod_power.h" 29 #include "core_types.h" 30 #include "dmcu.h" 31 #include "abm.h" 32 #include "power_helpers.h" 33 #include "dce/dmub_psr.h" 34 #include "dal_asic_id.h" 35 #include "link_service.h" 36 #include <linux/math.h> 37 38 #define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ 39 #define DC_TRACE_LEVEL_MESSAGEP(...) /* do nothing */ 40 41 #define MOD_POWER_MAX_CONCURRENT_STREAMS 32 42 #define SMOOTH_BRIGHTNESS_ADJUSTMENT_TIME_IN_MS 500 43 #define LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND 25000 44 45 /* If system or panel does not report some sort of brightness percent to nits 46 * mapping, we will use following default values so backlight control using 47 * nits based interfaces will still work, but might not describe panel 48 * correctly. In this case percentage based backlight control should ideally 49 * be used. 50 * Min = 5 nits 51 * Max = 300 nits 52 */ 53 54 static const unsigned int pwr_default_min_brightness_millinits = 1000; 55 static const unsigned int pwr_default_sdr_brightness_millinits = 270000; 56 57 static const unsigned int default_ac_backlight_percent = 100; 58 static const unsigned int default_dc_backlight_percent = 70; 59 60 #define MOD_POWER_TO_CORE(mod_power)\ 61 container_of(mod_power, struct core_power, mod_public) 62 63 /* Given a specific dc_stream* this function finds its equivalent 64 * on the core_freesync->map and returns the corresponding index 65 */ 66 unsigned int map_index_from_stream(struct core_power *core_power, 67 const struct dc_stream_state *stream) 68 { 69 unsigned int index = 0; 70 71 for (index = 0; index < core_power->num_entities; index++) { 72 if (core_power->map[index].stream == stream) 73 return index; 74 } 75 /* Could not find stream requested, this is not trivial, fix when hit*/ 76 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 77 WPP_BIT_FLAG_Firmware_PsrState, 78 "map index from stream: ERROR: core_power=%p stream=%p", 79 core_power, 80 stream); 81 ASSERT(false); 82 /* We come here only when we can't map stream index. 83 * In good cases, this would happen when we attempt to change 84 * brightness before stream creation, in which case we create a 85 * dummy stream with index 0. 86 * With external monitor connected, the index passed from this return 87 * is 1. Passing anything greater than 0 from here would always point 88 * to bad memory. 89 */ 90 return 0; 91 } 92 93 bool mod_power_hw_init(struct mod_power *mod_power) 94 { 95 /* Call backlight initialization */ 96 return mod_power_hw_init_backlight(mod_power); 97 98 /* Future: Add other HW init here */ 99 } 100 101 struct mod_power *mod_power_create(struct dc *dc, 102 struct mod_power_init_params *init_params, 103 unsigned int edp_num) 104 { 105 struct core_power *core_power = NULL; 106 int i = 0; 107 unsigned int abm_max_config = 0; 108 unsigned int inst = 0; 109 bool is_brightness_range_valid = false; 110 111 if (dc == NULL) 112 goto fail_dc_null; 113 114 core_power = kzalloc(sizeof(struct core_power), GFP_KERNEL); 115 116 if (core_power == NULL) 117 goto fail_alloc_context; 118 119 core_power->edp_num = edp_num; 120 core_power->map = kzalloc(sizeof(struct power_entity) * MOD_POWER_MAX_CONCURRENT_STREAMS, 121 GFP_KERNEL); 122 123 if (core_power->map == NULL) 124 goto fail_alloc_map; 125 126 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) { 127 core_power->map[i].stream = NULL; 128 } 129 130 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) { 131 core_power->map[i].psr_context = 132 kzalloc(sizeof(struct mod_power_psr_context), 133 GFP_KERNEL); 134 if (core_power->map[i].psr_context == NULL) 135 goto fail_construct; 136 } 137 138 core_power->psr_smu_optimizations_support = init_params->allow_psr_smu_optimizations; 139 core_power->multi_disp_optimizations_support = init_params->allow_psr_multi_disp_optimizations; 140 141 for (inst = 0; inst < edp_num; inst++) { 142 core_power->bl_prop[inst].min_abm_backlight = 143 init_params[inst].min_abm_backlight; 144 core_power->bl_prop[inst].disable_fractional_pwm = 145 init_params[inst].disable_fractional_pwm; 146 core_power->bl_prop[inst].use_linear_backlight_curve = 147 init_params[inst].use_linear_backlight_curve; 148 core_power->bl_prop[inst].use_nits_based_brightness = 149 init_params[inst].use_nits_based_brightness; 150 core_power->bl_prop[inst].backlight_ramping_override = 151 init_params[inst].backlight_ramping_override; 152 core_power->bl_prop[inst].backlight_ramping_reduction = 153 init_params[inst].backlight_ramping_reduction; 154 core_power->bl_prop[inst].backlight_ramping_start = 155 init_params[inst].backlight_ramping_start; 156 core_power->bl_prop[inst].use_custom_backlight_caps = 157 init_params[inst].use_custom_backlight_caps; 158 core_power->bl_prop[inst].custom_backlight_caps_config_no = 159 init_params[inst].custom_backlight_caps_config_no; 160 161 // Do not allow less than 101 backlight levels 162 if (init_params[inst].num_backlight_levels < 101) 163 core_power->bl_prop[inst].num_backlight_levels = 101; 164 else 165 core_power->bl_prop[inst].num_backlight_levels = 166 init_params[inst].num_backlight_levels; 167 168 core_power->bl_prop[inst].backlight_lut = (unsigned int *) 169 (kzalloc(sizeof(unsigned int) * 170 core_power->bl_prop[inst].num_backlight_levels, GFP_KERNEL)); 171 if (core_power->bl_prop[inst].backlight_lut == NULL) 172 goto fail_alloc_backlight_array; 173 } 174 175 core_power->varibright_prop.varibright_active = false; 176 177 core_power->varibright_prop.varibright_user_enable = 178 init_params->def_varibright_enable; 179 180 // Table of ABM levels here is 1-4, but level 0 also exists as 'off' 181 if (init_params->varibright_level <= abm_defines_max_level) { 182 core_power->varibright_prop.varibright_level = 183 init_params->varibright_level; 184 185 } else { 186 core_power->varibright_prop.varibright_level = 3; 187 } 188 if (init_params->def_varibright_level <= abm_defines_max_level) { 189 core_power->varibright_prop.def_varibright_level = 190 init_params->def_varibright_level; 191 } else { 192 core_power->varibright_prop.def_varibright_level = 3; 193 } 194 195 // ABM used to contain 4 different configs. There is only 3 since ABM 2.3. 196 if ((dc->res_pool->dmcu != NULL) && (dc->res_pool->dmcu->dmcu_version.abm_version < 0x23)) 197 abm_max_config = 4; 198 else 199 abm_max_config = 3; 200 201 if (init_params->abm_config_setting < abm_max_config) 202 core_power->varibright_prop.varibright_config_setting = 203 init_params->abm_config_setting; 204 else 205 core_power->varibright_prop.varibright_config_setting = 0; 206 207 for (inst = 0; inst < edp_num; inst++) { 208 core_power->bl_prop[inst].backlight_lut[0] = init_params[inst].min_backlight_pwm; 209 core_power->bl_prop[inst].backlight_lut[ 210 core_power->bl_prop[inst].num_backlight_levels-1] = 211 init_params[inst].max_backlight_pwm; 212 core_power->bl_prop[inst].min_backlight_pwm = init_params[inst].min_backlight_pwm; 213 core_power->bl_prop[inst].max_backlight_pwm = init_params[inst].max_backlight_pwm; 214 core_power->bl_prop[inst].ac_backlight_percent = 215 default_ac_backlight_percent; 216 core_power->bl_prop[inst].dc_backlight_percent = 217 default_dc_backlight_percent; 218 core_power->bl_prop[inst].backlight_caps_valid = false; 219 220 if (core_power->bl_prop[inst].use_nits_based_brightness) { 221 core_power->bl_prop[inst].min_brightness_millinits = 222 init_params[inst].panel_min_millinits; 223 core_power->bl_prop[inst].max_brightness_millinits = 224 init_params[inst].panel_max_millinits; 225 } else { 226 227 core_power->bl_prop[inst].min_brightness_millinits = 228 pwr_default_min_brightness_millinits; 229 core_power->bl_prop[inst].max_brightness_millinits = 230 pwr_default_sdr_brightness_millinits; 231 } 232 233 core_power->bl_prop[inst].backlight_range = 234 core_power->bl_prop[inst].max_backlight_pwm- 235 core_power->bl_prop[inst].min_backlight_pwm; 236 237 core_power->bl_prop[inst].nits_range = 238 core_power->bl_prop[inst].max_brightness_millinits - 239 core_power->bl_prop[inst].min_brightness_millinits; 240 241 core_power->bl_state[inst].smooth_brightness_enabled = true; 242 } 243 244 /* Check if at least 1 instance in core_power is populated before failing */ 245 for (inst = 0; inst < edp_num; inst++) { 246 if (core_power->bl_prop[inst].nits_range != 0 && core_power->bl_prop[inst].backlight_range != 0) { 247 is_brightness_range_valid = true; 248 break; 249 } 250 251 } 252 if (!is_brightness_range_valid) 253 goto fail_bad_brightness_range; 254 255 core_power->num_entities = 0; 256 257 core_power->dc = dc; 258 for (inst = 0; inst < edp_num; inst++) { 259 initialize_backlight_caps(core_power, inst); 260 core_power->bl_state[inst].backlight_millipercent = 261 core_power->bl_prop[inst].dc_backlight_percent * 1000; 262 core_power->bl_state[inst].backlight_pwm = backlight_millipercent_to_pwm(core_power, 263 core_power->bl_state[inst].backlight_millipercent, inst); 264 core_power->bl_state[inst].backlight_millinit = backlight_millipercent_to_millinit(core_power, 265 core_power->bl_state[inst].backlight_millipercent, inst); 266 } 267 268 return &core_power->mod_public; 269 270 fail_bad_brightness_range: 271 fail_alloc_backlight_array: 272 for (inst = 0; inst < edp_num; inst++) 273 if (core_power->bl_prop[inst].backlight_lut) 274 kfree(core_power->bl_prop[inst].backlight_lut); 275 fail_construct: 276 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) { 277 if (core_power->map[i].psr_context) 278 kfree(core_power->map[i].psr_context); 279 } 280 kfree(core_power->map); 281 282 fail_alloc_map: 283 kfree(core_power); 284 285 fail_alloc_context: 286 fail_dc_null: 287 return NULL; 288 } 289 290 void mod_power_destroy(struct mod_power *mod_power) 291 { 292 if (mod_power != NULL) { 293 unsigned int i; 294 struct core_power *core_power = 295 MOD_POWER_TO_CORE(mod_power); 296 297 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) 298 if (core_power->map[i].psr_context) 299 kfree(core_power->map[i].psr_context); 300 301 for (i = 0; i < core_power->num_entities; i++) 302 if (core_power->map[i].stream) 303 dc_stream_release(core_power->map[i].stream); 304 305 kfree(core_power->map); 306 307 for (i = 0; i < MAX_NUM_EDP; i++) 308 if (core_power->bl_prop[i].backlight_lut) 309 kfree(core_power->bl_prop[i].backlight_lut); 310 311 kfree(core_power); 312 } 313 } 314 315 bool mod_power_add_stream(struct mod_power *mod_power, 316 struct dc_stream_state *stream, struct psr_caps *caps) 317 { 318 struct core_power *core_power = NULL; 319 320 if (mod_power == NULL) 321 return false; 322 323 core_power = MOD_POWER_TO_CORE(mod_power); 324 325 if (core_power->num_entities < MOD_POWER_MAX_CONCURRENT_STREAMS) { 326 dc_stream_retain(stream); 327 328 core_power->map[core_power->num_entities].stream = stream; 329 core_power->map[core_power->num_entities].caps = caps; 330 331 // initialize cached PSR params to something "safe" (something that is 332 // consistent with disabled PSR state) 333 core_power->map[core_power->num_entities].psr_enabled = 0; 334 core_power->map[core_power->num_entities].psr_events = psr_event_vsync; 335 core_power->map[core_power->num_entities].psr_power_opt = 0; 336 core_power->num_entities++; 337 return true; 338 } 339 340 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 341 WPP_BIT_FLAG_Firmware_PsrState, 342 "mod_power: add_stream: ERROR: stream=%p num_entities=%u >= MOD_POWER_MAX_CONCURRENT_STREAMS", 343 stream, 344 core_power->num_entities); 345 346 return false; 347 } 348 349 bool mod_power_remove_stream(struct mod_power *mod_power, 350 const struct dc_stream_state *stream) 351 { 352 unsigned int i = 0; 353 struct core_power *core_power = NULL; 354 unsigned int index = 0; 355 356 if (mod_power == NULL) 357 return false; 358 359 core_power = MOD_POWER_TO_CORE(mod_power); 360 if (core_power->num_entities == 0) { 361 /* trying to remove a stream a second time or have not added yet */ 362 BREAK_TO_DEBUGGER(); 363 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 364 WPP_BIT_FLAG_Firmware_PsrState, 365 "mod_power: remove_stream: ERROR: num_entities=0 stream=%p", 366 stream); 367 return false; 368 } 369 370 index = map_index_from_stream(core_power, stream); 371 372 if (index >= core_power->num_entities) { 373 /* trying to remove a stream a second time or have not added yet */ 374 BREAK_TO_DEBUGGER(); 375 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 376 WPP_BIT_FLAG_Firmware_PsrState, 377 "mod_power: remove_stream: ERROR: index=%u >= num_entities=%u stream=%p", 378 index, 379 core_power->num_entities, 380 stream); 381 return false; 382 } 383 384 dc_stream_release(core_power->map[index].stream); 385 core_power->map[index].stream = NULL; 386 /* To remove this entity, shift everything after down */ 387 for (i = index; i < core_power->num_entities - 1; i++) { 388 core_power->map[i].stream = core_power->map[i + 1].stream; 389 core_power->map[i].caps = core_power->map[i + 1].caps; 390 391 // copy over cached parameters in case they map to PSR capable display 392 core_power->map[i].psr_enabled = core_power->map[i + 1].psr_enabled; 393 core_power->map[i].psr_events = core_power->map[i + 1].psr_events; 394 core_power->map[i].psr_power_opt = core_power->map[i + 1].psr_power_opt; 395 396 memcpy(core_power->map[i].psr_context, core_power->map[i + 1].psr_context, sizeof(struct mod_power_psr_context)); 397 memset(core_power->map[i + 1].psr_context, 0, sizeof(struct mod_power_psr_context)); 398 } 399 core_power->num_entities--; 400 401 return true; 402 } 403 404 /* 405 * Replace_stream should be used when there is a mode set for existing 406 * display target with a valid stream. In this case might need to retain 407 * cached PSR state (events, power opt, en/dis) if we are dealing with PSR 408 * capable display. If mod_power_remove and mod_power_add are used instead, 409 * then stream may be assigned to a different slot and may end up with 410 * wrong cached PSR state. It is hard to tell which PSR events should 411 * persist through mode set or what psr_events should be initialized to, so 412 * it might be better just to retain them all. 413 */ 414 bool mod_power_replace_stream(struct mod_power *mod_power, 415 const struct dc_stream_state *current_stream, 416 struct dc_stream_state *new_stream, 417 struct psr_caps *new_caps) 418 { 419 struct core_power *core_power = NULL; 420 unsigned int index = 0; 421 422 if (mod_power == NULL) 423 return false; 424 425 core_power = MOD_POWER_TO_CORE(mod_power); 426 if (core_power->num_entities == 0) { 427 /* no streams exist in the table yet */ 428 BREAK_TO_DEBUGGER(); 429 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 430 WPP_BIT_FLAG_Firmware_PsrState, 431 "mod_power: replace_stream: ERROR: num_entities=0 stream=%p", 432 current_stream); 433 return false; 434 } 435 436 index = map_index_from_stream(core_power, current_stream); 437 438 if (index >= core_power->num_entities) { 439 /* trying to replace a non-existent stream */ 440 BREAK_TO_DEBUGGER(); 441 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 442 WPP_BIT_FLAG_Firmware_PsrState, 443 "mod_power: replace_stream: ERROR: index=%u >= num_entities=%u stream=%p", 444 index, 445 core_power->num_entities, 446 current_stream); 447 return false; 448 } 449 450 dc_stream_release(core_power->map[index].stream); 451 dc_stream_retain(new_stream); 452 core_power->map[index].stream = new_stream; 453 core_power->map[index].caps = new_caps; 454 memset(core_power->map[index].psr_context, 0, sizeof(struct mod_power_psr_context)); 455 456 return true; 457 } 458 459 bool mod_power_notify_mode_change(struct mod_power *mod_power, 460 const struct dc_stream_state *stream, 461 bool is_hdr) 462 { 463 unsigned int stream_index = 0; 464 struct core_power *core_power = NULL; 465 struct dc_link *link = NULL; 466 struct dc *dc = NULL; 467 unsigned int panel_inst = 0; 468 int active_replay_events = 0; 469 470 if ((mod_power == NULL) || (stream == NULL)) 471 return false; 472 473 core_power = MOD_POWER_TO_CORE(mod_power); 474 475 if (core_power->num_entities == 0) 476 return false; 477 478 stream_index = map_index_from_stream(core_power, stream); 479 480 if (stream_index >= core_power->num_entities) 481 return false; 482 483 dc = core_power->dc; 484 link = dc_stream_get_link(stream); 485 active_replay_events = core_power->map[stream_index].replay_events; 486 if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) { 487 ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); 488 uint8_t aux_inst = (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; 489 490 mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr); 491 492 /* Handle PSR notification */ 493 mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index); 494 495 link->replay_settings.replay_smu_opt_enable = 496 (link->replay_settings.config.replay_smu_opt_supported && 497 mod_power_only_edp(dc->current_state, stream)); 498 499 if (active_replay_events & replay_event_os_request_force_ffu) { 500 link->replay_settings.config.os_request_force_ffu = true; 501 } 502 503 if (dc_is_embedded_signal(stream->signal)) 504 dc->link_srv->dp_setup_replay(link, stream); 505 } 506 507 return true; 508 } 509 510 static bool mod_power_set_replay_active(struct dc_stream_state *stream, 511 bool replay_active, 512 bool wait, 513 bool force_static) 514 { 515 uint64_t state; 516 unsigned int retry_count; 517 const unsigned int max_retry = 1000; 518 struct dc_link *link = NULL; 519 520 if (!stream) 521 return false; 522 523 link = dc_stream_get_link(stream); 524 525 if (!link) 526 return false; 527 528 if (!dc_link_set_replay_allow_active(link, &replay_active, false, force_static, NULL)) 529 return false; 530 531 if (wait == true) { 532 533 for (retry_count = 0; retry_count <= max_retry; retry_count++) { 534 dc_link_get_replay_state(link, &state); 535 if (replay_active) { 536 if (state != REPLAY_STATE_0 && 537 (!force_static || state == REPLAY_STATE_3)) 538 break; 539 } else { 540 if (state == REPLAY_STATE_0) 541 break; 542 } 543 udelay(500); 544 } 545 546 /* assert if max retry hit */ 547 if (retry_count >= max_retry) 548 ASSERT(0); 549 } else { 550 /* To-do: Add trace log */ 551 } 552 553 return true; 554 } 555 556 static unsigned int mod_power_replay_setup_power_opt(struct dc_link *link, 557 unsigned int active_replay_events, bool is_ultra_sleep_mode) 558 { 559 unsigned int power_opt = 0; 560 561 if (is_ultra_sleep_mode) { 562 /* Static Screen */ 563 power_opt |= (replay_power_opt_smu_opt_static_screen | replay_power_opt_z10_static_screen); 564 } else if (active_replay_events & replay_event_test_harness_ultra_sleep) { 565 power_opt |= replay_power_opt_z10_static_screen; 566 } 567 568 /* replay_power_opt_flag is a configuration parameter into the module that determines 569 * which optimizations to enable during replay 570 */ 571 power_opt &= link->replay_settings.config.replay_power_opt_supported; 572 573 return power_opt; 574 } 575 576 static bool mod_power_replay_set_power_opt(struct mod_power *mod_power, 577 struct dc_stream_state *stream, 578 unsigned int active_replay_events, 579 bool is_ultra_sleep_mode) 580 { 581 (void)mod_power; 582 struct dc_link *link = NULL; 583 unsigned int power_opt = 0; 584 585 if (!stream) 586 return false; 587 588 link = dc_stream_get_link(stream); 589 590 if (!link || !link->replay_settings.replay_feature_enabled) 591 return false; 592 593 power_opt = mod_power_replay_setup_power_opt(link, active_replay_events, is_ultra_sleep_mode); 594 595 if (!dc_link_set_replay_allow_active(link, NULL, false, false, &power_opt)) 596 return false; 597 598 return true; 599 } 600 601 bool mod_power_get_replay_event(struct mod_power *mod_power, 602 struct dc_stream_state *stream, 603 unsigned int *active_replay_events) 604 { 605 struct core_power *core_power = NULL; 606 unsigned int stream_index = 0; 607 608 if (mod_power == NULL) 609 return false; 610 611 core_power = MOD_POWER_TO_CORE(mod_power); 612 613 if (core_power->num_entities == 0) 614 return false; 615 616 stream_index = map_index_from_stream(core_power, stream); 617 618 *active_replay_events = core_power->map[stream_index].replay_events; 619 620 return true; 621 } 622 623 static bool mod_power_update_replay_active_status(unsigned int active_replay_events, 624 struct dc_link *link, uint32_t *coasting_vtotal, bool *is_full_screen_video, bool *is_ultra_sleep_mode, uint16_t *frame_skip_number, bool *is_video_playback) 625 { 626 if (!link || !coasting_vtotal || !is_full_screen_video || !is_video_playback) 627 return false; 628 629 // Check coasting_vtotal_table has been updated. 630 if (!link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC] 631 || !link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]) 632 return false; 633 634 unsigned int replay_enable_option = 635 link->replay_settings.config.replay_enable_option; 636 637 /* TODO: To support test harness and DDS event */ 638 639 *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; 640 ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM] <= 0xFFFF); 641 *frame_skip_number = (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; 642 643 link->replay_settings.config.replay_timing_sync_supported = false; 644 645 *is_full_screen_video = false; 646 647 *is_ultra_sleep_mode = false; 648 649 *is_video_playback = false; 650 651 /* DSAT test scenario */ 652 if (active_replay_events & replay_event_test_harness_mode) { 653 if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) 654 *coasting_vtotal = 655 link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; 656 if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { 657 ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS] <= 0xFFFF); 658 *frame_skip_number = 659 (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; 660 } 661 662 /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ 663 if (active_replay_events & (replay_event_test_harness_enable_replay)) { 664 if ((active_replay_events & replay_event_test_harness_ultra_sleep) && 665 !link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) 666 link->replay_settings.config.replay_timing_sync_supported = false; 667 return true; 668 } else 669 return false; 670 } else if (active_replay_events & (replay_event_test_harness_enable_replay)) { 671 if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) 672 *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; 673 if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { 674 uint32_t frame_skip_val = 675 link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; 676 677 ASSERT(frame_skip_val <= 0xFFFF); 678 *frame_skip_number = (uint16_t)frame_skip_val; 679 } 680 681 /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ 682 if ((active_replay_events & replay_event_test_harness_ultra_sleep) && 683 !link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) 684 link->replay_settings.config.replay_timing_sync_supported = false; 685 return true; 686 } else if (active_replay_events & (replay_event_test_harness_disable_replay | replay_event_os_request_disable)) { 687 // set last set coasting vtotal 688 if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) 689 *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; 690 if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { 691 uint32_t frame_skip_val = 692 link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; 693 694 ASSERT(frame_skip_val <= 0xFFFF); 695 *frame_skip_number = (uint16_t)frame_skip_val; 696 } 697 return false; 698 } 699 700 /* Inactive conditions */ 701 if (active_replay_events & (replay_event_edp_panel_off_disable_psr | 702 replay_event_hw_programming | 703 replay_event_vrr | 704 replay_event_immediate_flip | 705 replay_event_prepare_vtotal | 706 replay_event_vrr_transition | 707 replay_event_pause | 708 replay_event_disable_replay_while_DPMS | 709 replay_event_sleep_resume | 710 replay_event_disable_in_AC | 711 replay_event_disable_replay_while_detect_display | 712 replay_event_infopacket | 713 replay_event_crc_window_active)) 714 return false; 715 716 // Full screen scenario 717 if (active_replay_events & replay_event_full_screen) { 718 if (!(replay_enable_option & pr_enable_option_full_screen)) 719 return false; 720 } 721 722 /* Full screen video scenario */ 723 if (active_replay_events & replay_event_big_screen_video) { 724 725 link->replay_settings.config.replay_timing_sync_supported = false; 726 727 if (replay_enable_option & pr_enable_option_full_screen_video_coasting) { 728 unsigned int fsn_vid = 729 link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_FULL_SCREEN_VIDEO]; 730 731 *coasting_vtotal = 732 link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_FULL_SCREEN_VIDEO]; 733 ASSERT(fsn_vid <= 0xFFFF); 734 *frame_skip_number = (uint16_t)fsn_vid; 735 } 736 737 *is_video_playback = true; 738 739 if ((replay_enable_option & pr_enable_option_full_screen_video) && 740 (replay_enable_option & pr_enable_option_full_screen_video_coasting)) { 741 *is_full_screen_video = true; 742 return true; 743 } else 744 return false; 745 } 746 747 /* MPO video scenario 748 * Some of the cases may contain a full screen UI layer in MPO video scenario which is 749 * not the expected case to enable Replay. 750 */ 751 if ((active_replay_events & replay_event_mpo_video_selective_update) && 752 !(active_replay_events & replay_event_full_screen)) { 753 754 link->replay_settings.config.replay_timing_sync_supported = false; 755 756 if (replay_enable_option & pr_enable_option_mpo_video_coasting) { 757 *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; 758 { 759 uint32_t frame_skip_val = 760 link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; 761 762 ASSERT(frame_skip_val <= 0xFFFF); 763 *frame_skip_number = (uint16_t)frame_skip_val; 764 } 765 } 766 767 *is_video_playback = true; 768 769 if (replay_enable_option & pr_enable_option_mpo_video) 770 return true; 771 else 772 return false; 773 } 774 775 /* Static screen scenario */ 776 if (!(active_replay_events & replay_event_vsync)) { 777 778 if (replay_enable_option & pr_enable_option_static_screen_coasting) { 779 // Do not adjust eDP refresh rate if static screen + normal sleep mode 780 if ((!(link->replay_settings.config.replay_power_opt_supported & 781 replay_power_opt_z10_static_screen)) || 782 (active_replay_events & replay_event_cursor_updating)) { 783 // normal sleep mode 784 *coasting_vtotal = 785 link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM]; 786 { 787 uint32_t frame_skip_val = 788 link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_NOM]; 789 790 ASSERT(frame_skip_val <= 0xFFFF); 791 *frame_skip_number = (uint16_t)frame_skip_val; 792 } 793 } else { 794 // ultra sleep mode 795 *coasting_vtotal = 796 link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC]; 797 { 798 uint32_t frame_skip_val = 799 link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_STATIC]; 800 801 ASSERT(frame_skip_val <= 0xFFFF); 802 *frame_skip_number = (uint16_t)frame_skip_val; 803 } 804 *is_ultra_sleep_mode = true; 805 } 806 } 807 808 if (replay_enable_option & pr_enable_option_static_screen) { 809 if (!link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode) 810 link->replay_settings.config.replay_timing_sync_supported = false; 811 return true; 812 } else 813 return false; 814 } 815 816 /* General UI scenario */ 817 if (active_replay_events & replay_event_general_ui) { 818 if (replay_enable_option & pr_enable_option_general_ui) 819 return true; 820 else 821 return false; 822 } 823 824 return false; 825 } 826 827 bool mod_power_replay_set_coasting_vtotal(struct mod_power *mod_power, 828 const struct dc_stream_state *stream, 829 uint32_t coasting_vtotal, 830 uint16_t frame_skip_number) 831 { 832 struct core_power *core_power = NULL; 833 struct dc_link *link = NULL; 834 835 if (!stream) 836 return false; 837 838 link = dc_stream_get_link(stream); 839 if (!link || !link->replay_settings.replay_feature_enabled) 840 return false; 841 842 if (mod_power == NULL) 843 return false; 844 845 core_power = MOD_POWER_TO_CORE(mod_power); 846 847 if (core_power->num_entities == 0) 848 return false; 849 850 return link->dc->link_srv->edp_set_coasting_vtotal(link, coasting_vtotal, frame_skip_number); 851 } 852 853 void mod_power_replay_set_timing_sync_supported(struct mod_power *mod_power, 854 const struct dc_stream_state *stream) 855 { 856 struct core_power *core_power = NULL; 857 struct dc_link *link = NULL; 858 unsigned int stream_index = 0; 859 union dmub_replay_cmd_set cmd_data = { 0 }; 860 861 if (!stream || mod_power == NULL) 862 return; 863 864 core_power = MOD_POWER_TO_CORE(mod_power); 865 if (core_power->num_entities == 0) 866 return; 867 868 stream_index = map_index_from_stream(core_power, stream); 869 if (stream_index > core_power->num_entities) //invalid index 870 return; 871 872 link = dc_stream_get_link(stream); 873 if (!link || !link->replay_settings.replay_feature_enabled) 874 return; 875 876 cmd_data.sync_data.timing_sync_supported = link->replay_settings.config.replay_timing_sync_supported; 877 878 link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_Timing_Sync_Supported, 879 &cmd_data); 880 } 881 882 void mod_power_replay_disabled_adaptive_sync_sdp(struct mod_power *mod_power, 883 const struct dc_stream_state *stream, bool force_disabled) 884 { 885 struct core_power *core_power = NULL; 886 struct dc_link *link = NULL; 887 unsigned int stream_index = 0; 888 union dmub_replay_cmd_set cmd_data = { 0 }; 889 890 if (!stream || mod_power == NULL) 891 return; 892 893 core_power = MOD_POWER_TO_CORE(mod_power); 894 if (core_power->num_entities == 0) 895 return; 896 897 stream_index = map_index_from_stream(core_power, stream); 898 if (stream_index > core_power->num_entities) //invalid index 899 return; 900 901 link = dc_stream_get_link(stream); 902 if (!link || !link->replay_settings.replay_feature_enabled) 903 return; 904 905 cmd_data.disabled_adaptive_sync_sdp_data.force_disabled = force_disabled; 906 907 link->dc->link_srv->edp_send_replay_cmd(link, Replay_Disabled_Adaptive_Sync_SDP, 908 &cmd_data); 909 } 910 911 static void mod_power_replay_set_general_cmd(struct mod_power *mod_power, 912 const struct dc_stream_state *stream, 913 const enum dmub_cmd_replay_general_subtype general_cmd_type, 914 const uint32_t param1, const uint32_t param2) 915 { 916 struct core_power *core_power = NULL; 917 struct dc_link *link = NULL; 918 unsigned int stream_index = 0; 919 union dmub_replay_cmd_set cmd_data = { 0 }; 920 921 if (!stream || mod_power == NULL) 922 return; 923 924 core_power = MOD_POWER_TO_CORE(mod_power); 925 if (core_power->num_entities == 0) 926 return; 927 928 stream_index = map_index_from_stream(core_power, stream); 929 if (stream_index > core_power->num_entities) //invalid index 930 return; 931 932 link = dc_stream_get_link(stream); 933 if (!link || !link->replay_settings.replay_feature_enabled) 934 return; 935 936 cmd_data.set_general_cmd_data.subtype = general_cmd_type; 937 cmd_data.set_general_cmd_data.param1 = param1; 938 cmd_data.set_general_cmd_data.param2 = param2; 939 link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_General_Cmd, 940 &cmd_data); 941 } 942 943 void mod_power_replay_disabled_desync_error_detection(struct mod_power *mod_power, 944 const struct dc_stream_state *stream, bool force_disabled) 945 { 946 mod_power_replay_set_general_cmd(mod_power, stream, 947 REPLAY_GENERAL_CMD_DISABLED_DESYNC_ERROR_DETECTION, 948 force_disabled, 0); 949 } 950 951 static void mod_power_replay_set_pseudo_vtotal(struct mod_power *mod_power, 952 const struct dc_stream_state *stream, uint16_t vtotal) 953 { 954 struct core_power *core_power = NULL; 955 struct dc_link *link = NULL; 956 unsigned int stream_index = 0; 957 union dmub_replay_cmd_set cmd_data = { 0 }; 958 959 if (!stream || mod_power == NULL) 960 return; 961 962 core_power = MOD_POWER_TO_CORE(mod_power); 963 if (core_power->num_entities == 0) 964 return; 965 966 stream_index = map_index_from_stream(core_power, stream); 967 if (stream_index > core_power->num_entities) //invalid index 968 return; 969 970 link = dc_stream_get_link(stream); 971 if (!link || !link->replay_settings.replay_feature_enabled) 972 return; 973 974 cmd_data.pseudo_vtotal_data.vtotal = vtotal; 975 976 if (link->replay_settings.last_pseudo_vtotal != vtotal) { 977 link->replay_settings.last_pseudo_vtotal = vtotal; 978 link->dc->link_srv->edp_send_replay_cmd(link, Replay_Set_Pseudo_VTotal, &cmd_data); 979 } 980 } 981 982 static void mod_power_update_error_status(struct mod_power *mod_power, 983 const struct dc_stream_state *stream) 984 { 985 struct dc_link *link = NULL; 986 union replay_debug_flags *pDebug = NULL; 987 988 if (mod_power == NULL || stream == NULL) 989 return; 990 991 link = dc_stream_get_link(stream); 992 993 if (!link) 994 return; 995 996 pDebug = (union replay_debug_flags *)&link->replay_settings.config.debug_flags; 997 998 if (0 == pDebug->bitfields.enable_visual_confirm_debug) 999 return; 1000 1001 mod_power_replay_set_general_cmd(mod_power, stream, 1002 REPLAY_GENERAL_CMD_UPDATE_ERROR_STATUS, 1003 link->replay_settings.config.replay_error_status.raw, 0); 1004 } 1005 1006 void mod_power_set_low_rr_activate(struct mod_power *mod_power, 1007 const struct dc_stream_state *stream, bool low_rr_supported) 1008 { 1009 struct dc_link *link = NULL; 1010 1011 if (mod_power == NULL || stream == NULL) 1012 return; 1013 1014 link = dc_stream_get_link(stream); 1015 1016 if (!link) 1017 return; 1018 1019 mod_power_replay_set_general_cmd(mod_power, stream, 1020 REPLAY_GENERAL_CMD_SET_LOW_RR_ACTIVATE, 1021 low_rr_supported, 0); 1022 } 1023 1024 void mod_power_set_video_conferencing_activate(struct mod_power *mod_power, 1025 const struct dc_stream_state *stream, bool video_conferencing_activate) 1026 { 1027 struct dc_link *link = NULL; 1028 1029 if (mod_power == NULL || stream == NULL) 1030 return; 1031 1032 link = dc_stream_get_link(stream); 1033 if (!link || !link->replay_settings.replay_feature_enabled) 1034 return; 1035 1036 mod_power_replay_set_general_cmd(mod_power, stream, 1037 REPLAY_GENERAL_CMD_VIDEO_CONFERENCING, 1038 video_conferencing_activate, 0); 1039 } 1040 1041 void mod_power_set_coasting_vtotal_without_frame_update(struct mod_power *mod_power, 1042 const struct dc_stream_state *stream, uint32_t coasting_vtotal) 1043 { 1044 struct dc_link *link = NULL; 1045 1046 if (mod_power == NULL || stream == NULL) 1047 return; 1048 1049 link = dc_stream_get_link(stream); 1050 if (!link || !link->replay_settings.replay_feature_enabled) 1051 return; 1052 1053 mod_power_replay_set_general_cmd(mod_power, stream, 1054 REPLAY_GENERAL_CMD_SET_COASTING_VTOTAL_WITHOUT_FRAME_UPDATE, 1055 coasting_vtotal, 0); 1056 } 1057 1058 void mod_power_set_replay_continuously_resync(struct mod_power *mod_power, 1059 const struct dc_stream_state *stream, bool enable) 1060 { 1061 struct dc_link *link = NULL; 1062 1063 if (mod_power == NULL || stream == NULL) 1064 return; 1065 1066 link = dc_stream_get_link(stream); 1067 if (!link || !link->replay_settings.replay_feature_enabled) 1068 return; 1069 1070 mod_power_replay_set_general_cmd(mod_power, stream, 1071 REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC, 1072 enable, 0); 1073 } 1074 1075 void mod_power_set_live_capture_with_cvt_activate(struct mod_power *mod_power, 1076 const struct dc_stream_state *stream, bool live_capture_with_cvt_activate) 1077 { 1078 struct dc_link *link = NULL; 1079 1080 if (mod_power == NULL || stream == NULL) 1081 return; 1082 1083 link = dc_stream_get_link(stream); 1084 if (!link || !link->replay_settings.replay_feature_enabled) 1085 return; 1086 1087 // Check if LIVE_CAPTURE_WITH_CVT bit is enabled in DalRegKey_ReplayOptimization 1088 if (!link->replay_settings.config.replay_optimization.bits.LIVE_CAPTURE_WITH_CVT) 1089 return; 1090 1091 if (link->replay_settings.config.live_capture_with_cvt_activated != live_capture_with_cvt_activate) { 1092 link->replay_settings.config.live_capture_with_cvt_activated = live_capture_with_cvt_activate; 1093 mod_power_replay_set_general_cmd(mod_power, stream, 1094 REPLAY_GENERAL_CMD_LIVE_CAPTURE_WITH_CVT, 1095 live_capture_with_cvt_activate, 0); 1096 } 1097 } 1098 1099 bool mod_power_set_replay_event(struct mod_power *mod_power, 1100 struct dc_stream_state *stream, bool set_event, 1101 enum replay_event event, bool wait_for_disable) 1102 { 1103 struct core_power *core_power = NULL; 1104 struct dc_link *link = NULL; 1105 unsigned int stream_index = 0; 1106 unsigned int active_replay_events = 0; 1107 bool replay_active_request = false; 1108 bool force_static = false; 1109 uint32_t coasting_vtotal = 0; 1110 bool current_timing_sync_status = false; 1111 bool is_full_screen_video = false; 1112 bool is_ultra_sleep_mode = false; 1113 unsigned int sink_duration_us = 0; 1114 bool low_rr_active = false; 1115 uint16_t frame_skip_number = 0; 1116 bool is_video_playback = false; 1117 1118 if (!stream) 1119 return false; 1120 1121 if (mod_power == NULL) 1122 return false; 1123 1124 core_power = MOD_POWER_TO_CORE(mod_power); 1125 1126 if (core_power->num_entities == 0) 1127 return false; 1128 1129 stream_index = map_index_from_stream(core_power, stream); 1130 1131 if (set_event) 1132 core_power->map[stream_index].replay_events |= event; 1133 else 1134 core_power->map[stream_index].replay_events &= ~event; 1135 1136 link = dc_stream_get_link(stream); 1137 if (!link || !link->replay_settings.replay_feature_enabled) 1138 return false; 1139 1140 if ((core_power->map[stream_index].replay_events & replay_event_disable_replay_while_switching_mux) != 0) 1141 return false; 1142 1143 if ((core_power->map[stream_index].replay_events & replay_event_os_override_hold) != 0) 1144 return false; 1145 1146 active_replay_events = core_power->map[stream_index].replay_events; 1147 1148 current_timing_sync_status = 1149 link->replay_settings.config.replay_timing_sync_supported; 1150 1151 replay_active_request = mod_power_update_replay_active_status(active_replay_events, 1152 link, &coasting_vtotal, &is_full_screen_video, &is_ultra_sleep_mode, &frame_skip_number, &is_video_playback); 1153 1154 if (is_full_screen_video) 1155 mod_power_replay_set_pseudo_vtotal(mod_power, stream, 1156 link->replay_settings.low_rr_full_screen_video_pseudo_vtotal); 1157 else 1158 mod_power_replay_set_pseudo_vtotal(mod_power, stream, 0); 1159 1160 //If timing_sync_status change, then re-enabled set timing_sync_supported value and re-enabled replay 1161 if (current_timing_sync_status != link->replay_settings.config.replay_timing_sync_supported) 1162 mod_power_replay_set_timing_sync_supported(mod_power, stream); 1163 1164 if (link->replay_settings.config.low_rr_supported) { 1165 sink_duration_us = 1166 (unsigned int)(div_u64(((unsigned long long)(coasting_vtotal) 1167 * 10000) * stream->timing.h_total, 1168 stream->timing.pix_clk_100hz)); 1169 low_rr_active = sink_duration_us < LOW_REFRESH_RATE_DURATION_US_UPPER_BOUND ? false : true; 1170 if (low_rr_active != link->replay_settings.config.low_rr_activated) { 1171 mod_power_set_low_rr_activate(mod_power, stream, low_rr_active); 1172 link->replay_settings.config.low_rr_activated = low_rr_active; 1173 } 1174 } 1175 1176 // The function return fail when 1177 // 1. DMUB function is not support (for backward compatible). 1178 // 2. active_replay_events or coasting_vtotal is not updated in the same time 1179 if (!mod_power_replay_set_power_opt_and_coasting_vtotal(mod_power, 1180 stream, active_replay_events, coasting_vtotal, is_ultra_sleep_mode, frame_skip_number)) { 1181 if (!mod_power_replay_set_power_opt(mod_power, stream, active_replay_events, is_ultra_sleep_mode)) 1182 return false; 1183 1184 if (!mod_power_replay_set_coasting_vtotal(mod_power, stream, coasting_vtotal, frame_skip_number)) 1185 return false; 1186 } 1187 1188 mod_power_set_live_capture_with_cvt_activate(mod_power, stream, is_video_playback); 1189 1190 mod_power_update_error_status(mod_power, stream); 1191 1192 // If Replay is going to be enable (No matter is disable -> enable or enable -> enable), we don't need to wait. 1193 // If Replay is going to be disable 1194 // if disable -> disable 1195 // -> Replay DMUB state should be state 0. 1196 // So no matter wait_for_disable is true or not, it should makes no difference. 1197 // if enable -> disable -> We should wait if wait_for_disable is true. 1198 if (replay_active_request) 1199 wait_for_disable = false; 1200 1201 if (!mod_power_set_replay_active(stream, replay_active_request, wait_for_disable, force_static)) 1202 return false; 1203 1204 return true; 1205 } 1206 1207 bool mod_power_get_replay_active_status(const struct dc_stream_state *stream, 1208 bool *replay_active) 1209 { 1210 const struct dc_link *link = NULL; 1211 1212 if (!stream) 1213 return false; 1214 1215 link = dc_stream_get_link(stream); 1216 *replay_active = link->replay_settings.replay_allow_active; 1217 1218 return true; 1219 } 1220 1221 void mod_power_replay_residency(const struct dc_stream_state *stream, 1222 unsigned int *residency, const bool is_start, const bool is_alpm) 1223 { 1224 const struct dc_link *link = NULL; 1225 enum pr_residency_mode mode; 1226 1227 if (!stream) 1228 return; 1229 1230 link = dc_stream_get_link(stream); 1231 1232 if (is_alpm) 1233 mode = PR_RESIDENCY_MODE_ALPM; 1234 else 1235 mode = PR_RESIDENCY_MODE_PHY; 1236 1237 if (link && link->dc && link->dc->link_srv) 1238 link->dc->link_srv->edp_replay_residency(link, residency, is_start, mode); 1239 } 1240 1241 bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power, 1242 const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal, 1243 bool is_ultra_sleep_mode, uint16_t frame_skip_number) 1244 { 1245 struct core_power *core_power = NULL; 1246 struct dc_link *link = NULL; 1247 unsigned int power_opt = 0; 1248 1249 if (!stream) 1250 return false; 1251 1252 if (mod_power == NULL) 1253 return false; 1254 1255 core_power = MOD_POWER_TO_CORE(mod_power); 1256 1257 if (core_power->num_entities == 0) 1258 return false; 1259 1260 link = dc_stream_get_link(stream); 1261 1262 if (!link || !link->replay_settings.replay_feature_enabled) 1263 return false; 1264 1265 power_opt = mod_power_replay_setup_power_opt(link, active_replay_events, is_ultra_sleep_mode); 1266 1267 return link->dc->link_srv->edp_set_replay_power_opt_and_coasting_vtotal(link, &power_opt, coasting_vtotal, frame_skip_number); 1268 } 1269 1270 1271 1272 1273 1274