xref: /linux/drivers/gpu/drm/amd/display/modules/power/power.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
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 		kfree(core_power->bl_prop[inst].backlight_lut);
274 fail_construct:
275 	for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++)
276 		kfree(core_power->map[i].psr_context);
277 
278 	kfree(core_power->map);
279 
280 fail_alloc_map:
281 	kfree(core_power);
282 
283 fail_alloc_context:
284 fail_dc_null:
285 	return NULL;
286 }
287 
288 void mod_power_destroy(struct mod_power *mod_power)
289 {
290 	if (mod_power != NULL) {
291 		unsigned int i;
292 		struct core_power *core_power =
293 				MOD_POWER_TO_CORE(mod_power);
294 
295 		for (i = 0; i < MOD_POWER_MAX_CONCURRENT_STREAMS; i++)
296 			kfree(core_power->map[i].psr_context);
297 
298 		for (i = 0; i < core_power->num_entities; i++)
299 			if (core_power->map[i].stream)
300 				dc_stream_release(core_power->map[i].stream);
301 
302 		kfree(core_power->map);
303 
304 		for (i = 0; i < MAX_NUM_EDP; i++)
305 			kfree(core_power->bl_prop[i].backlight_lut);
306 
307 		kfree(core_power);
308 	}
309 }
310 
311 bool mod_power_add_stream(struct mod_power *mod_power,
312 		struct dc_stream_state *stream, struct psr_caps *caps)
313 {
314 	struct core_power *core_power = NULL;
315 
316 	if (mod_power == NULL)
317 		return false;
318 
319 	core_power = MOD_POWER_TO_CORE(mod_power);
320 
321 	if (core_power->num_entities < MOD_POWER_MAX_CONCURRENT_STREAMS) {
322 		dc_stream_retain(stream);
323 
324 		core_power->map[core_power->num_entities].stream = stream;
325 		core_power->map[core_power->num_entities].caps = caps;
326 
327 		// initialize cached PSR params to something "safe" (something that is
328 		// consistent with disabled PSR state)
329 		core_power->map[core_power->num_entities].psr_enabled = 0;
330 		core_power->map[core_power->num_entities].psr_events = psr_event_vsync;
331 		core_power->map[core_power->num_entities].psr_power_opt = 0;
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 
392 		memcpy(core_power->map[i].psr_context, core_power->map[i + 1].psr_context, sizeof(struct mod_power_psr_context));
393 		memset(core_power->map[i + 1].psr_context, 0, sizeof(struct mod_power_psr_context));
394 	}
395 	core_power->num_entities--;
396 
397 	return true;
398 }
399 
400 /*
401  * Replace_stream should be used when there is a mode set for existing
402  * display target with a valid stream. In this case might need to retain
403  * cached PSR state (events, power opt, en/dis) if we are dealing with PSR
404  * capable display. If mod_power_remove and mod_power_add are used instead,
405  * then stream may be assigned to a different slot and may end up with
406  * wrong cached PSR state. It is hard to tell which PSR events should
407  * persist through mode set or what psr_events should be initialized to, so
408  * it might be better just to retain them all.
409  */
410 bool mod_power_replace_stream(struct mod_power *mod_power,
411 		const struct dc_stream_state *current_stream,
412 		struct dc_stream_state *new_stream,
413 		struct psr_caps *new_caps)
414 {
415 	struct core_power *core_power = NULL;
416 	unsigned int index = 0;
417 
418 	if (mod_power == NULL)
419 		return false;
420 
421 	core_power = MOD_POWER_TO_CORE(mod_power);
422 	if (core_power->num_entities == 0) {
423 		/* no streams exist in the table yet */
424 		BREAK_TO_DEBUGGER();
425 		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
426 							WPP_BIT_FLAG_Firmware_PsrState,
427 							"mod_power: replace_stream: ERROR: num_entities=0 stream=%p",
428 							current_stream);
429 		return false;
430 	}
431 
432 	index = map_index_from_stream(core_power, current_stream);
433 
434 	if (index >= core_power->num_entities) {
435 		/* trying to replace a non-existent stream */
436 		BREAK_TO_DEBUGGER();
437 		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
438 							WPP_BIT_FLAG_Firmware_PsrState,
439 							"mod_power: replace_stream: ERROR: index=%u >= num_entities=%u stream=%p",
440 							index,
441 							core_power->num_entities,
442 							current_stream);
443 		return false;
444 	}
445 
446 	dc_stream_release(core_power->map[index].stream);
447 	dc_stream_retain(new_stream);
448 	core_power->map[index].stream = new_stream;
449 	core_power->map[index].caps = new_caps;
450 	memset(core_power->map[index].psr_context, 0, sizeof(struct mod_power_psr_context));
451 
452 	return true;
453 }
454 bool mod_power_notify_mode_change(struct mod_power *mod_power,
455 		const struct dc_stream_state *stream,
456 		bool is_hdr)
457 {
458 	unsigned int stream_index = 0;
459 	struct core_power *core_power = NULL;
460 	struct dc_link *link = NULL;
461 	struct dc *dc = NULL;
462 	unsigned int panel_inst = 0;
463 	uint8_t aux_inst = 0;
464 
465 	if ((mod_power == NULL) || (stream == NULL))
466 		return false;
467 
468 	core_power = MOD_POWER_TO_CORE(mod_power);
469 
470 	if (core_power->num_entities == 0)
471 		return false;
472 
473 	stream_index = map_index_from_stream(core_power, stream);
474 
475 	if (stream_index >= core_power->num_entities)
476 		return false;
477 
478 	dc = core_power->dc;
479 	link = dc_stream_get_link(stream);
480 
481 	if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) {
482 		aux_inst = link->dc->link_srv->get_ddc_aux_inst(link);
483 
484 		mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr);
485 
486 		/* Handle PSR notification */
487 		mod_power_psr_notify_mode_change(mod_power, stream, link, stream_index);
488 
489 		/* Handle Replay notification */
490 		mod_power_replay_notify_mode_change(mod_power, dc, link, stream, stream_index);
491 	}
492 
493 	return true;
494 }
495 
496 bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream)
497 {
498 	return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal);
499 }
500