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