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