1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "dm_services.h"
27 #include "basics/dc_common.h"
28 #include "dc.h"
29 #include "core_types.h"
30 #include "resource.h"
31 #include "ipp.h"
32 #include "timing_generator.h"
33 #include "dc_dmub_srv.h"
34 #include "dc_state_priv.h"
35 #include "dc_stream_priv.h"
36 
37 #define DC_LOGGER dc->ctx->logger
38 
39 /*******************************************************************************
40  * Private functions
41  ******************************************************************************/
update_stream_signal(struct dc_stream_state * stream,struct dc_sink * sink)42 void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink)
43 {
44 	if (sink->sink_signal == SIGNAL_TYPE_NONE)
45 		stream->signal = stream->link->connector_signal;
46 	else
47 		stream->signal = sink->sink_signal;
48 
49 	if (dc_is_dvi_signal(stream->signal)) {
50 		if (stream->ctx->dc->caps.dual_link_dvi &&
51 			(stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK &&
52 			sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
53 			stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK;
54 		else
55 			stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
56 	}
57 }
58 
dc_stream_construct(struct dc_stream_state * stream,struct dc_sink * dc_sink_data)59 bool dc_stream_construct(struct dc_stream_state *stream,
60 	struct dc_sink *dc_sink_data)
61 {
62 	uint32_t i = 0;
63 
64 	stream->sink = dc_sink_data;
65 	dc_sink_retain(dc_sink_data);
66 
67 	stream->ctx = dc_sink_data->ctx;
68 	stream->link = dc_sink_data->link;
69 	stream->sink_patches = dc_sink_data->edid_caps.panel_patch;
70 	stream->converter_disable_audio = dc_sink_data->converter_disable_audio;
71 	stream->qs_bit = dc_sink_data->edid_caps.qs_bit;
72 	stream->qy_bit = dc_sink_data->edid_caps.qy_bit;
73 
74 	/* Copy audio modes */
75 	/* TODO - Remove this translation */
76 	for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++) {
77 		stream->audio_info.modes[i].channel_count = dc_sink_data->edid_caps.audio_modes[i].channel_count;
78 		stream->audio_info.modes[i].format_code = dc_sink_data->edid_caps.audio_modes[i].format_code;
79 		stream->audio_info.modes[i].sample_rates.all = dc_sink_data->edid_caps.audio_modes[i].sample_rate;
80 		stream->audio_info.modes[i].sample_size = dc_sink_data->edid_caps.audio_modes[i].sample_size;
81 	}
82 	stream->audio_info.mode_count = dc_sink_data->edid_caps.audio_mode_count;
83 	stream->audio_info.audio_latency = dc_sink_data->edid_caps.audio_latency;
84 	stream->audio_info.video_latency = dc_sink_data->edid_caps.video_latency;
85 	memmove(
86 		stream->audio_info.display_name,
87 		dc_sink_data->edid_caps.display_name,
88 		AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
89 	stream->audio_info.manufacture_id = dc_sink_data->edid_caps.manufacturer_id;
90 	stream->audio_info.product_id = dc_sink_data->edid_caps.product_id;
91 	stream->audio_info.flags.all = dc_sink_data->edid_caps.speaker_flags;
92 
93 	if (dc_sink_data->dc_container_id != NULL) {
94 		struct dc_container_id *dc_container_id = dc_sink_data->dc_container_id;
95 
96 		stream->audio_info.port_id[0] = dc_container_id->portId[0];
97 		stream->audio_info.port_id[1] = dc_container_id->portId[1];
98 	} else {
99 		/* TODO - WindowDM has implemented,
100 		other DMs need Unhardcode port_id */
101 		stream->audio_info.port_id[0] = 0x5558859e;
102 		stream->audio_info.port_id[1] = 0xd989449;
103 	}
104 
105 	/* EDID CAP translation for HDMI 2.0 */
106 	stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
107 
108 	memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg));
109 	stream->timing.dsc_cfg.num_slices_h = 0;
110 	stream->timing.dsc_cfg.num_slices_v = 0;
111 	stream->timing.dsc_cfg.bits_per_pixel = 128;
112 	stream->timing.dsc_cfg.block_pred_enable = 1;
113 	stream->timing.dsc_cfg.linebuf_depth = 9;
114 	stream->timing.dsc_cfg.version_minor = 2;
115 	stream->timing.dsc_cfg.ycbcr422_simple = 0;
116 
117 	update_stream_signal(stream, dc_sink_data);
118 
119 	stream->out_transfer_func = dc_create_transfer_func();
120 	if (stream->out_transfer_func == NULL) {
121 		dc_sink_release(dc_sink_data);
122 		return false;
123 	}
124 	stream->out_transfer_func->type = TF_TYPE_BYPASS;
125 
126 	dc_stream_assign_stream_id(stream);
127 
128 	return true;
129 }
130 
dc_stream_destruct(struct dc_stream_state * stream)131 void dc_stream_destruct(struct dc_stream_state *stream)
132 {
133 	dc_sink_release(stream->sink);
134 	if (stream->out_transfer_func != NULL) {
135 		dc_transfer_func_release(stream->out_transfer_func);
136 		stream->out_transfer_func = NULL;
137 	}
138 }
139 
dc_stream_assign_stream_id(struct dc_stream_state * stream)140 void dc_stream_assign_stream_id(struct dc_stream_state *stream)
141 {
142 	/* MSB is reserved to indicate phantoms */
143 	stream->stream_id = stream->ctx->dc_stream_id_count;
144 	stream->ctx->dc_stream_id_count++;
145 }
146 
dc_stream_retain(struct dc_stream_state * stream)147 void dc_stream_retain(struct dc_stream_state *stream)
148 {
149 	kref_get(&stream->refcount);
150 }
151 
dc_stream_free(struct kref * kref)152 static void dc_stream_free(struct kref *kref)
153 {
154 	struct dc_stream_state *stream = container_of(kref, struct dc_stream_state, refcount);
155 
156 	dc_stream_destruct(stream);
157 	kfree(stream);
158 }
159 
dc_stream_release(struct dc_stream_state * stream)160 void dc_stream_release(struct dc_stream_state *stream)
161 {
162 	if (stream != NULL) {
163 		kref_put(&stream->refcount, dc_stream_free);
164 	}
165 }
166 
dc_create_stream_for_sink(struct dc_sink * sink)167 struct dc_stream_state *dc_create_stream_for_sink(
168 		struct dc_sink *sink)
169 {
170 	struct dc_stream_state *stream;
171 
172 	if (sink == NULL)
173 		return NULL;
174 
175 	stream = kzalloc(sizeof(struct dc_stream_state), GFP_KERNEL);
176 	if (stream == NULL)
177 		goto alloc_fail;
178 
179 	if (dc_stream_construct(stream, sink) == false)
180 		goto construct_fail;
181 
182 	kref_init(&stream->refcount);
183 
184 	return stream;
185 
186 construct_fail:
187 	kfree(stream);
188 
189 alloc_fail:
190 	return NULL;
191 }
192 
dc_copy_stream(const struct dc_stream_state * stream)193 struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream)
194 {
195 	struct dc_stream_state *new_stream;
196 
197 	new_stream = kmemdup(stream, sizeof(struct dc_stream_state), GFP_KERNEL);
198 	if (!new_stream)
199 		return NULL;
200 
201 	if (new_stream->sink)
202 		dc_sink_retain(new_stream->sink);
203 
204 	if (new_stream->out_transfer_func)
205 		dc_transfer_func_retain(new_stream->out_transfer_func);
206 
207 	dc_stream_assign_stream_id(new_stream);
208 
209 	/* If using dynamic encoder assignment, wait till stream committed to assign encoder. */
210 	if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign)
211 		new_stream->link_enc = NULL;
212 
213 	kref_init(&new_stream->refcount);
214 
215 	return new_stream;
216 }
217 
218 /**
219  * dc_stream_get_status() - Get current stream status of the given stream state
220  * @stream: The stream to get the stream status for.
221  *
222  * The given stream is expected to exist in dc->current_state. Otherwise, NULL
223  * will be returned.
224  */
dc_stream_get_status(struct dc_stream_state * stream)225 struct dc_stream_status *dc_stream_get_status(
226 	struct dc_stream_state *stream)
227 {
228 	struct dc *dc = stream->ctx->dc;
229 	return dc_state_get_stream_status(dc->current_state, stream);
230 }
231 
program_cursor_attributes(struct dc * dc,struct dc_stream_state * stream,const struct dc_cursor_attributes * attributes)232 static void program_cursor_attributes(
233 	struct dc *dc,
234 	struct dc_stream_state *stream,
235 	const struct dc_cursor_attributes *attributes)
236 {
237 	int i;
238 	struct resource_context *res_ctx;
239 	struct pipe_ctx *pipe_to_program = NULL;
240 
241 	if (!stream)
242 		return;
243 
244 	res_ctx = &dc->current_state->res_ctx;
245 
246 	for (i = 0; i < MAX_PIPES; i++) {
247 		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
248 
249 		if (pipe_ctx->stream != stream)
250 			continue;
251 
252 		if (!pipe_to_program) {
253 			pipe_to_program = pipe_ctx;
254 			dc->hwss.cursor_lock(dc, pipe_to_program, true);
255 			if (pipe_to_program->next_odm_pipe)
256 				dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
257 		}
258 
259 		dc->hwss.set_cursor_attribute(pipe_ctx);
260 		if (dc->ctx->dmub_srv)
261 			dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
262 		if (dc->hwss.set_cursor_sdr_white_level)
263 			dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
264 	}
265 
266 	if (pipe_to_program) {
267 		dc->hwss.cursor_lock(dc, pipe_to_program, false);
268 		if (pipe_to_program->next_odm_pipe)
269 			dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
270 	}
271 }
272 
273 /*
274  * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address
275  */
dc_stream_set_cursor_attributes(struct dc_stream_state * stream,const struct dc_cursor_attributes * attributes)276 bool dc_stream_set_cursor_attributes(
277 	struct dc_stream_state *stream,
278 	const struct dc_cursor_attributes *attributes)
279 {
280 	struct dc  *dc;
281 	bool reset_idle_optimizations = false;
282 
283 	if (NULL == stream) {
284 		dm_error("DC: dc_stream is NULL!\n");
285 		return false;
286 	}
287 	if (NULL == attributes) {
288 		dm_error("DC: attributes is NULL!\n");
289 		return false;
290 	}
291 
292 	if (attributes->address.quad_part == 0) {
293 		dm_output_to_console("DC: Cursor address is 0!\n");
294 		return false;
295 	}
296 
297 	dc = stream->ctx->dc;
298 
299 	/* SubVP is not compatible with HW cursor larger than 64 x 64 x 4.
300 	 * Therefore, if cursor is greater than 64 x 64 x 4, fallback to SW cursor in the following case:
301 	 * 1. If the config is a candidate for SubVP high refresh (both single an dual display configs)
302 	 * 2. If not subvp high refresh, for single display cases, if resolution is >= 5K and refresh rate < 120hz
303 	 * 3. If not subvp high refresh, for multi display cases, if resolution is >= 4K and refresh rate < 120hz
304 	 */
305 	if (dc->debug.allow_sw_cursor_fallback && attributes->height * attributes->width * 4 > 16384) {
306 		if (check_subvp_sw_cursor_fallback_req(dc, stream))
307 			return false;
308 	}
309 
310 	stream->cursor_attributes = *attributes;
311 
312 	dc_z10_restore(dc);
313 	/* disable idle optimizations while updating cursor */
314 	if (dc->idle_optimizations_allowed) {
315 		dc_allow_idle_optimizations(dc, false);
316 		reset_idle_optimizations = true;
317 	}
318 
319 	program_cursor_attributes(dc, stream, attributes);
320 
321 	/* re-enable idle optimizations if necessary */
322 	if (reset_idle_optimizations)
323 		dc_allow_idle_optimizations(dc, true);
324 
325 	return true;
326 }
327 
program_cursor_position(struct dc * dc,struct dc_stream_state * stream,const struct dc_cursor_position * position)328 static void program_cursor_position(
329 	struct dc *dc,
330 	struct dc_stream_state *stream,
331 	const struct dc_cursor_position *position)
332 {
333 	int i;
334 	struct resource_context *res_ctx;
335 	struct pipe_ctx *pipe_to_program = NULL;
336 
337 	if (!stream)
338 		return;
339 
340 	res_ctx = &dc->current_state->res_ctx;
341 
342 	for (i = 0; i < MAX_PIPES; i++) {
343 		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
344 
345 		if (pipe_ctx->stream != stream ||
346 				(!pipe_ctx->plane_res.mi  && !pipe_ctx->plane_res.hubp) ||
347 				!pipe_ctx->plane_state ||
348 				(!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) ||
349 				(!pipe_ctx->plane_res.ipp && !pipe_ctx->plane_res.dpp))
350 			continue;
351 
352 		if (!pipe_to_program) {
353 			pipe_to_program = pipe_ctx;
354 			dc->hwss.cursor_lock(dc, pipe_to_program, true);
355 		}
356 
357 		dc->hwss.set_cursor_position(pipe_ctx);
358 		if (dc->ctx->dmub_srv)
359 			dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
360 	}
361 
362 	if (pipe_to_program)
363 		dc->hwss.cursor_lock(dc, pipe_to_program, false);
364 }
365 
dc_stream_set_cursor_position(struct dc_stream_state * stream,const struct dc_cursor_position * position)366 bool dc_stream_set_cursor_position(
367 	struct dc_stream_state *stream,
368 	const struct dc_cursor_position *position)
369 {
370 	struct dc *dc;
371 	bool reset_idle_optimizations = false;
372 
373 	if (NULL == stream) {
374 		dm_error("DC: dc_stream is NULL!\n");
375 		return false;
376 	}
377 
378 	if (NULL == position) {
379 		dm_error("DC: cursor position is NULL!\n");
380 		return false;
381 	}
382 
383 	dc = stream->ctx->dc;
384 	dc_z10_restore(dc);
385 
386 	/* disable idle optimizations if enabling cursor */
387 	if (dc->idle_optimizations_allowed && (!stream->cursor_position.enable || dc->debug.exit_idle_opt_for_cursor_updates)
388 			&& position->enable) {
389 		dc_allow_idle_optimizations(dc, false);
390 		reset_idle_optimizations = true;
391 	}
392 
393 	stream->cursor_position = *position;
394 
395 	program_cursor_position(dc, stream, position);
396 	/* re-enable idle optimizations if necessary */
397 	if (reset_idle_optimizations)
398 		dc_allow_idle_optimizations(dc, true);
399 
400 	return true;
401 }
402 
dc_stream_add_writeback(struct dc * dc,struct dc_stream_state * stream,struct dc_writeback_info * wb_info)403 bool dc_stream_add_writeback(struct dc *dc,
404 		struct dc_stream_state *stream,
405 		struct dc_writeback_info *wb_info)
406 {
407 	bool isDrc = false;
408 	int i = 0;
409 	struct dwbc *dwb;
410 
411 	if (stream == NULL) {
412 		dm_error("DC: dc_stream is NULL!\n");
413 		return false;
414 	}
415 
416 	if (wb_info == NULL) {
417 		dm_error("DC: dc_writeback_info is NULL!\n");
418 		return false;
419 	}
420 
421 	if (wb_info->dwb_pipe_inst >= MAX_DWB_PIPES) {
422 		dm_error("DC: writeback pipe is invalid!\n");
423 		return false;
424 	}
425 
426 	wb_info->dwb_params.out_transfer_func = stream->out_transfer_func;
427 
428 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
429 	dwb->dwb_is_drc = false;
430 
431 	/* recalculate and apply DML parameters */
432 
433 	for (i = 0; i < stream->num_wb_info; i++) {
434 		/*dynamic update*/
435 		if (stream->writeback_info[i].wb_enabled &&
436 			stream->writeback_info[i].dwb_pipe_inst == wb_info->dwb_pipe_inst) {
437 			stream->writeback_info[i] = *wb_info;
438 			isDrc = true;
439 		}
440 	}
441 
442 	if (!isDrc) {
443 		ASSERT(stream->num_wb_info + 1 <= MAX_DWB_PIPES);
444 		stream->writeback_info[stream->num_wb_info++] = *wb_info;
445 	}
446 
447 	if (dc->hwss.enable_writeback) {
448 		struct dc_stream_status *stream_status = dc_stream_get_status(stream);
449 		struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
450 		if (stream_status)
451 			dwb->otg_inst = stream_status->primary_otg_inst;
452 	}
453 
454 	if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
455 		dm_error("DC: update_bandwidth failed!\n");
456 		return false;
457 	}
458 
459 	/* enable writeback */
460 	if (dc->hwss.enable_writeback) {
461 		struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
462 
463 		if (dwb->funcs->is_enabled(dwb)) {
464 			/* writeback pipe already enabled, only need to update */
465 			dc->hwss.update_writeback(dc, wb_info, dc->current_state);
466 		} else {
467 			/* Enable writeback pipe from scratch*/
468 			dc->hwss.enable_writeback(dc, wb_info, dc->current_state);
469 		}
470 	}
471 
472 	return true;
473 }
474 
dc_stream_fc_disable_writeback(struct dc * dc,struct dc_stream_state * stream,uint32_t dwb_pipe_inst)475 bool dc_stream_fc_disable_writeback(struct dc *dc,
476 		struct dc_stream_state *stream,
477 		uint32_t dwb_pipe_inst)
478 {
479 	struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst];
480 
481 	if (stream == NULL) {
482 		dm_error("DC: dc_stream is NULL!\n");
483 		return false;
484 	}
485 
486 	if (dwb_pipe_inst >= MAX_DWB_PIPES) {
487 		dm_error("DC: writeback pipe is invalid!\n");
488 		return false;
489 	}
490 
491 	if (stream->num_wb_info > MAX_DWB_PIPES) {
492 		dm_error("DC: num_wb_info is invalid!\n");
493 		return false;
494 	}
495 
496 	if (dwb->funcs->set_fc_enable)
497 		dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE);
498 
499 	return true;
500 }
501 
dc_stream_remove_writeback(struct dc * dc,struct dc_stream_state * stream,uint32_t dwb_pipe_inst)502 bool dc_stream_remove_writeback(struct dc *dc,
503 		struct dc_stream_state *stream,
504 		uint32_t dwb_pipe_inst)
505 {
506 	int i = 0, j = 0;
507 	if (stream == NULL) {
508 		dm_error("DC: dc_stream is NULL!\n");
509 		return false;
510 	}
511 
512 	if (dwb_pipe_inst >= MAX_DWB_PIPES) {
513 		dm_error("DC: writeback pipe is invalid!\n");
514 		return false;
515 	}
516 
517 	if (stream->num_wb_info > MAX_DWB_PIPES) {
518 		dm_error("DC: num_wb_info is invalid!\n");
519 		return false;
520 	}
521 
522 	/* remove writeback info for disabled writeback pipes from stream */
523 	for (i = 0, j = 0; i < stream->num_wb_info; i++) {
524 		if (stream->writeback_info[i].wb_enabled) {
525 
526 			if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst)
527 				stream->writeback_info[i].wb_enabled = false;
528 
529 			/* trim the array */
530 			if (j < i) {
531 				memcpy(&stream->writeback_info[j], &stream->writeback_info[i],
532 						sizeof(struct dc_writeback_info));
533 				j++;
534 			}
535 		}
536 	}
537 	stream->num_wb_info = j;
538 
539 	/* recalculate and apply DML parameters */
540 	if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
541 		dm_error("DC: update_bandwidth failed!\n");
542 		return false;
543 	}
544 
545 	/* disable writeback */
546 	if (dc->hwss.disable_writeback) {
547 		struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst];
548 
549 		if (dwb->funcs->is_enabled(dwb))
550 			dc->hwss.disable_writeback(dc, dwb_pipe_inst);
551 	}
552 
553 	return true;
554 }
555 
dc_stream_warmup_writeback(struct dc * dc,int num_dwb,struct dc_writeback_info * wb_info)556 bool dc_stream_warmup_writeback(struct dc *dc,
557 		int num_dwb,
558 		struct dc_writeback_info *wb_info)
559 {
560 	if (dc->hwss.mmhubbub_warmup)
561 		return dc->hwss.mmhubbub_warmup(dc, num_dwb, wb_info);
562 	else
563 		return false;
564 }
dc_stream_get_vblank_counter(const struct dc_stream_state * stream)565 uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream)
566 {
567 	uint8_t i;
568 	struct dc  *dc = stream->ctx->dc;
569 	struct resource_context *res_ctx =
570 		&dc->current_state->res_ctx;
571 
572 	for (i = 0; i < MAX_PIPES; i++) {
573 		struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
574 
575 		if (res_ctx->pipe_ctx[i].stream != stream || !tg)
576 			continue;
577 
578 		return tg->funcs->get_frame_count(tg);
579 	}
580 
581 	return 0;
582 }
583 
dc_stream_send_dp_sdp(const struct dc_stream_state * stream,const uint8_t * custom_sdp_message,unsigned int sdp_message_size)584 bool dc_stream_send_dp_sdp(const struct dc_stream_state *stream,
585 		const uint8_t *custom_sdp_message,
586 		unsigned int sdp_message_size)
587 {
588 	int i;
589 	struct dc  *dc;
590 	struct resource_context *res_ctx;
591 
592 	if (stream == NULL) {
593 		dm_error("DC: dc_stream is NULL!\n");
594 		return false;
595 	}
596 
597 	dc = stream->ctx->dc;
598 	res_ctx = &dc->current_state->res_ctx;
599 
600 	for (i = 0; i < MAX_PIPES; i++) {
601 		struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
602 
603 		if (pipe_ctx->stream != stream)
604 			continue;
605 
606 		if (dc->hwss.send_immediate_sdp_message != NULL)
607 			dc->hwss.send_immediate_sdp_message(pipe_ctx,
608 								custom_sdp_message,
609 								sdp_message_size);
610 		else
611 			DC_LOG_WARNING("%s:send_immediate_sdp_message not implemented on this ASIC\n",
612 			__func__);
613 
614 	}
615 
616 	return true;
617 }
618 
dc_stream_get_scanoutpos(const struct dc_stream_state * stream,uint32_t * v_blank_start,uint32_t * v_blank_end,uint32_t * h_position,uint32_t * v_position)619 bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,
620 				  uint32_t *v_blank_start,
621 				  uint32_t *v_blank_end,
622 				  uint32_t *h_position,
623 				  uint32_t *v_position)
624 {
625 	uint8_t i;
626 	bool ret = false;
627 	struct dc  *dc = stream->ctx->dc;
628 	struct resource_context *res_ctx =
629 		&dc->current_state->res_ctx;
630 
631 	for (i = 0; i < MAX_PIPES; i++) {
632 		struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
633 
634 		if (res_ctx->pipe_ctx[i].stream != stream || !tg)
635 			continue;
636 
637 		tg->funcs->get_scanoutpos(tg,
638 					  v_blank_start,
639 					  v_blank_end,
640 					  h_position,
641 					  v_position);
642 
643 		ret = true;
644 		break;
645 	}
646 
647 	return ret;
648 }
649 
dc_stream_dmdata_status_done(struct dc * dc,struct dc_stream_state * stream)650 bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream)
651 {
652 	struct pipe_ctx *pipe = NULL;
653 	int i;
654 
655 	if (!dc->hwss.dmdata_status_done)
656 		return false;
657 
658 	for (i = 0; i < MAX_PIPES; i++) {
659 		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
660 		if (pipe->stream == stream)
661 			break;
662 	}
663 	/* Stream not found, by default we'll assume HUBP fetched dm data */
664 	if (i == MAX_PIPES)
665 		return true;
666 
667 	return dc->hwss.dmdata_status_done(pipe);
668 }
669 
dc_stream_set_dynamic_metadata(struct dc * dc,struct dc_stream_state * stream,struct dc_dmdata_attributes * attr)670 bool dc_stream_set_dynamic_metadata(struct dc *dc,
671 		struct dc_stream_state *stream,
672 		struct dc_dmdata_attributes *attr)
673 {
674 	struct pipe_ctx *pipe_ctx = NULL;
675 	struct hubp *hubp;
676 	int i;
677 
678 	/* Dynamic metadata is only supported on HDMI or DP */
679 	if (!dc_is_hdmi_signal(stream->signal) && !dc_is_dp_signal(stream->signal))
680 		return false;
681 
682 	/* Check hardware support */
683 	if (!dc->hwss.program_dmdata_engine)
684 		return false;
685 
686 	for (i = 0; i < MAX_PIPES; i++) {
687 		pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
688 		if (pipe_ctx->stream == stream)
689 			break;
690 	}
691 
692 	if (i == MAX_PIPES)
693 		return false;
694 
695 	hubp = pipe_ctx->plane_res.hubp;
696 	if (hubp == NULL)
697 		return false;
698 
699 	pipe_ctx->stream->dmdata_address = attr->address;
700 
701 	dc->hwss.program_dmdata_engine(pipe_ctx);
702 
703 	if (hubp->funcs->dmdata_set_attributes != NULL &&
704 			pipe_ctx->stream->dmdata_address.quad_part != 0) {
705 		hubp->funcs->dmdata_set_attributes(hubp, attr);
706 	}
707 
708 	return true;
709 }
710 
dc_stream_add_dsc_to_resource(struct dc * dc,struct dc_state * state,struct dc_stream_state * stream)711 enum dc_status dc_stream_add_dsc_to_resource(struct dc *dc,
712 		struct dc_state *state,
713 		struct dc_stream_state *stream)
714 {
715 	if (dc->res_pool->funcs->add_dsc_to_stream_resource) {
716 		return dc->res_pool->funcs->add_dsc_to_stream_resource(dc, state, stream);
717 	} else {
718 		return DC_NO_DSC_RESOURCE;
719 	}
720 }
721 
dc_stream_get_pipe_ctx(struct dc_stream_state * stream)722 struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream)
723 {
724 	int i = 0;
725 
726 	for (i = 0; i < MAX_PIPES; i++) {
727 		struct pipe_ctx *pipe = &stream->ctx->dc->current_state->res_ctx.pipe_ctx[i];
728 
729 		if (pipe->stream == stream)
730 			return pipe;
731 	}
732 
733 	return NULL;
734 }
735 
dc_stream_log(const struct dc * dc,const struct dc_stream_state * stream)736 void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
737 {
738 	DC_LOG_DC(
739 			"core_stream 0x%p: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n",
740 			stream,
741 			stream->src.x,
742 			stream->src.y,
743 			stream->src.width,
744 			stream->src.height,
745 			stream->dst.x,
746 			stream->dst.y,
747 			stream->dst.width,
748 			stream->dst.height,
749 			stream->output_color_space);
750 	DC_LOG_DC(
751 			"\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n",
752 			stream->timing.pix_clk_100hz / 10,
753 			stream->timing.h_total,
754 			stream->timing.v_total,
755 			stream->timing.pixel_encoding,
756 			stream->timing.display_color_depth);
757 	DC_LOG_DC(
758 			"\tlink: %d\n",
759 			stream->link->link_index);
760 
761 	DC_LOG_DC(
762 			"\tdsc: %d, mst_pbn: %d\n",
763 			stream->timing.flags.DSC,
764 			stream->timing.dsc_cfg.mst_pbn);
765 
766 	if (stream->sink) {
767 		if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
768 			stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
769 
770 			DC_LOG_DC(
771 					"\tdispname: %s signal: %x\n",
772 					stream->sink->edid_caps.display_name,
773 					stream->signal);
774 		}
775 	}
776 }
777 
778