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_obj(struct core_power); 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_obj(struct mod_power_psr_context); 133 if (core_power->map[i].psr_context == NULL) 134 goto fail_construct; 135 } 136 137 core_power->psr_smu_optimizations_support = init_params->allow_psr_smu_optimizations; 138 core_power->multi_disp_optimizations_support = init_params->allow_psr_multi_disp_optimizations; 139 140 for (inst = 0; inst < edp_num; inst++) { 141 core_power->bl_prop[inst].min_abm_backlight = 142 init_params[inst].min_abm_backlight; 143 core_power->bl_prop[inst].disable_fractional_pwm = 144 init_params[inst].disable_fractional_pwm; 145 core_power->bl_prop[inst].use_linear_backlight_curve = 146 init_params[inst].use_linear_backlight_curve; 147 core_power->bl_prop[inst].use_nits_based_brightness = 148 init_params[inst].use_nits_based_brightness; 149 core_power->bl_prop[inst].backlight_ramping_override = 150 init_params[inst].backlight_ramping_override; 151 core_power->bl_prop[inst].backlight_ramping_reduction = 152 init_params[inst].backlight_ramping_reduction; 153 core_power->bl_prop[inst].backlight_ramping_start = 154 init_params[inst].backlight_ramping_start; 155 core_power->bl_prop[inst].use_custom_backlight_caps = 156 init_params[inst].use_custom_backlight_caps; 157 core_power->bl_prop[inst].custom_backlight_caps_config_no = 158 init_params[inst].custom_backlight_caps_config_no; 159 160 // Do not allow less than 101 backlight levels 161 if (init_params[inst].num_backlight_levels < 101) 162 core_power->bl_prop[inst].num_backlight_levels = 101; 163 else 164 core_power->bl_prop[inst].num_backlight_levels = 165 init_params[inst].num_backlight_levels; 166 167 core_power->bl_prop[inst].backlight_lut = (unsigned int *) 168 (kzalloc(sizeof(unsigned int) * 169 core_power->bl_prop[inst].num_backlight_levels, GFP_KERNEL)); 170 if (core_power->bl_prop[inst].backlight_lut == NULL) 171 goto fail_alloc_backlight_array; 172 } 173 174 core_power->varibright_prop.varibright_active = false; 175 176 core_power->varibright_prop.varibright_user_enable = 177 init_params->def_varibright_enable; 178 179 // Table of ABM levels here is 1-4, but level 0 also exists as 'off' 180 if (init_params->varibright_level <= abm_defines_max_level) { 181 core_power->varibright_prop.varibright_level = 182 init_params->varibright_level; 183 184 } else { 185 core_power->varibright_prop.varibright_level = 3; 186 } 187 if (init_params->def_varibright_level <= abm_defines_max_level) { 188 core_power->varibright_prop.def_varibright_level = 189 init_params->def_varibright_level; 190 } else { 191 core_power->varibright_prop.def_varibright_level = 3; 192 } 193 194 // ABM used to contain 4 different configs. There is only 3 since ABM 2.3. 195 if ((dc->res_pool->dmcu != NULL) && (dc->res_pool->dmcu->dmcu_version.abm_version < 0x23)) 196 abm_max_config = 4; 197 else 198 abm_max_config = 3; 199 200 if (init_params->abm_config_setting < abm_max_config) 201 core_power->varibright_prop.varibright_config_setting = 202 init_params->abm_config_setting; 203 else 204 core_power->varibright_prop.varibright_config_setting = 0; 205 206 for (inst = 0; inst < edp_num; inst++) { 207 core_power->bl_prop[inst].backlight_lut[0] = init_params[inst].min_backlight_pwm; 208 core_power->bl_prop[inst].backlight_lut[ 209 core_power->bl_prop[inst].num_backlight_levels-1] = 210 init_params[inst].max_backlight_pwm; 211 core_power->bl_prop[inst].min_backlight_pwm = init_params[inst].min_backlight_pwm; 212 core_power->bl_prop[inst].max_backlight_pwm = init_params[inst].max_backlight_pwm; 213 core_power->bl_prop[inst].ac_backlight_percent = 214 default_ac_backlight_percent; 215 core_power->bl_prop[inst].dc_backlight_percent = 216 default_dc_backlight_percent; 217 core_power->bl_prop[inst].backlight_caps_valid = false; 218 219 if (core_power->bl_prop[inst].use_nits_based_brightness) { 220 core_power->bl_prop[inst].min_brightness_millinits = 221 init_params[inst].panel_min_millinits; 222 core_power->bl_prop[inst].max_brightness_millinits = 223 init_params[inst].panel_max_millinits; 224 } else { 225 226 core_power->bl_prop[inst].min_brightness_millinits = 227 pwr_default_min_brightness_millinits; 228 core_power->bl_prop[inst].max_brightness_millinits = 229 pwr_default_sdr_brightness_millinits; 230 } 231 232 core_power->bl_prop[inst].backlight_range = 233 core_power->bl_prop[inst].max_backlight_pwm- 234 core_power->bl_prop[inst].min_backlight_pwm; 235 236 core_power->bl_prop[inst].nits_range = 237 core_power->bl_prop[inst].max_brightness_millinits - 238 core_power->bl_prop[inst].min_brightness_millinits; 239 240 core_power->bl_state[inst].smooth_brightness_enabled = true; 241 } 242 243 /* Check if at least 1 instance in core_power is populated before failing */ 244 for (inst = 0; inst < edp_num; inst++) { 245 if (core_power->bl_prop[inst].nits_range != 0 && core_power->bl_prop[inst].backlight_range != 0) { 246 is_brightness_range_valid = true; 247 break; 248 } 249 250 } 251 if (!is_brightness_range_valid) 252 goto fail_bad_brightness_range; 253 254 core_power->num_entities = 0; 255 256 core_power->dc = dc; 257 for (inst = 0; inst < edp_num; inst++) { 258 initialize_backlight_caps(core_power, inst); 259 core_power->bl_state[inst].backlight_millipercent = 260 core_power->bl_prop[inst].dc_backlight_percent * 1000; 261 core_power->bl_state[inst].backlight_pwm = backlight_millipercent_to_pwm(core_power, 262 core_power->bl_state[inst].backlight_millipercent, inst); 263 core_power->bl_state[inst].backlight_millinit = backlight_millipercent_to_millinit(core_power, 264 core_power->bl_state[inst].backlight_millipercent, inst); 265 } 266 267 return &core_power->mod_public; 268 269 fail_bad_brightness_range: 270 fail_alloc_backlight_array: 271 for (inst = 0; inst < edp_num; inst++) 272 kfree(core_power->bl_prop[inst].backlight_lut); 273 fail_construct: 274 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) 275 kfree(core_power->map[i].psr_context); 276 277 kfree(core_power->map); 278 279 fail_alloc_map: 280 kfree(core_power); 281 282 fail_alloc_context: 283 fail_dc_null: 284 return NULL; 285 } 286 287 void mod_power_destroy(struct mod_power *mod_power) 288 { 289 if (mod_power != NULL) { 290 unsigned int i; 291 struct core_power *core_power = 292 MOD_POWER_TO_CORE(mod_power); 293 294 for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++) 295 kfree(core_power->map[i].psr_context); 296 297 for (i = 0; i < core_power->num_entities; i++) 298 if (core_power->map[i].stream) 299 dc_stream_release(core_power->map[i].stream); 300 301 kfree(core_power->map); 302 303 for (i = 0; i < MAX_NUM_EDP; i++) 304 kfree(core_power->bl_prop[i].backlight_lut); 305 306 kfree(core_power); 307 } 308 } 309 310 bool mod_power_add_stream(struct mod_power *mod_power, 311 struct dc_stream_state *stream, struct psr_caps *caps) 312 { 313 struct core_power *core_power = NULL; 314 315 if (mod_power == NULL) 316 return false; 317 318 core_power = MOD_POWER_TO_CORE(mod_power); 319 320 if (core_power->num_entities < MOD_POWER_MAX_CONCURRENT_STREAMS) { 321 dc_stream_retain(stream); 322 323 core_power->map[core_power->num_entities].stream = stream; 324 core_power->map[core_power->num_entities].caps = caps; 325 326 // initialize cached PSR params to something "safe" (something that is 327 // consistent with disabled PSR state) 328 core_power->map[core_power->num_entities].psr_enabled = 0; 329 core_power->map[core_power->num_entities].psr_events = psr_event_vsync; 330 core_power->map[core_power->num_entities].psr_power_opt = 0; 331 core_power->map[core_power->num_entities].replay_events = replay_event_vsync; 332 core_power->num_entities++; 333 return true; 334 } 335 336 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 337 WPP_BIT_FLAG_Firmware_PsrState, 338 "mod_power: add_stream: ERROR: stream=%p num_entities=%u >= MOD_POWER_MAX_CONCURRENT_STREAMS", 339 stream, 340 core_power->num_entities); 341 342 return false; 343 } 344 345 bool mod_power_remove_stream(struct mod_power *mod_power, 346 const struct dc_stream_state *stream) 347 { 348 unsigned int i = 0; 349 struct core_power *core_power = NULL; 350 unsigned int index = 0; 351 352 if (mod_power == NULL) 353 return false; 354 355 core_power = MOD_POWER_TO_CORE(mod_power); 356 if (core_power->num_entities == 0) { 357 /* trying to remove a stream a second time or have not added yet */ 358 BREAK_TO_DEBUGGER(); 359 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 360 WPP_BIT_FLAG_Firmware_PsrState, 361 "mod_power: remove_stream: ERROR: num_entities=0 stream=%p", 362 stream); 363 return false; 364 } 365 366 index = map_index_from_stream(core_power, stream); 367 368 if (index >= core_power->num_entities) { 369 /* trying to remove a stream a second time or have not added yet */ 370 BREAK_TO_DEBUGGER(); 371 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 372 WPP_BIT_FLAG_Firmware_PsrState, 373 "mod_power: remove_stream: ERROR: index=%u >= num_entities=%u stream=%p", 374 index, 375 core_power->num_entities, 376 stream); 377 return false; 378 } 379 380 dc_stream_release(core_power->map[index].stream); 381 core_power->map[index].stream = NULL; 382 /* To remove this entity, shift everything after down */ 383 for (i = index; i < core_power->num_entities - 1; i++) { 384 core_power->map[i].stream = core_power->map[i + 1].stream; 385 core_power->map[i].caps = core_power->map[i + 1].caps; 386 387 // copy over cached parameters in case they map to PSR capable display 388 core_power->map[i].psr_enabled = core_power->map[i + 1].psr_enabled; 389 core_power->map[i].psr_events = core_power->map[i + 1].psr_events; 390 core_power->map[i].psr_power_opt = core_power->map[i + 1].psr_power_opt; 391 core_power->map[i].replay_events = core_power->map[i + 1].replay_events; 392 393 memcpy(core_power->map[i].psr_context, core_power->map[i + 1].psr_context, sizeof(struct mod_power_psr_context)); 394 memset(core_power->map[i + 1].psr_context, 0, sizeof(struct mod_power_psr_context)); 395 } 396 core_power->num_entities--; 397 398 return true; 399 } 400 401 /* 402 * Replace_stream should be used when there is a mode set for existing 403 * display target with a valid stream. In this case might need to retain 404 * cached PSR state (events, power opt, en/dis) if we are dealing with PSR 405 * capable display. If mod_power_remove and mod_power_add are used instead, 406 * then stream may be assigned to a different slot and may end up with 407 * wrong cached PSR state. It is hard to tell which PSR events should 408 * persist through mode set or what psr_events should be initialized to, so 409 * it might be better just to retain them all. 410 */ 411 bool mod_power_replace_stream(struct mod_power *mod_power, 412 const struct dc_stream_state *current_stream, 413 struct dc_stream_state *new_stream, 414 struct psr_caps *new_caps) 415 { 416 struct core_power *core_power = NULL; 417 unsigned int index = 0; 418 419 if (mod_power == NULL) 420 return false; 421 422 core_power = MOD_POWER_TO_CORE(mod_power); 423 if (core_power->num_entities == 0) { 424 /* no streams exist in the table yet */ 425 BREAK_TO_DEBUGGER(); 426 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 427 WPP_BIT_FLAG_Firmware_PsrState, 428 "mod_power: replace_stream: ERROR: num_entities=0 stream=%p", 429 current_stream); 430 return false; 431 } 432 433 index = map_index_from_stream(core_power, current_stream); 434 435 if (index >= core_power->num_entities) { 436 /* trying to replace a non-existent stream */ 437 BREAK_TO_DEBUGGER(); 438 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 439 WPP_BIT_FLAG_Firmware_PsrState, 440 "mod_power: replace_stream: ERROR: index=%u >= num_entities=%u stream=%p", 441 index, 442 core_power->num_entities, 443 current_stream); 444 return false; 445 } 446 447 dc_stream_release(core_power->map[index].stream); 448 dc_stream_retain(new_stream); 449 core_power->map[index].stream = new_stream; 450 core_power->map[index].caps = new_caps; 451 memset(core_power->map[index].psr_context, 0, sizeof(struct mod_power_psr_context)); 452 453 return true; 454 } 455 bool mod_power_notify_mode_change(struct mod_power *mod_power, 456 const struct dc_stream_state *stream, 457 bool is_hdr) 458 { 459 unsigned int stream_index = 0; 460 struct core_power *core_power = NULL; 461 struct dc_link *link = NULL; 462 struct dc *dc = NULL; 463 unsigned int panel_inst = 0; 464 uint8_t aux_inst = 0; 465 466 if ((mod_power == NULL) || (stream == NULL)) 467 return false; 468 469 core_power = MOD_POWER_TO_CORE(mod_power); 470 471 if (core_power->num_entities == 0) 472 return false; 473 474 stream_index = map_index_from_stream(core_power, stream); 475 476 if (stream_index >= core_power->num_entities) 477 return false; 478 479 dc = core_power->dc; 480 link = dc_stream_get_link(stream); 481 482 if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) { 483 aux_inst = link->dc->link_srv->get_ddc_aux_inst(link); 484 485 mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr); 486 487 /* Handle PSR notification */ 488 mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index); 489 490 /* Handle Replay notification */ 491 mod_power_replay_notify_mode_change(mod_power, dc, link, stream, stream_index); 492 } 493 494 return true; 495 } 496 497 bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream) 498 { 499 return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal); 500 } 501