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 */
map_index_from_stream(struct core_power * core_power,const struct dc_stream_state * stream)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
mod_power_hw_init(struct mod_power * mod_power)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
mod_power_create(struct dc * dc,struct mod_power_init_params * init_params,unsigned int edp_num)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
mod_power_destroy(struct mod_power * mod_power)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
mod_power_add_stream(struct mod_power * mod_power,struct dc_stream_state * stream,struct psr_caps * caps)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->num_entities++;
332 return true;
333 }
334
335 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
336 WPP_BIT_FLAG_Firmware_PsrState,
337 "mod_power: add_stream: ERROR: stream=%p num_entities=%u >= MOD_POWER_MAX_CONCURRENT_STREAMS",
338 stream,
339 core_power->num_entities);
340
341 return false;
342 }
343
mod_power_remove_stream(struct mod_power * mod_power,const struct dc_stream_state * stream)344 bool mod_power_remove_stream(struct mod_power *mod_power,
345 const struct dc_stream_state *stream)
346 {
347 unsigned int i = 0;
348 struct core_power *core_power = NULL;
349 unsigned int index = 0;
350
351 if (mod_power == NULL)
352 return false;
353
354 core_power = MOD_POWER_TO_CORE(mod_power);
355 if (core_power->num_entities == 0) {
356 /* trying to remove a stream a second time or have not added yet */
357 BREAK_TO_DEBUGGER();
358 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
359 WPP_BIT_FLAG_Firmware_PsrState,
360 "mod_power: remove_stream: ERROR: num_entities=0 stream=%p",
361 stream);
362 return false;
363 }
364
365 index = map_index_from_stream(core_power, stream);
366
367 if (index >= core_power->num_entities) {
368 /* trying to remove a stream a second time or have not added yet */
369 BREAK_TO_DEBUGGER();
370 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
371 WPP_BIT_FLAG_Firmware_PsrState,
372 "mod_power: remove_stream: ERROR: index=%u >= num_entities=%u stream=%p",
373 index,
374 core_power->num_entities,
375 stream);
376 return false;
377 }
378
379 dc_stream_release(core_power->map[index].stream);
380 core_power->map[index].stream = NULL;
381 /* To remove this entity, shift everything after down */
382 for (i = index; i < core_power->num_entities - 1; i++) {
383 core_power->map[i].stream = core_power->map[i + 1].stream;
384 core_power->map[i].caps = core_power->map[i + 1].caps;
385
386 // copy over cached parameters in case they map to PSR capable display
387 core_power->map[i].psr_enabled = core_power->map[i + 1].psr_enabled;
388 core_power->map[i].psr_events = core_power->map[i + 1].psr_events;
389 core_power->map[i].psr_power_opt = core_power->map[i + 1].psr_power_opt;
390
391 memcpy(core_power->map[i].psr_context, core_power->map[i + 1].psr_context, sizeof(struct mod_power_psr_context));
392 memset(core_power->map[i + 1].psr_context, 0, sizeof(struct mod_power_psr_context));
393 }
394 core_power->num_entities--;
395
396 return true;
397 }
398
399 /*
400 * Replace_stream should be used when there is a mode set for existing
401 * display target with a valid stream. In this case might need to retain
402 * cached PSR state (events, power opt, en/dis) if we are dealing with PSR
403 * capable display. If mod_power_remove and mod_power_add are used instead,
404 * then stream may be assigned to a different slot and may end up with
405 * wrong cached PSR state. It is hard to tell which PSR events should
406 * persist through mode set or what psr_events should be initialized to, so
407 * it might be better just to retain them all.
408 */
mod_power_replace_stream(struct mod_power * mod_power,const struct dc_stream_state * current_stream,struct dc_stream_state * new_stream,struct psr_caps * new_caps)409 bool mod_power_replace_stream(struct mod_power *mod_power,
410 const struct dc_stream_state *current_stream,
411 struct dc_stream_state *new_stream,
412 struct psr_caps *new_caps)
413 {
414 struct core_power *core_power = NULL;
415 unsigned int index = 0;
416
417 if (mod_power == NULL)
418 return false;
419
420 core_power = MOD_POWER_TO_CORE(mod_power);
421 if (core_power->num_entities == 0) {
422 /* no streams exist in the table yet */
423 BREAK_TO_DEBUGGER();
424 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
425 WPP_BIT_FLAG_Firmware_PsrState,
426 "mod_power: replace_stream: ERROR: num_entities=0 stream=%p",
427 current_stream);
428 return false;
429 }
430
431 index = map_index_from_stream(core_power, current_stream);
432
433 if (index >= core_power->num_entities) {
434 /* trying to replace a non-existent stream */
435 BREAK_TO_DEBUGGER();
436 DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
437 WPP_BIT_FLAG_Firmware_PsrState,
438 "mod_power: replace_stream: ERROR: index=%u >= num_entities=%u stream=%p",
439 index,
440 core_power->num_entities,
441 current_stream);
442 return false;
443 }
444
445 dc_stream_release(core_power->map[index].stream);
446 dc_stream_retain(new_stream);
447 core_power->map[index].stream = new_stream;
448 core_power->map[index].caps = new_caps;
449 memset(core_power->map[index].psr_context, 0, sizeof(struct mod_power_psr_context));
450
451 return true;
452 }
mod_power_notify_mode_change(struct mod_power * mod_power,const struct dc_stream_state * stream,bool is_hdr)453 bool mod_power_notify_mode_change(struct mod_power *mod_power,
454 const struct dc_stream_state *stream,
455 bool is_hdr)
456 {
457 unsigned int stream_index = 0;
458 struct core_power *core_power = NULL;
459 struct dc_link *link = NULL;
460 struct dc *dc = NULL;
461 unsigned int panel_inst = 0;
462 uint8_t aux_inst = 0;
463
464 if ((mod_power == NULL) || (stream == NULL))
465 return false;
466
467 core_power = MOD_POWER_TO_CORE(mod_power);
468
469 if (core_power->num_entities == 0)
470 return false;
471
472 stream_index = map_index_from_stream(core_power, stream);
473
474 if (stream_index >= core_power->num_entities)
475 return false;
476
477 dc = core_power->dc;
478 link = dc_stream_get_link(stream);
479
480 if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) {
481 aux_inst = link->dc->link_srv->get_ddc_aux_inst(link);
482
483 mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr);
484
485 /* Handle PSR notification */
486 mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index);
487
488 /* Handle Replay notification */
489 mod_power_replay_notify_mode_change(mod_power, dc, link, stream, stream_index);
490 }
491
492 return true;
493 }
494
mod_power_only_edp(const struct dc_state * context,const struct dc_stream_state * stream)495 bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream)
496 {
497 return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal);
498 }
499