]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drm/amd/display: Audio is not switching to DP when HDMI/DP hot plug/unplug
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / dce110 / dce110_hw_sequencer.c
1 /*
2 * Copyright 2015 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 #include "dm_services.h"
26 #include "dc.h"
27 #include "dc_bios_types.h"
28 #include "core_types.h"
29 #include "core_status.h"
30 #include "resource.h"
31 #include "hw_sequencer.h"
32 #include "dm_helpers.h"
33 #include "dce110_hw_sequencer.h"
34 #include "dce110_timing_generator.h"
35
36 #include "bios/bios_parser_helper.h"
37 #include "timing_generator.h"
38 #include "mem_input.h"
39 #include "opp.h"
40 #include "ipp.h"
41 #include "transform.h"
42 #include "stream_encoder.h"
43 #include "link_encoder.h"
44 #include "clock_source.h"
45 #include "abm.h"
46 #include "audio.h"
47 #include "dce/dce_hwseq.h"
48
49 /* include DCE11 register header files */
50 #include "dce/dce_11_0_d.h"
51 #include "dce/dce_11_0_sh_mask.h"
52
53 struct dce110_hw_seq_reg_offsets {
54 uint32_t crtc;
55 };
56
57 static const struct dce110_hw_seq_reg_offsets reg_offsets[] = {
58 {
59 .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
60 },
61 {
62 .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
63 },
64 {
65 .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
66 },
67 {
68 .crtc = (mmCRTCV_GSL_CONTROL - mmCRTC_GSL_CONTROL),
69 }
70 };
71
72 #define HW_REG_BLND(reg, id)\
73 (reg + reg_offsets[id].blnd)
74
75 #define HW_REG_CRTC(reg, id)\
76 (reg + reg_offsets[id].crtc)
77
78 #define MAX_WATERMARK 0xFFFF
79 #define SAFE_NBP_MARK 0x7FFF
80
81 /*******************************************************************************
82 * Private definitions
83 ******************************************************************************/
84 /***************************PIPE_CONTROL***********************************/
85 static void dce110_init_pte(struct dc_context *ctx)
86 {
87 uint32_t addr;
88 uint32_t value = 0;
89 uint32_t chunk_int = 0;
90 uint32_t chunk_mul = 0;
91
92 addr = mmUNP_DVMM_PTE_CONTROL;
93 value = dm_read_reg(ctx, addr);
94
95 set_reg_field_value(
96 value,
97 0,
98 DVMM_PTE_CONTROL,
99 DVMM_USE_SINGLE_PTE);
100
101 set_reg_field_value(
102 value,
103 1,
104 DVMM_PTE_CONTROL,
105 DVMM_PTE_BUFFER_MODE0);
106
107 set_reg_field_value(
108 value,
109 1,
110 DVMM_PTE_CONTROL,
111 DVMM_PTE_BUFFER_MODE1);
112
113 dm_write_reg(ctx, addr, value);
114
115 addr = mmDVMM_PTE_REQ;
116 value = dm_read_reg(ctx, addr);
117
118 chunk_int = get_reg_field_value(
119 value,
120 DVMM_PTE_REQ,
121 HFLIP_PTEREQ_PER_CHUNK_INT);
122
123 chunk_mul = get_reg_field_value(
124 value,
125 DVMM_PTE_REQ,
126 HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
127
128 if (chunk_int != 0x4 || chunk_mul != 0x4) {
129
130 set_reg_field_value(
131 value,
132 255,
133 DVMM_PTE_REQ,
134 MAX_PTEREQ_TO_ISSUE);
135
136 set_reg_field_value(
137 value,
138 4,
139 DVMM_PTE_REQ,
140 HFLIP_PTEREQ_PER_CHUNK_INT);
141
142 set_reg_field_value(
143 value,
144 4,
145 DVMM_PTE_REQ,
146 HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
147
148 dm_write_reg(ctx, addr, value);
149 }
150 }
151 /**************************************************************************/
152
153 static void enable_display_pipe_clock_gating(
154 struct dc_context *ctx,
155 bool clock_gating)
156 {
157 /*TODO*/
158 }
159
160 static bool dce110_enable_display_power_gating(
161 struct core_dc *dc,
162 uint8_t controller_id,
163 struct dc_bios *dcb,
164 enum pipe_gating_control power_gating)
165 {
166 enum bp_result bp_result = BP_RESULT_OK;
167 enum bp_pipe_control_action cntl;
168 struct dc_context *ctx = dc->ctx;
169 unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
170
171 if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
172 return true;
173
174 if (power_gating == PIPE_GATING_CONTROL_INIT)
175 cntl = ASIC_PIPE_INIT;
176 else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
177 cntl = ASIC_PIPE_ENABLE;
178 else
179 cntl = ASIC_PIPE_DISABLE;
180
181 if (controller_id == underlay_idx)
182 controller_id = CONTROLLER_ID_UNDERLAY0 - 1;
183
184 if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0){
185
186 bp_result = dcb->funcs->enable_disp_power_gating(
187 dcb, controller_id + 1, cntl);
188
189 /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2
190 * by default when command table is called
191 *
192 * Bios parser accepts controller_id = 6 as indicative of
193 * underlay pipe in dce110. But we do not support more
194 * than 3.
195 */
196 if (controller_id < CONTROLLER_ID_MAX - 1)
197 dm_write_reg(ctx,
198 HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id),
199 0);
200 }
201
202 if (power_gating != PIPE_GATING_CONTROL_ENABLE)
203 dce110_init_pte(ctx);
204
205 if (bp_result == BP_RESULT_OK)
206 return true;
207 else
208 return false;
209 }
210
211 static void build_prescale_params(struct ipp_prescale_params *prescale_params,
212 const struct core_surface *surface)
213 {
214 prescale_params->mode = IPP_PRESCALE_MODE_FIXED_UNSIGNED;
215
216 switch (surface->public.format) {
217 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
218 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
219 prescale_params->scale = 0x2020;
220 break;
221 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
222 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
223 prescale_params->scale = 0x2008;
224 break;
225 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
226 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
227 prescale_params->scale = 0x2000;
228 break;
229 default:
230 ASSERT(false);
231 break;
232 }
233 }
234
235 static bool dce110_set_input_transfer_func(
236 struct pipe_ctx *pipe_ctx,
237 const struct core_surface *surface)
238 {
239 struct input_pixel_processor *ipp = pipe_ctx->ipp;
240 const struct core_transfer_func *tf = NULL;
241 struct ipp_prescale_params prescale_params = { 0 };
242 bool result = true;
243
244 if (ipp == NULL)
245 return false;
246
247 if (surface->public.in_transfer_func)
248 tf = DC_TRANSFER_FUNC_TO_CORE(surface->public.in_transfer_func);
249
250 build_prescale_params(&prescale_params, surface);
251 ipp->funcs->ipp_program_prescale(ipp, &prescale_params);
252
253 if (surface->public.gamma_correction)
254 ipp->funcs->ipp_program_input_lut(ipp, surface->public.gamma_correction);
255
256 if (tf == NULL) {
257 /* Default case if no input transfer function specified */
258 ipp->funcs->ipp_set_degamma(ipp,
259 IPP_DEGAMMA_MODE_HW_sRGB);
260 } else if (tf->public.type == TF_TYPE_PREDEFINED) {
261 switch (tf->public.tf) {
262 case TRANSFER_FUNCTION_SRGB:
263 ipp->funcs->ipp_set_degamma(ipp,
264 IPP_DEGAMMA_MODE_HW_sRGB);
265 break;
266 case TRANSFER_FUNCTION_BT709:
267 ipp->funcs->ipp_set_degamma(ipp,
268 IPP_DEGAMMA_MODE_HW_xvYCC);
269 break;
270 case TRANSFER_FUNCTION_LINEAR:
271 ipp->funcs->ipp_set_degamma(ipp,
272 IPP_DEGAMMA_MODE_BYPASS);
273 break;
274 case TRANSFER_FUNCTION_PQ:
275 result = false;
276 break;
277 default:
278 result = false;
279 break;
280 }
281 } else {
282 /*TF_TYPE_DISTRIBUTED_POINTS - Not supported in DCE 11*/
283 result = false;
284 }
285
286 return result;
287 }
288
289 static bool build_custom_float(
290 struct fixed31_32 value,
291 const struct custom_float_format *format,
292 bool *negative,
293 uint32_t *mantissa,
294 uint32_t *exponenta)
295 {
296 uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1;
297
298 const struct fixed31_32 mantissa_constant_plus_max_fraction =
299 dal_fixed31_32_from_fraction(
300 (1LL << (format->mantissa_bits + 1)) - 1,
301 1LL << format->mantissa_bits);
302
303 struct fixed31_32 mantiss;
304
305 if (dal_fixed31_32_eq(
306 value,
307 dal_fixed31_32_zero)) {
308 *negative = false;
309 *mantissa = 0;
310 *exponenta = 0;
311 return true;
312 }
313
314 if (dal_fixed31_32_lt(
315 value,
316 dal_fixed31_32_zero)) {
317 *negative = format->sign;
318 value = dal_fixed31_32_neg(value);
319 } else {
320 *negative = false;
321 }
322
323 if (dal_fixed31_32_lt(
324 value,
325 dal_fixed31_32_one)) {
326 uint32_t i = 1;
327
328 do {
329 value = dal_fixed31_32_shl(value, 1);
330 ++i;
331 } while (dal_fixed31_32_lt(
332 value,
333 dal_fixed31_32_one));
334
335 --i;
336
337 if (exp_offset <= i) {
338 *mantissa = 0;
339 *exponenta = 0;
340 return true;
341 }
342
343 *exponenta = exp_offset - i;
344 } else if (dal_fixed31_32_le(
345 mantissa_constant_plus_max_fraction,
346 value)) {
347 uint32_t i = 1;
348
349 do {
350 value = dal_fixed31_32_shr(value, 1);
351 ++i;
352 } while (dal_fixed31_32_lt(
353 mantissa_constant_plus_max_fraction,
354 value));
355
356 *exponenta = exp_offset + i - 1;
357 } else {
358 *exponenta = exp_offset;
359 }
360
361 mantiss = dal_fixed31_32_sub(
362 value,
363 dal_fixed31_32_one);
364
365 if (dal_fixed31_32_lt(
366 mantiss,
367 dal_fixed31_32_zero) ||
368 dal_fixed31_32_lt(
369 dal_fixed31_32_one,
370 mantiss))
371 mantiss = dal_fixed31_32_zero;
372 else
373 mantiss = dal_fixed31_32_shl(
374 mantiss,
375 format->mantissa_bits);
376
377 *mantissa = dal_fixed31_32_floor(mantiss);
378
379 return true;
380 }
381
382 static bool setup_custom_float(
383 const struct custom_float_format *format,
384 bool negative,
385 uint32_t mantissa,
386 uint32_t exponenta,
387 uint32_t *result)
388 {
389 uint32_t i = 0;
390 uint32_t j = 0;
391
392 uint32_t value = 0;
393
394 /* verification code:
395 * once calculation is ok we can remove it
396 */
397
398 const uint32_t mantissa_mask =
399 (1 << (format->mantissa_bits + 1)) - 1;
400
401 const uint32_t exponenta_mask =
402 (1 << (format->exponenta_bits + 1)) - 1;
403
404 if (mantissa & ~mantissa_mask) {
405 BREAK_TO_DEBUGGER();
406 mantissa = mantissa_mask;
407 }
408
409 if (exponenta & ~exponenta_mask) {
410 BREAK_TO_DEBUGGER();
411 exponenta = exponenta_mask;
412 }
413
414 /* end of verification code */
415
416 while (i < format->mantissa_bits) {
417 uint32_t mask = 1 << i;
418
419 if (mantissa & mask)
420 value |= mask;
421
422 ++i;
423 }
424
425 while (j < format->exponenta_bits) {
426 uint32_t mask = 1 << j;
427
428 if (exponenta & mask)
429 value |= mask << i;
430
431 ++j;
432 }
433
434 if (negative && format->sign)
435 value |= 1 << (i + j);
436
437 *result = value;
438
439 return true;
440 }
441
442 static bool convert_to_custom_float_format(
443 struct fixed31_32 value,
444 const struct custom_float_format *format,
445 uint32_t *result)
446 {
447 uint32_t mantissa;
448 uint32_t exponenta;
449 bool negative;
450
451 return build_custom_float(
452 value, format, &negative, &mantissa, &exponenta) &&
453 setup_custom_float(
454 format, negative, mantissa, exponenta, result);
455 }
456
457 static bool convert_to_custom_float(
458 struct pwl_result_data *rgb_resulted,
459 struct curve_points *arr_points,
460 uint32_t hw_points_num)
461 {
462 struct custom_float_format fmt;
463
464 struct pwl_result_data *rgb = rgb_resulted;
465
466 uint32_t i = 0;
467
468 fmt.exponenta_bits = 6;
469 fmt.mantissa_bits = 12;
470 fmt.sign = true;
471
472 if (!convert_to_custom_float_format(
473 arr_points[0].x,
474 &fmt,
475 &arr_points[0].custom_float_x)) {
476 BREAK_TO_DEBUGGER();
477 return false;
478 }
479
480 if (!convert_to_custom_float_format(
481 arr_points[0].offset,
482 &fmt,
483 &arr_points[0].custom_float_offset)) {
484 BREAK_TO_DEBUGGER();
485 return false;
486 }
487
488 if (!convert_to_custom_float_format(
489 arr_points[0].slope,
490 &fmt,
491 &arr_points[0].custom_float_slope)) {
492 BREAK_TO_DEBUGGER();
493 return false;
494 }
495
496 fmt.mantissa_bits = 10;
497 fmt.sign = false;
498
499 if (!convert_to_custom_float_format(
500 arr_points[1].x,
501 &fmt,
502 &arr_points[1].custom_float_x)) {
503 BREAK_TO_DEBUGGER();
504 return false;
505 }
506
507 if (!convert_to_custom_float_format(
508 arr_points[1].y,
509 &fmt,
510 &arr_points[1].custom_float_y)) {
511 BREAK_TO_DEBUGGER();
512 return false;
513 }
514
515 if (!convert_to_custom_float_format(
516 arr_points[2].slope,
517 &fmt,
518 &arr_points[2].custom_float_slope)) {
519 BREAK_TO_DEBUGGER();
520 return false;
521 }
522
523 fmt.mantissa_bits = 12;
524 fmt.sign = true;
525
526 while (i != hw_points_num) {
527 if (!convert_to_custom_float_format(
528 rgb->red,
529 &fmt,
530 &rgb->red_reg)) {
531 BREAK_TO_DEBUGGER();
532 return false;
533 }
534
535 if (!convert_to_custom_float_format(
536 rgb->green,
537 &fmt,
538 &rgb->green_reg)) {
539 BREAK_TO_DEBUGGER();
540 return false;
541 }
542
543 if (!convert_to_custom_float_format(
544 rgb->blue,
545 &fmt,
546 &rgb->blue_reg)) {
547 BREAK_TO_DEBUGGER();
548 return false;
549 }
550
551 if (!convert_to_custom_float_format(
552 rgb->delta_red,
553 &fmt,
554 &rgb->delta_red_reg)) {
555 BREAK_TO_DEBUGGER();
556 return false;
557 }
558
559 if (!convert_to_custom_float_format(
560 rgb->delta_green,
561 &fmt,
562 &rgb->delta_green_reg)) {
563 BREAK_TO_DEBUGGER();
564 return false;
565 }
566
567 if (!convert_to_custom_float_format(
568 rgb->delta_blue,
569 &fmt,
570 &rgb->delta_blue_reg)) {
571 BREAK_TO_DEBUGGER();
572 return false;
573 }
574
575 ++rgb;
576 ++i;
577 }
578
579 return true;
580 }
581
582 bool dce110_translate_regamma_to_hw_format(const struct dc_transfer_func
583 *output_tf, struct pwl_params *regamma_params)
584 {
585 struct curve_points *arr_points;
586 struct pwl_result_data *rgb_resulted;
587 struct pwl_result_data *rgb;
588 struct pwl_result_data *rgb_plus_1;
589 struct fixed31_32 y_r;
590 struct fixed31_32 y_g;
591 struct fixed31_32 y_b;
592 struct fixed31_32 y1_min;
593 struct fixed31_32 y3_max;
594
595 int32_t segment_start, segment_end;
596 uint32_t i, j, k, seg_distr[16], increment, start_index, hw_points;
597
598 if (output_tf == NULL || regamma_params == NULL)
599 return false;
600
601 arr_points = regamma_params->arr_points;
602 rgb_resulted = regamma_params->rgb_resulted;
603 hw_points = 0;
604
605 memset(regamma_params, 0, sizeof(struct pwl_params));
606
607 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
608 /* 16 segments
609 * segments are from 2^-11 to 2^5
610 */
611 segment_start = -11;
612 segment_end = 5;
613
614 seg_distr[0] = 2;
615 seg_distr[1] = 2;
616 seg_distr[2] = 2;
617 seg_distr[3] = 2;
618 seg_distr[4] = 2;
619 seg_distr[5] = 2;
620 seg_distr[6] = 3;
621 seg_distr[7] = 4;
622 seg_distr[8] = 4;
623 seg_distr[9] = 4;
624 seg_distr[10] = 4;
625 seg_distr[11] = 5;
626 seg_distr[12] = 5;
627 seg_distr[13] = 5;
628 seg_distr[14] = 5;
629 seg_distr[15] = 5;
630
631 } else {
632 /* 10 segments
633 * segment is from 2^-10 to 2^0
634 */
635 segment_start = -10;
636 segment_end = 0;
637
638 seg_distr[0] = 3;
639 seg_distr[1] = 4;
640 seg_distr[2] = 4;
641 seg_distr[3] = 4;
642 seg_distr[4] = 4;
643 seg_distr[5] = 4;
644 seg_distr[6] = 4;
645 seg_distr[7] = 4;
646 seg_distr[8] = 5;
647 seg_distr[9] = 5;
648 seg_distr[10] = -1;
649 seg_distr[11] = -1;
650 seg_distr[12] = -1;
651 seg_distr[13] = -1;
652 seg_distr[14] = -1;
653 seg_distr[15] = -1;
654 }
655
656 for (k = 0; k < 16; k++) {
657 if (seg_distr[k] != -1)
658 hw_points += (1 << seg_distr[k]);
659 }
660
661 j = 0;
662 for (k = 0; k < (segment_end - segment_start); k++) {
663 increment = 32 / (1 << seg_distr[k]);
664 start_index = (segment_start + k + 25) * 32;
665 for (i = start_index; i < start_index + 32; i += increment) {
666 if (j == hw_points - 1)
667 break;
668 rgb_resulted[j].red = output_tf->tf_pts.red[i];
669 rgb_resulted[j].green = output_tf->tf_pts.green[i];
670 rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
671 j++;
672 }
673 }
674
675 /* last point */
676 start_index = (segment_end + 25) * 32;
677 rgb_resulted[hw_points - 1].red =
678 output_tf->tf_pts.red[start_index];
679 rgb_resulted[hw_points - 1].green =
680 output_tf->tf_pts.green[start_index];
681 rgb_resulted[hw_points - 1].blue =
682 output_tf->tf_pts.blue[start_index];
683
684 arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
685 dal_fixed31_32_from_int(segment_start));
686 arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
687 dal_fixed31_32_from_int(segment_end));
688 arr_points[2].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
689 dal_fixed31_32_from_int(segment_end));
690
691 y_r = rgb_resulted[0].red;
692 y_g = rgb_resulted[0].green;
693 y_b = rgb_resulted[0].blue;
694
695 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
696
697 arr_points[0].y = y1_min;
698 arr_points[0].slope = dal_fixed31_32_div(
699 arr_points[0].y,
700 arr_points[0].x);
701
702 y_r = rgb_resulted[hw_points - 1].red;
703 y_g = rgb_resulted[hw_points - 1].green;
704 y_b = rgb_resulted[hw_points - 1].blue;
705
706 /* see comment above, m_arrPoints[1].y should be the Y value for the
707 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
708 */
709 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
710
711 arr_points[1].y = y3_max;
712 arr_points[2].y = y3_max;
713
714 arr_points[1].slope = dal_fixed31_32_zero;
715 arr_points[2].slope = dal_fixed31_32_zero;
716
717 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
718 /* for PQ, we want to have a straight line from last HW X point,
719 * and the slope to be such that we hit 1.0 at 10000 nits.
720 */
721 const struct fixed31_32 end_value =
722 dal_fixed31_32_from_int(125);
723
724 arr_points[1].slope = dal_fixed31_32_div(
725 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
726 dal_fixed31_32_sub(end_value, arr_points[1].x));
727 arr_points[2].slope = dal_fixed31_32_div(
728 dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y),
729 dal_fixed31_32_sub(end_value, arr_points[1].x));
730 }
731
732 regamma_params->hw_points_num = hw_points;
733
734 i = 1;
735 for (k = 0; k < 16 && i < 16; k++) {
736 if (seg_distr[k] != -1) {
737 regamma_params->arr_curve_points[k].segments_num =
738 seg_distr[k];
739 regamma_params->arr_curve_points[i].offset =
740 regamma_params->arr_curve_points[k].
741 offset + (1 << seg_distr[k]);
742 }
743 i++;
744 }
745
746 if (seg_distr[k] != -1)
747 regamma_params->arr_curve_points[k].segments_num =
748 seg_distr[k];
749
750 rgb = rgb_resulted;
751 rgb_plus_1 = rgb_resulted + 1;
752
753 i = 1;
754
755 while (i != hw_points + 1) {
756 if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red))
757 rgb_plus_1->red = rgb->red;
758 if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green))
759 rgb_plus_1->green = rgb->green;
760 if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue))
761 rgb_plus_1->blue = rgb->blue;
762
763 rgb->delta_red = dal_fixed31_32_sub(
764 rgb_plus_1->red,
765 rgb->red);
766 rgb->delta_green = dal_fixed31_32_sub(
767 rgb_plus_1->green,
768 rgb->green);
769 rgb->delta_blue = dal_fixed31_32_sub(
770 rgb_plus_1->blue,
771 rgb->blue);
772
773 ++rgb_plus_1;
774 ++rgb;
775 ++i;
776 }
777
778 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
779
780 return true;
781 }
782
783 static bool dce110_set_output_transfer_func(
784 struct pipe_ctx *pipe_ctx,
785 const struct core_surface *surface, /* Surface - To be removed */
786 const struct core_stream *stream)
787 {
788 struct output_pixel_processor *opp = pipe_ctx->opp;
789
790 opp->funcs->opp_power_on_regamma_lut(opp, true);
791 opp->regamma_params->hw_points_num = GAMMA_HW_POINTS_NUM;
792
793 if (stream->public.out_transfer_func &&
794 stream->public.out_transfer_func->type ==
795 TF_TYPE_PREDEFINED &&
796 stream->public.out_transfer_func->tf ==
797 TRANSFER_FUNCTION_SRGB) {
798 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB);
799 } else if (dce110_translate_regamma_to_hw_format(
800 stream->public.out_transfer_func, opp->regamma_params)) {
801 opp->funcs->opp_program_regamma_pwl(opp, opp->regamma_params);
802 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER);
803 } else {
804 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_BYPASS);
805 }
806
807 opp->funcs->opp_power_on_regamma_lut(opp, false);
808
809 return true;
810 }
811
812 static enum dc_status bios_parser_crtc_source_select(
813 struct pipe_ctx *pipe_ctx)
814 {
815 struct dc_bios *dcb;
816 /* call VBIOS table to set CRTC source for the HW
817 * encoder block
818 * note: video bios clears all FMT setting here. */
819 struct bp_crtc_source_select crtc_source_select = {0};
820 const struct core_sink *sink = pipe_ctx->stream->sink;
821
822 crtc_source_select.engine_id = pipe_ctx->stream_enc->id;
823 crtc_source_select.controller_id = pipe_ctx->pipe_idx + 1;
824 /*TODO: Need to un-hardcode color depth, dp_audio and account for
825 * the case where signal and sink signal is different (translator
826 * encoder)*/
827 crtc_source_select.signal = pipe_ctx->stream->signal;
828 crtc_source_select.enable_dp_audio = false;
829 crtc_source_select.sink_signal = pipe_ctx->stream->signal;
830 crtc_source_select.display_output_bit_depth = PANEL_8BIT_COLOR;
831
832 dcb = sink->ctx->dc_bios;
833
834 if (BP_RESULT_OK != dcb->funcs->crtc_source_select(
835 dcb,
836 &crtc_source_select)) {
837 return DC_ERROR_UNEXPECTED;
838 }
839
840 return DC_OK;
841 }
842
843 void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
844 {
845 ASSERT(pipe_ctx->stream);
846
847 if (pipe_ctx->stream_enc == NULL)
848 return; /* this is not root pipe */
849
850 if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
851 pipe_ctx->stream_enc->funcs->update_hdmi_info_packets(
852 pipe_ctx->stream_enc,
853 &pipe_ctx->encoder_info_frame);
854 else if (dc_is_dp_signal(pipe_ctx->stream->signal))
855 pipe_ctx->stream_enc->funcs->update_dp_info_packets(
856 pipe_ctx->stream_enc,
857 &pipe_ctx->encoder_info_frame);
858 }
859
860 void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
861 {
862 enum dc_lane_count lane_count =
863 pipe_ctx->stream->sink->link->public.cur_link_settings.lane_count;
864
865 struct dc_crtc_timing *timing = &pipe_ctx->stream->public.timing;
866 struct core_link *link = pipe_ctx->stream->sink->link;
867
868 /* 1. update AVI info frame (HDMI, DP)
869 * we always need to update info frame
870 */
871 uint32_t active_total_with_borders;
872 uint32_t early_control = 0;
873 struct timing_generator *tg = pipe_ctx->tg;
874
875 /* TODOFPGA may change to hwss.update_info_frame */
876 dce110_update_info_frame(pipe_ctx);
877 /* enable early control to avoid corruption on DP monitor*/
878 active_total_with_borders =
879 timing->h_addressable
880 + timing->h_border_left
881 + timing->h_border_right;
882
883 if (lane_count != 0)
884 early_control = active_total_with_borders % lane_count;
885
886 if (early_control == 0)
887 early_control = lane_count;
888
889 tg->funcs->set_early_control(tg, early_control);
890
891 /* enable audio only within mode set */
892 if (pipe_ctx->audio != NULL) {
893 if (dc_is_dp_signal(pipe_ctx->stream->signal))
894 pipe_ctx->stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_enc);
895 }
896
897 /* For MST, there are multiply stream go to only one link.
898 * connect DIG back_end to front_end while enable_stream and
899 * disconnect them during disable_stream
900 * BY this, it is logic clean to separate stream and link */
901 link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
902 pipe_ctx->stream_enc->id, true);
903
904 }
905
906 void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
907 {
908 struct core_stream *stream = pipe_ctx->stream;
909 struct core_link *link = stream->sink->link;
910
911 if (pipe_ctx->audio) {
912 pipe_ctx->audio->funcs->az_disable(pipe_ctx->audio);
913
914 if (dc_is_dp_signal(pipe_ctx->stream->signal))
915 pipe_ctx->stream_enc->funcs->dp_audio_disable(
916 pipe_ctx->stream_enc);
917 else
918 pipe_ctx->stream_enc->funcs->hdmi_audio_disable(
919 pipe_ctx->stream_enc);
920
921 pipe_ctx->audio = NULL;
922
923 /* TODO: notify audio driver for if audio modes list changed
924 * add audio mode list change flag */
925 /* dal_audio_disable_azalia_audio_jack_presence(stream->audio,
926 * stream->stream_engine_id);
927 */
928 }
929
930 if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
931 pipe_ctx->stream_enc->funcs->stop_hdmi_info_packets(
932 pipe_ctx->stream_enc);
933
934 if (dc_is_dp_signal(pipe_ctx->stream->signal))
935 pipe_ctx->stream_enc->funcs->stop_dp_info_packets(
936 pipe_ctx->stream_enc);
937
938 pipe_ctx->stream_enc->funcs->audio_mute_control(
939 pipe_ctx->stream_enc, true);
940
941
942 /* blank at encoder level */
943 if (dc_is_dp_signal(pipe_ctx->stream->signal))
944 pipe_ctx->stream_enc->funcs->dp_blank(pipe_ctx->stream_enc);
945
946 link->link_enc->funcs->connect_dig_be_to_fe(
947 link->link_enc,
948 pipe_ctx->stream_enc->id,
949 false);
950
951 }
952
953 void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
954 struct dc_link_settings *link_settings)
955 {
956 struct encoder_unblank_param params = { { 0 } };
957
958 /* only 3 items below are used by unblank */
959 params.pixel_clk_khz =
960 pipe_ctx->stream->public.timing.pix_clk_khz;
961 params.link_settings.link_rate = link_settings->link_rate;
962 pipe_ctx->stream_enc->funcs->dp_unblank(pipe_ctx->stream_enc, &params);
963 }
964
965 static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
966 {
967 switch (crtc_id) {
968 case CONTROLLER_ID_D0:
969 return DTO_SOURCE_ID0;
970 case CONTROLLER_ID_D1:
971 return DTO_SOURCE_ID1;
972 case CONTROLLER_ID_D2:
973 return DTO_SOURCE_ID2;
974 case CONTROLLER_ID_D3:
975 return DTO_SOURCE_ID3;
976 case CONTROLLER_ID_D4:
977 return DTO_SOURCE_ID4;
978 case CONTROLLER_ID_D5:
979 return DTO_SOURCE_ID5;
980 default:
981 return DTO_SOURCE_UNKNOWN;
982 }
983 }
984
985 static void build_audio_output(
986 const struct pipe_ctx *pipe_ctx,
987 struct audio_output *audio_output)
988 {
989 const struct core_stream *stream = pipe_ctx->stream;
990 audio_output->engine_id = pipe_ctx->stream_enc->id;
991
992 audio_output->signal = pipe_ctx->stream->signal;
993
994 /* audio_crtc_info */
995
996 audio_output->crtc_info.h_total =
997 stream->public.timing.h_total;
998
999 /*
1000 * Audio packets are sent during actual CRTC blank physical signal, we
1001 * need to specify actual active signal portion
1002 */
1003 audio_output->crtc_info.h_active =
1004 stream->public.timing.h_addressable
1005 + stream->public.timing.h_border_left
1006 + stream->public.timing.h_border_right;
1007
1008 audio_output->crtc_info.v_active =
1009 stream->public.timing.v_addressable
1010 + stream->public.timing.v_border_top
1011 + stream->public.timing.v_border_bottom;
1012
1013 audio_output->crtc_info.pixel_repetition = 1;
1014
1015 audio_output->crtc_info.interlaced =
1016 stream->public.timing.flags.INTERLACE;
1017
1018 audio_output->crtc_info.refresh_rate =
1019 (stream->public.timing.pix_clk_khz*1000)/
1020 (stream->public.timing.h_total*stream->public.timing.v_total);
1021
1022 audio_output->crtc_info.color_depth =
1023 stream->public.timing.display_color_depth;
1024
1025 audio_output->crtc_info.requested_pixel_clock =
1026 pipe_ctx->pix_clk_params.requested_pix_clk;
1027
1028 /*
1029 * TODO - Investigate why calculated pixel clk has to be
1030 * requested pixel clk
1031 */
1032 audio_output->crtc_info.calculated_pixel_clock =
1033 pipe_ctx->pix_clk_params.requested_pix_clk;
1034
1035 if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
1036 pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
1037 audio_output->pll_info.dp_dto_source_clock_in_khz =
1038 pipe_ctx->dis_clk->funcs->get_dp_ref_clk_frequency(
1039 pipe_ctx->dis_clk);
1040 }
1041
1042 audio_output->pll_info.feed_back_divider =
1043 pipe_ctx->pll_settings.feedback_divider;
1044
1045 audio_output->pll_info.dto_source =
1046 translate_to_dto_source(
1047 pipe_ctx->pipe_idx + 1);
1048
1049 /* TODO hard code to enable for now. Need get from stream */
1050 audio_output->pll_info.ss_enabled = true;
1051
1052 audio_output->pll_info.ss_percentage =
1053 pipe_ctx->pll_settings.ss_percentage;
1054 }
1055
1056 static void get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx,
1057 struct tg_color *color)
1058 {
1059 uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->pipe_idx) / 4;
1060
1061 switch (pipe_ctx->scl_data.format) {
1062 case PIXEL_FORMAT_ARGB8888:
1063 /* set boarder color to red */
1064 color->color_r_cr = color_value;
1065 break;
1066
1067 case PIXEL_FORMAT_ARGB2101010:
1068 /* set boarder color to blue */
1069 color->color_b_cb = color_value;
1070 break;
1071 case PIXEL_FORMAT_420BPP12:
1072 /* set boarder color to green */
1073 color->color_g_y = color_value;
1074 break;
1075 case PIXEL_FORMAT_FP16:
1076 /* set boarder color to white */
1077 color->color_r_cr = color_value;
1078 color->color_b_cb = color_value;
1079 color->color_g_y = color_value;
1080 break;
1081 default:
1082 break;
1083 }
1084 }
1085
1086 static void program_scaler(const struct core_dc *dc,
1087 const struct pipe_ctx *pipe_ctx)
1088 {
1089 struct tg_color color = {0};
1090
1091 if (dc->public.debug.surface_visual_confirm)
1092 get_surface_visual_confirm_color(pipe_ctx, &color);
1093 else
1094 color_space_to_black_color(dc,
1095 pipe_ctx->stream->public.output_color_space,
1096 &color);
1097
1098 pipe_ctx->xfm->funcs->transform_set_pixel_storage_depth(
1099 pipe_ctx->xfm,
1100 pipe_ctx->scl_data.lb_params.depth,
1101 &pipe_ctx->stream->bit_depth_params);
1102
1103 if (pipe_ctx->tg->funcs->set_overscan_blank_color)
1104 pipe_ctx->tg->funcs->set_overscan_blank_color(
1105 pipe_ctx->tg,
1106 &color);
1107
1108 pipe_ctx->xfm->funcs->transform_set_scaler(pipe_ctx->xfm,
1109 &pipe_ctx->scl_data);
1110 }
1111
1112 static enum dc_status dce110_prog_pixclk_crtc_otg(
1113 struct pipe_ctx *pipe_ctx,
1114 struct validate_context *context,
1115 struct core_dc *dc)
1116 {
1117 struct core_stream *stream = pipe_ctx->stream;
1118 struct pipe_ctx *pipe_ctx_old = &dc->current_context->res_ctx.
1119 pipe_ctx[pipe_ctx->pipe_idx];
1120 struct tg_color black_color = {0};
1121
1122 if (!pipe_ctx_old->stream) {
1123
1124 /* program blank color */
1125 color_space_to_black_color(dc,
1126 stream->public.output_color_space, &black_color);
1127 pipe_ctx->tg->funcs->set_blank_color(
1128 pipe_ctx->tg,
1129 &black_color);
1130
1131 /*
1132 * Must blank CRTC after disabling power gating and before any
1133 * programming, otherwise CRTC will be hung in bad state
1134 */
1135 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
1136
1137 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
1138 pipe_ctx->clock_source,
1139 &pipe_ctx->pix_clk_params,
1140 &pipe_ctx->pll_settings)) {
1141 BREAK_TO_DEBUGGER();
1142 return DC_ERROR_UNEXPECTED;
1143 }
1144
1145 pipe_ctx->tg->funcs->program_timing(
1146 pipe_ctx->tg,
1147 &stream->public.timing,
1148 true);
1149 }
1150
1151 if (!pipe_ctx_old->stream) {
1152 if (false == pipe_ctx->tg->funcs->enable_crtc(
1153 pipe_ctx->tg)) {
1154 BREAK_TO_DEBUGGER();
1155 return DC_ERROR_UNEXPECTED;
1156 }
1157 }
1158
1159 return DC_OK;
1160 }
1161
1162 static enum dc_status apply_single_controller_ctx_to_hw(
1163 struct pipe_ctx *pipe_ctx,
1164 struct validate_context *context,
1165 struct core_dc *dc)
1166 {
1167 struct core_stream *stream = pipe_ctx->stream;
1168 struct pipe_ctx *pipe_ctx_old = &dc->current_context->res_ctx.
1169 pipe_ctx[pipe_ctx->pipe_idx];
1170
1171 /* */
1172 dc->hwss.prog_pixclk_crtc_otg(pipe_ctx, context, dc);
1173
1174 pipe_ctx->opp->funcs->opp_set_dyn_expansion(
1175 pipe_ctx->opp,
1176 COLOR_SPACE_YCBCR601,
1177 stream->public.timing.display_color_depth,
1178 pipe_ctx->stream->signal);
1179
1180 pipe_ctx->opp->funcs->opp_program_fmt(
1181 pipe_ctx->opp,
1182 &stream->bit_depth_params,
1183 &stream->clamping);
1184
1185 /* FPGA does not program backend */
1186 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
1187 return DC_OK;
1188
1189 /* TODO: move to stream encoder */
1190 if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL)
1191 if (DC_OK != bios_parser_crtc_source_select(pipe_ctx)) {
1192 BREAK_TO_DEBUGGER();
1193 return DC_ERROR_UNEXPECTED;
1194 }
1195
1196 if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL)
1197 stream->sink->link->link_enc->funcs->setup(
1198 stream->sink->link->link_enc,
1199 pipe_ctx->stream->signal);
1200
1201 if (dc_is_dp_signal(pipe_ctx->stream->signal))
1202 pipe_ctx->stream_enc->funcs->dp_set_stream_attribute(
1203 pipe_ctx->stream_enc,
1204 &stream->public.timing,
1205 stream->public.output_color_space);
1206
1207 if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
1208 pipe_ctx->stream_enc->funcs->hdmi_set_stream_attribute(
1209 pipe_ctx->stream_enc,
1210 &stream->public.timing,
1211 stream->phy_pix_clk,
1212 pipe_ctx->audio != NULL);
1213
1214 if (dc_is_dvi_signal(pipe_ctx->stream->signal))
1215 pipe_ctx->stream_enc->funcs->dvi_set_stream_attribute(
1216 pipe_ctx->stream_enc,
1217 &stream->public.timing,
1218 (pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
1219 true : false);
1220
1221 if (!pipe_ctx_old->stream) {
1222 core_link_enable_stream(pipe_ctx);
1223
1224 if (dc_is_dp_signal(pipe_ctx->stream->signal))
1225 dce110_unblank_stream(pipe_ctx,
1226 &stream->sink->link->public.cur_link_settings);
1227 }
1228
1229 pipe_ctx->scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
1230 /* program_scaler and allocate_mem_input are not new asic */
1231 if (!pipe_ctx_old || memcmp(&pipe_ctx_old->scl_data,
1232 &pipe_ctx->scl_data,
1233 sizeof(struct scaler_data)) != 0)
1234 program_scaler(dc, pipe_ctx);
1235
1236 /* mst support - use total stream count */
1237 pipe_ctx->mi->funcs->allocate_mem_input(
1238 pipe_ctx->mi,
1239 stream->public.timing.h_total,
1240 stream->public.timing.v_total,
1241 stream->public.timing.pix_clk_khz,
1242 context->stream_count);
1243
1244 return DC_OK;
1245 }
1246
1247 /******************************************************************************/
1248
1249 static void power_down_encoders(struct core_dc *dc)
1250 {
1251 int i;
1252
1253 for (i = 0; i < dc->link_count; i++) {
1254 dc->links[i]->link_enc->funcs->disable_output(
1255 dc->links[i]->link_enc, SIGNAL_TYPE_NONE);
1256 }
1257 }
1258
1259 static void power_down_controllers(struct core_dc *dc)
1260 {
1261 int i;
1262
1263 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1264 dc->res_pool->timing_generators[i]->funcs->disable_crtc(
1265 dc->res_pool->timing_generators[i]);
1266 }
1267 }
1268
1269 static void power_down_clock_sources(struct core_dc *dc)
1270 {
1271 int i;
1272
1273 if (dc->res_pool->dp_clock_source->funcs->cs_power_down(
1274 dc->res_pool->dp_clock_source) == false)
1275 dm_error("Failed to power down pll! (dp clk src)\n");
1276
1277 for (i = 0; i < dc->res_pool->clk_src_count; i++) {
1278 if (dc->res_pool->clock_sources[i]->funcs->cs_power_down(
1279 dc->res_pool->clock_sources[i]) == false)
1280 dm_error("Failed to power down pll! (clk src index=%d)\n", i);
1281 }
1282 }
1283
1284 static void power_down_all_hw_blocks(struct core_dc *dc)
1285 {
1286 power_down_encoders(dc);
1287
1288 power_down_controllers(dc);
1289
1290 power_down_clock_sources(dc);
1291 }
1292
1293 static void disable_vga_and_power_gate_all_controllers(
1294 struct core_dc *dc)
1295 {
1296 int i;
1297 struct timing_generator *tg;
1298 struct dc_context *ctx = dc->ctx;
1299
1300 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1301 tg = dc->res_pool->timing_generators[i];
1302
1303 tg->funcs->disable_vga(tg);
1304
1305 /* Enable CLOCK gating for each pipe BEFORE controller
1306 * powergating. */
1307 enable_display_pipe_clock_gating(ctx,
1308 true);
1309
1310 dc->hwss.power_down_front_end(
1311 dc, &dc->current_context->res_ctx.pipe_ctx[i]);
1312 }
1313 }
1314
1315 /**
1316 * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need:
1317 * 1. Power down all DC HW blocks
1318 * 2. Disable VGA engine on all controllers
1319 * 3. Enable power gating for controller
1320 * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS)
1321 */
1322 void dce110_enable_accelerated_mode(struct core_dc *dc)
1323 {
1324 power_down_all_hw_blocks(dc);
1325
1326 disable_vga_and_power_gate_all_controllers(dc);
1327 bios_set_scratch_acc_mode_change(dc->ctx->dc_bios);
1328 }
1329
1330 static uint32_t compute_pstate_blackout_duration(
1331 struct bw_fixed blackout_duration,
1332 const struct core_stream *stream)
1333 {
1334 uint32_t total_dest_line_time_ns;
1335 uint32_t pstate_blackout_duration_ns;
1336
1337 pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24;
1338
1339 total_dest_line_time_ns = 1000000UL *
1340 stream->public.timing.h_total /
1341 stream->public.timing.pix_clk_khz +
1342 pstate_blackout_duration_ns;
1343
1344 return total_dest_line_time_ns;
1345 }
1346
1347 /* get the index of the pipe_ctx if there were no gaps in the pipe_ctx array*/
1348 int get_bw_result_idx(
1349 struct resource_context *res_ctx,
1350 int pipe_idx)
1351 {
1352 int i, collapsed_idx;
1353
1354 if (res_ctx->pipe_ctx[pipe_idx].top_pipe)
1355 return 3;
1356
1357 collapsed_idx = 0;
1358 for (i = 0; i < pipe_idx; i++) {
1359 if (res_ctx->pipe_ctx[i].stream)
1360 collapsed_idx++;
1361 }
1362
1363 return collapsed_idx;
1364 }
1365
1366 static bool is_watermark_set_a_greater(
1367 const struct bw_watermarks *set_a,
1368 const struct bw_watermarks *set_b)
1369 {
1370 if (set_a->a_mark > set_b->a_mark
1371 || set_a->b_mark > set_b->b_mark
1372 || set_a->c_mark > set_b->c_mark
1373 || set_a->d_mark > set_b->d_mark)
1374 return true;
1375 return false;
1376 }
1377
1378 static bool did_watermarks_increase(
1379 struct pipe_ctx *pipe_ctx,
1380 struct validate_context *context,
1381 struct validate_context *old_context)
1382 {
1383 int collapsed_pipe_idx = get_bw_result_idx(&context->res_ctx,
1384 pipe_ctx->pipe_idx);
1385 int old_collapsed_pipe_idx = get_bw_result_idx(&old_context->res_ctx,
1386 pipe_ctx->pipe_idx);
1387 struct pipe_ctx *old_pipe_ctx = &old_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
1388
1389 if (!old_pipe_ctx->stream)
1390 return true;
1391
1392 if (is_watermark_set_a_greater(
1393 &context->bw_results.nbp_state_change_wm_ns[collapsed_pipe_idx],
1394 &old_context->bw_results.nbp_state_change_wm_ns[old_collapsed_pipe_idx]))
1395 return true;
1396 if (is_watermark_set_a_greater(
1397 &context->bw_results.stutter_exit_wm_ns[collapsed_pipe_idx],
1398 &old_context->bw_results.stutter_exit_wm_ns[old_collapsed_pipe_idx]))
1399 return true;
1400 if (is_watermark_set_a_greater(
1401 &context->bw_results.urgent_wm_ns[collapsed_pipe_idx],
1402 &old_context->bw_results.urgent_wm_ns[old_collapsed_pipe_idx]))
1403 return true;
1404
1405 return false;
1406 }
1407
1408 static void program_wm_for_pipe(struct core_dc *dc,
1409 struct pipe_ctx *pipe_ctx,
1410 struct validate_context *context)
1411 {
1412 int total_dest_line_time_ns = compute_pstate_blackout_duration(
1413 dc->bw_vbios.blackout_duration,
1414 pipe_ctx->stream);
1415 int bw_result_idx = get_bw_result_idx(&context->res_ctx,
1416 pipe_ctx->pipe_idx);
1417
1418 pipe_ctx->mi->funcs->mem_input_program_display_marks(
1419 pipe_ctx->mi,
1420 context->bw_results.nbp_state_change_wm_ns[bw_result_idx],
1421 context->bw_results.stutter_exit_wm_ns[bw_result_idx],
1422 context->bw_results.urgent_wm_ns[bw_result_idx],
1423 total_dest_line_time_ns);
1424
1425 if (pipe_ctx->top_pipe)
1426 pipe_ctx->mi->funcs->mem_input_program_chroma_display_marks(
1427 pipe_ctx->mi,
1428 context->bw_results.nbp_state_change_wm_ns[bw_result_idx + 1],
1429 context->bw_results.stutter_exit_wm_ns[bw_result_idx + 1],
1430 context->bw_results.urgent_wm_ns[bw_result_idx + 1],
1431 total_dest_line_time_ns);
1432 }
1433
1434 void dce110_set_displaymarks(
1435 const struct core_dc *dc,
1436 struct validate_context *context)
1437 {
1438 uint8_t i, num_pipes;
1439 unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
1440
1441 for (i = 0, num_pipes = 0; i < MAX_PIPES; i++) {
1442 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1443 uint32_t total_dest_line_time_ns;
1444
1445 if (pipe_ctx->stream == NULL)
1446 continue;
1447
1448 total_dest_line_time_ns = compute_pstate_blackout_duration(
1449 dc->bw_vbios.blackout_duration, pipe_ctx->stream);
1450 pipe_ctx->mi->funcs->mem_input_program_display_marks(
1451 pipe_ctx->mi,
1452 context->bw_results.nbp_state_change_wm_ns[num_pipes],
1453 context->bw_results.stutter_exit_wm_ns[num_pipes],
1454 context->bw_results.urgent_wm_ns[num_pipes],
1455 total_dest_line_time_ns);
1456 if (i == underlay_idx) {
1457 num_pipes++;
1458 pipe_ctx->mi->funcs->mem_input_program_chroma_display_marks(
1459 pipe_ctx->mi,
1460 context->bw_results.nbp_state_change_wm_ns[num_pipes],
1461 context->bw_results.stutter_exit_wm_ns[num_pipes],
1462 context->bw_results.urgent_wm_ns[num_pipes],
1463 total_dest_line_time_ns);
1464 }
1465 num_pipes++;
1466 }
1467 }
1468
1469 static void set_safe_displaymarks(struct resource_context *res_ctx)
1470 {
1471 int i;
1472 int underlay_idx = res_ctx->pool->underlay_pipe_index;
1473 struct bw_watermarks max_marks = {
1474 MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK };
1475 struct bw_watermarks nbp_marks = {
1476 SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK };
1477
1478 for (i = 0; i < MAX_PIPES; i++) {
1479 if (res_ctx->pipe_ctx[i].stream == NULL)
1480 continue;
1481
1482 res_ctx->pipe_ctx[i].mi->funcs->mem_input_program_display_marks(
1483 res_ctx->pipe_ctx[i].mi,
1484 nbp_marks,
1485 max_marks,
1486 max_marks,
1487 MAX_WATERMARK);
1488 if (i == underlay_idx)
1489 res_ctx->pipe_ctx[i].mi->funcs->mem_input_program_chroma_display_marks(
1490 res_ctx->pipe_ctx[i].mi,
1491 nbp_marks,
1492 max_marks,
1493 max_marks,
1494 MAX_WATERMARK);
1495 }
1496 }
1497
1498 static void switch_dp_clock_sources(
1499 const struct core_dc *dc,
1500 struct resource_context *res_ctx)
1501 {
1502 uint8_t i;
1503 for (i = 0; i < MAX_PIPES; i++) {
1504 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
1505
1506 if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
1507 continue;
1508
1509 if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
1510 struct clock_source *clk_src =
1511 resource_find_used_clk_src_for_sharing(
1512 res_ctx, pipe_ctx);
1513
1514 if (clk_src &&
1515 clk_src != pipe_ctx->clock_source) {
1516 resource_unreference_clock_source(
1517 res_ctx, &pipe_ctx->clock_source);
1518 pipe_ctx->clock_source = clk_src;
1519 resource_reference_clock_source(res_ctx, clk_src);
1520
1521 dce_crtc_switch_to_clk_src(dc->hwseq, clk_src, i);
1522 }
1523 }
1524 }
1525 }
1526
1527 /*******************************************************************************
1528 * Public functions
1529 ******************************************************************************/
1530
1531 static void reset_single_pipe_hw_ctx(
1532 const struct core_dc *dc,
1533 struct pipe_ctx *pipe_ctx,
1534 struct validate_context *context)
1535 {
1536 core_link_disable_stream(pipe_ctx);
1537 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
1538 if (!hwss_wait_for_blank_complete(pipe_ctx->tg)) {
1539 dm_error("DC: failed to blank crtc!\n");
1540 BREAK_TO_DEBUGGER();
1541 }
1542 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
1543 pipe_ctx->mi->funcs->free_mem_input(
1544 pipe_ctx->mi, context->stream_count);
1545 resource_unreference_clock_source(
1546 &context->res_ctx, &pipe_ctx->clock_source);
1547
1548 dc->hwss.power_down_front_end((struct core_dc *)dc, pipe_ctx);
1549
1550 pipe_ctx->stream = NULL;
1551 }
1552
1553 static void set_drr(struct pipe_ctx **pipe_ctx,
1554 int num_pipes, int vmin, int vmax)
1555 {
1556 int i = 0;
1557 struct drr_params params = {0};
1558
1559 params.vertical_total_max = vmax;
1560 params.vertical_total_min = vmin;
1561
1562 /* TODO: If multiple pipes are to be supported, you need
1563 * some GSL stuff
1564 */
1565
1566 for (i = 0; i < num_pipes; i++) {
1567 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
1568 }
1569 }
1570
1571 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
1572 int num_pipes, int value)
1573 {
1574 unsigned int i;
1575
1576 for (i = 0; i < num_pipes; i++)
1577 pipe_ctx[i]->tg->funcs->
1578 set_static_screen_control(pipe_ctx[i]->tg, value);
1579 }
1580
1581 /* unit: in_khz before mode set, get pixel clock from context. ASIC register
1582 * may not be programmed yet.
1583 * TODO: after mode set, pre_mode_set = false,
1584 * may read PLL register to get pixel clock
1585 */
1586 static uint32_t get_max_pixel_clock_for_all_paths(
1587 struct core_dc *dc,
1588 struct validate_context *context,
1589 bool pre_mode_set)
1590 {
1591 uint32_t max_pix_clk = 0;
1592 int i;
1593
1594 if (!pre_mode_set) {
1595 /* TODO: read ASIC register to get pixel clock */
1596 ASSERT(0);
1597 }
1598
1599 for (i = 0; i < MAX_PIPES; i++) {
1600 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1601
1602 if (pipe_ctx->stream == NULL)
1603 continue;
1604
1605 /* do not check under lay */
1606 if (pipe_ctx->top_pipe)
1607 continue;
1608
1609 if (pipe_ctx->pix_clk_params.requested_pix_clk > max_pix_clk)
1610 max_pix_clk =
1611 pipe_ctx->pix_clk_params.requested_pix_clk;
1612 }
1613
1614 if (max_pix_clk == 0)
1615 ASSERT(0);
1616
1617 return max_pix_clk;
1618 }
1619
1620 /*
1621 * Find clock state based on clock requested. if clock value is 0, simply
1622 * set clock state as requested without finding clock state by clock value
1623 */
1624 static void apply_min_clocks(
1625 struct core_dc *dc,
1626 struct validate_context *context,
1627 enum dm_pp_clocks_state *clocks_state,
1628 bool pre_mode_set)
1629 {
1630 struct state_dependent_clocks req_clocks = {0};
1631 struct pipe_ctx *pipe_ctx;
1632 int i;
1633
1634 for (i = 0; i < MAX_PIPES; i++) {
1635 pipe_ctx = &context->res_ctx.pipe_ctx[i];
1636 if (pipe_ctx->dis_clk != NULL)
1637 break;
1638 }
1639
1640 if (!pre_mode_set) {
1641 /* set clock_state without verification */
1642 if (pipe_ctx->dis_clk->funcs->set_min_clocks_state) {
1643 pipe_ctx->dis_clk->funcs->set_min_clocks_state(
1644 pipe_ctx->dis_clk, *clocks_state);
1645 return;
1646 }
1647
1648 /* TODOFPGA */
1649 }
1650
1651 /* get the required state based on state dependent clocks:
1652 * display clock and pixel clock
1653 */
1654 req_clocks.display_clk_khz = context->dispclk_khz;
1655
1656 req_clocks.pixel_clk_khz = get_max_pixel_clock_for_all_paths(
1657 dc, context, true);
1658
1659 if (pipe_ctx->dis_clk->funcs->get_required_clocks_state) {
1660 *clocks_state = pipe_ctx->dis_clk->funcs->get_required_clocks_state(
1661 pipe_ctx->dis_clk, &req_clocks);
1662 pipe_ctx->dis_clk->funcs->set_min_clocks_state(
1663 pipe_ctx->dis_clk, *clocks_state);
1664 } else {
1665 }
1666 }
1667
1668 static enum dc_status apply_ctx_to_hw_fpga(
1669 struct core_dc *dc,
1670 struct validate_context *context)
1671 {
1672 enum dc_status status = DC_ERROR_UNEXPECTED;
1673 int i;
1674
1675 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
1676 struct pipe_ctx *pipe_ctx_old =
1677 &dc->current_context->res_ctx.pipe_ctx[i];
1678 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1679
1680 if (pipe_ctx->stream == NULL)
1681 continue;
1682
1683 if (pipe_ctx->stream == pipe_ctx_old->stream)
1684 continue;
1685
1686 status = apply_single_controller_ctx_to_hw(
1687 pipe_ctx,
1688 context,
1689 dc);
1690
1691 if (status != DC_OK)
1692 return status;
1693 }
1694
1695 return DC_OK;
1696 }
1697
1698 static void reset_hw_ctx_wrap(
1699 struct core_dc *dc,
1700 struct validate_context *context)
1701 {
1702 int i;
1703
1704 /* Reset old context */
1705 /* look up the targets that have been removed since last commit */
1706 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
1707 struct pipe_ctx *pipe_ctx_old =
1708 &dc->current_context->res_ctx.pipe_ctx[i];
1709 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1710
1711 /* Note: We need to disable output if clock sources change,
1712 * since bios does optimization and doesn't apply if changing
1713 * PHY when not already disabled.
1714 */
1715
1716 /* Skip underlay pipe since it will be handled in commit surface*/
1717 if (!pipe_ctx_old->stream || pipe_ctx_old->top_pipe)
1718 continue;
1719
1720 if (!pipe_ctx->stream ||
1721 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
1722 reset_single_pipe_hw_ctx(
1723 dc, pipe_ctx_old, dc->current_context);
1724 }
1725 }
1726
1727 /*TODO: const validate_context*/
1728 enum dc_status dce110_apply_ctx_to_hw(
1729 struct core_dc *dc,
1730 struct validate_context *context)
1731 {
1732 struct dc_bios *dcb = dc->ctx->dc_bios;
1733 enum dc_status status;
1734 int i;
1735 enum dm_pp_clocks_state clocks_state = DM_PP_CLOCKS_STATE_INVALID;
1736
1737 /* Reset old context */
1738 /* look up the targets that have been removed since last commit */
1739 dc->hwss.reset_hw_ctx_wrap(dc, context);
1740
1741 /* Skip applying if no targets */
1742 if (context->stream_count <= 0)
1743 return DC_OK;
1744
1745 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
1746 apply_ctx_to_hw_fpga(dc, context);
1747 return DC_OK;
1748 }
1749
1750 /* Apply new context */
1751 dcb->funcs->set_scratch_critical_state(dcb, true);
1752
1753 /* below is for real asic only */
1754 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
1755 struct pipe_ctx *pipe_ctx_old =
1756 &dc->current_context->res_ctx.pipe_ctx[i];
1757 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1758
1759 if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
1760 continue;
1761
1762 if (pipe_ctx->stream == pipe_ctx_old->stream) {
1763 if (pipe_ctx_old->clock_source != pipe_ctx->clock_source)
1764 dce_crtc_switch_to_clk_src(dc->hwseq,
1765 pipe_ctx->clock_source, i);
1766 continue;
1767 }
1768
1769 dc->hwss.enable_display_power_gating(
1770 dc, i, dc->ctx->dc_bios,
1771 PIPE_GATING_CONTROL_DISABLE);
1772 }
1773
1774 set_safe_displaymarks(&context->res_ctx);
1775 /*TODO: when pplib works*/
1776 apply_min_clocks(dc, context, &clocks_state, true);
1777
1778 if (context->dispclk_khz
1779 > dc->current_context->dispclk_khz)
1780 context->res_ctx.pool->display_clock->funcs->set_clock(
1781 context->res_ctx.pool->display_clock,
1782 context->dispclk_khz * 115 / 100);
1783
1784 /* program audio wall clock. use HDMI as clock source if HDMI
1785 * audio active. Otherwise, use DP as clock source
1786 * first, loop to find any HDMI audio, if not, loop find DP audio
1787 */
1788 /* Setup audio rate clock source */
1789 /* Issue:
1790 * Audio lag happened on DP monitor when unplug a HDMI monitor
1791 *
1792 * Cause:
1793 * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL
1794 * is set to either dto0 or dto1, audio should work fine.
1795 * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1,
1796 * set to dto0 will cause audio lag.
1797 *
1798 * Solution:
1799 * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx,
1800 * find first available pipe with audio, setup audio wall DTO per topology
1801 * instead of per pipe.
1802 */
1803 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
1804 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1805
1806 if (pipe_ctx->stream == NULL)
1807 continue;
1808
1809 if (pipe_ctx->top_pipe)
1810 continue;
1811
1812 if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A)
1813 continue;
1814
1815 if (pipe_ctx->audio != NULL) {
1816 struct audio_output audio_output;
1817
1818 build_audio_output(pipe_ctx, &audio_output);
1819
1820 pipe_ctx->audio->funcs->wall_dto_setup(
1821 pipe_ctx->audio,
1822 pipe_ctx->stream->signal,
1823 &audio_output.crtc_info,
1824 &audio_output.pll_info);
1825 break;
1826 }
1827 }
1828
1829 /* no HDMI audio is found, try DP audio */
1830 if (i == context->res_ctx.pool->pipe_count) {
1831 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
1832 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1833
1834 if (pipe_ctx->stream == NULL)
1835 continue;
1836
1837 if (pipe_ctx->top_pipe)
1838 continue;
1839
1840 if (!dc_is_dp_signal(pipe_ctx->stream->signal))
1841 continue;
1842
1843 if (pipe_ctx->audio != NULL) {
1844 struct audio_output audio_output;
1845
1846 build_audio_output(pipe_ctx, &audio_output);
1847
1848 pipe_ctx->audio->funcs->wall_dto_setup(
1849 pipe_ctx->audio,
1850 pipe_ctx->stream->signal,
1851 &audio_output.crtc_info,
1852 &audio_output.pll_info);
1853 break;
1854 }
1855 }
1856 }
1857
1858 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
1859 struct pipe_ctx *pipe_ctx_old =
1860 &dc->current_context->res_ctx.pipe_ctx[i];
1861 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1862
1863 if (pipe_ctx->stream == NULL)
1864 continue;
1865
1866 if (pipe_ctx->stream == pipe_ctx_old->stream)
1867 continue;
1868
1869 if (pipe_ctx->top_pipe)
1870 continue;
1871
1872 if (context->res_ctx.pipe_ctx[i].audio != NULL) {
1873
1874 struct audio_output audio_output;
1875
1876 build_audio_output(pipe_ctx, &audio_output);
1877
1878 if (dc_is_dp_signal(pipe_ctx->stream->signal))
1879 pipe_ctx->stream_enc->funcs->dp_audio_setup(
1880 pipe_ctx->stream_enc,
1881 pipe_ctx->audio->inst,
1882 &pipe_ctx->stream->public.audio_info);
1883 else
1884 pipe_ctx->stream_enc->funcs->hdmi_audio_setup(
1885 pipe_ctx->stream_enc,
1886 pipe_ctx->audio->inst,
1887 &pipe_ctx->stream->public.audio_info,
1888 &audio_output.crtc_info);
1889
1890 pipe_ctx->audio->funcs->az_configure(
1891 pipe_ctx->audio,
1892 pipe_ctx->stream->signal,
1893 &audio_output.crtc_info,
1894 &pipe_ctx->stream->public.audio_info);
1895 }
1896
1897 status = apply_single_controller_ctx_to_hw(
1898 pipe_ctx,
1899 context,
1900 dc);
1901
1902 if (DC_OK != status)
1903 return status;
1904 }
1905
1906 dc->hwss.set_displaymarks(dc, context);
1907
1908 /* to save power */
1909 apply_min_clocks(dc, context, &clocks_state, false);
1910
1911 dcb->funcs->set_scratch_critical_state(dcb, false);
1912
1913 switch_dp_clock_sources(dc, &context->res_ctx);
1914
1915 return DC_OK;
1916 }
1917
1918 /*******************************************************************************
1919 * Front End programming
1920 ******************************************************************************/
1921 static void set_default_colors(struct pipe_ctx *pipe_ctx)
1922 {
1923 struct default_adjustment default_adjust = { 0 };
1924
1925 default_adjust.force_hw_default = false;
1926 if (pipe_ctx->surface == NULL)
1927 default_adjust.in_color_space = COLOR_SPACE_SRGB;
1928 else
1929 default_adjust.in_color_space =
1930 pipe_ctx->surface->public.color_space;
1931 if (pipe_ctx->stream == NULL)
1932 default_adjust.out_color_space = COLOR_SPACE_SRGB;
1933 else
1934 default_adjust.out_color_space =
1935 pipe_ctx->stream->public.output_color_space;
1936 default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW;
1937 default_adjust.surface_pixel_format = pipe_ctx->scl_data.format;
1938
1939 /* display color depth */
1940 default_adjust.color_depth =
1941 pipe_ctx->stream->public.timing.display_color_depth;
1942
1943 /* Lb color depth */
1944 default_adjust.lb_color_depth = pipe_ctx->scl_data.lb_params.depth;
1945
1946 pipe_ctx->opp->funcs->opp_set_csc_default(
1947 pipe_ctx->opp, &default_adjust);
1948 }
1949
1950
1951 /*******************************************************************************
1952 * In order to turn on/off specific surface we will program
1953 * Blender + CRTC
1954 *
1955 * In case that we have two surfaces and they have a different visibility
1956 * we can't turn off the CRTC since it will turn off the entire display
1957 *
1958 * |----------------------------------------------- |
1959 * |bottom pipe|curr pipe | | |
1960 * |Surface |Surface | Blender | CRCT |
1961 * |visibility |visibility | Configuration| |
1962 * |------------------------------------------------|
1963 * | off | off | CURRENT_PIPE | blank |
1964 * | off | on | CURRENT_PIPE | unblank |
1965 * | on | off | OTHER_PIPE | unblank |
1966 * | on | on | BLENDING | unblank |
1967 * -------------------------------------------------|
1968 *
1969 ******************************************************************************/
1970 static void program_surface_visibility(const struct core_dc *dc,
1971 struct pipe_ctx *pipe_ctx)
1972 {
1973 enum blnd_mode blender_mode = BLND_MODE_CURRENT_PIPE;
1974 bool blank_target = false;
1975
1976 if (pipe_ctx->bottom_pipe) {
1977
1978 /* For now we are supporting only two pipes */
1979 ASSERT(pipe_ctx->bottom_pipe->bottom_pipe == NULL);
1980
1981 if (pipe_ctx->bottom_pipe->surface->public.visible) {
1982 if (pipe_ctx->surface->public.visible)
1983 blender_mode = BLND_MODE_BLENDING;
1984 else
1985 blender_mode = BLND_MODE_OTHER_PIPE;
1986
1987 } else if (!pipe_ctx->surface->public.visible)
1988 blank_target = true;
1989
1990 } else if (!pipe_ctx->surface->public.visible)
1991 blank_target = true;
1992
1993 dce_set_blender_mode(dc->hwseq, pipe_ctx->pipe_idx, blender_mode);
1994 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, blank_target);
1995
1996 }
1997
1998 /**
1999 * TODO REMOVE, USE UPDATE INSTEAD
2000 */
2001 static void set_plane_config(
2002 const struct core_dc *dc,
2003 struct pipe_ctx *pipe_ctx,
2004 struct resource_context *res_ctx)
2005 {
2006 struct mem_input *mi = pipe_ctx->mi;
2007 struct core_surface *surface = pipe_ctx->surface;
2008 struct xfm_grph_csc_adjustment adjust;
2009 struct out_csc_color_matrix tbl_entry;
2010 unsigned int i;
2011
2012 memset(&adjust, 0, sizeof(adjust));
2013 memset(&tbl_entry, 0, sizeof(tbl_entry));
2014 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
2015
2016 dce_enable_fe_clock(dc->hwseq, pipe_ctx->pipe_idx, true);
2017
2018 set_default_colors(pipe_ctx);
2019 if (pipe_ctx->stream->public.csc_color_matrix.enable_adjustment
2020 == true) {
2021 tbl_entry.color_space =
2022 pipe_ctx->stream->public.output_color_space;
2023
2024 for (i = 0; i < 12; i++)
2025 tbl_entry.regval[i] =
2026 pipe_ctx->stream->public.csc_color_matrix.matrix[i];
2027
2028 pipe_ctx->opp->funcs->opp_set_csc_adjustment
2029 (pipe_ctx->opp, &tbl_entry);
2030 }
2031
2032 if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
2033 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
2034 adjust.temperature_matrix[0] =
2035 pipe_ctx->stream->
2036 public.gamut_remap_matrix.matrix[0];
2037 adjust.temperature_matrix[1] =
2038 pipe_ctx->stream->
2039 public.gamut_remap_matrix.matrix[1];
2040 adjust.temperature_matrix[2] =
2041 pipe_ctx->stream->
2042 public.gamut_remap_matrix.matrix[2];
2043 adjust.temperature_matrix[3] =
2044 pipe_ctx->stream->
2045 public.gamut_remap_matrix.matrix[4];
2046 adjust.temperature_matrix[4] =
2047 pipe_ctx->stream->
2048 public.gamut_remap_matrix.matrix[5];
2049 adjust.temperature_matrix[5] =
2050 pipe_ctx->stream->
2051 public.gamut_remap_matrix.matrix[6];
2052 adjust.temperature_matrix[6] =
2053 pipe_ctx->stream->
2054 public.gamut_remap_matrix.matrix[8];
2055 adjust.temperature_matrix[7] =
2056 pipe_ctx->stream->
2057 public.gamut_remap_matrix.matrix[9];
2058 adjust.temperature_matrix[8] =
2059 pipe_ctx->stream->
2060 public.gamut_remap_matrix.matrix[10];
2061 }
2062
2063 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
2064
2065 pipe_ctx->scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
2066 program_scaler(dc, pipe_ctx);
2067
2068 program_surface_visibility(dc, pipe_ctx);
2069
2070 mi->funcs->mem_input_program_surface_config(
2071 mi,
2072 surface->public.format,
2073 &surface->public.tiling_info,
2074 &surface->public.plane_size,
2075 surface->public.rotation,
2076 NULL,
2077 false,
2078 pipe_ctx->surface->public.visible);
2079
2080 if (dc->public.config.gpu_vm_support)
2081 mi->funcs->mem_input_program_pte_vm(
2082 pipe_ctx->mi,
2083 surface->public.format,
2084 &surface->public.tiling_info,
2085 surface->public.rotation);
2086 }
2087
2088 static void update_plane_addr(const struct core_dc *dc,
2089 struct pipe_ctx *pipe_ctx)
2090 {
2091 struct core_surface *surface = pipe_ctx->surface;
2092
2093 if (surface == NULL)
2094 return;
2095
2096 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
2097 pipe_ctx->mi,
2098 &surface->public.address,
2099 surface->public.flip_immediate);
2100
2101 surface->status.requested_address = surface->public.address;
2102 }
2103
2104 void dce110_update_pending_status(struct pipe_ctx *pipe_ctx)
2105 {
2106 struct core_surface *surface = pipe_ctx->surface;
2107
2108 if (surface == NULL)
2109 return;
2110
2111 surface->status.is_flip_pending =
2112 pipe_ctx->mi->funcs->mem_input_is_flip_pending(
2113 pipe_ctx->mi);
2114
2115 if (surface->status.is_flip_pending && !surface->public.visible)
2116 pipe_ctx->mi->current_address = pipe_ctx->mi->request_address;
2117
2118 surface->status.current_address = pipe_ctx->mi->current_address;
2119 }
2120
2121 void dce110_power_down(struct core_dc *dc)
2122 {
2123 power_down_all_hw_blocks(dc);
2124 disable_vga_and_power_gate_all_controllers(dc);
2125 }
2126
2127 static bool wait_for_reset_trigger_to_occur(
2128 struct dc_context *dc_ctx,
2129 struct timing_generator *tg)
2130 {
2131 bool rc = false;
2132
2133 /* To avoid endless loop we wait at most
2134 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
2135 const uint32_t frames_to_wait_on_triggered_reset = 10;
2136 uint32_t i;
2137
2138 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
2139
2140 if (!tg->funcs->is_counter_moving(tg)) {
2141 DC_ERROR("TG counter is not moving!\n");
2142 break;
2143 }
2144
2145 if (tg->funcs->did_triggered_reset_occur(tg)) {
2146 rc = true;
2147 /* usually occurs at i=1 */
2148 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
2149 i);
2150 break;
2151 }
2152
2153 /* Wait for one frame. */
2154 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
2155 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
2156 }
2157
2158 if (false == rc)
2159 DC_ERROR("GSL: Timeout on reset trigger!\n");
2160
2161 return rc;
2162 }
2163
2164 /* Enable timing synchronization for a group of Timing Generators. */
2165 static void dce110_enable_timing_synchronization(
2166 struct core_dc *dc,
2167 int group_index,
2168 int group_size,
2169 struct pipe_ctx *grouped_pipes[])
2170 {
2171 struct dc_context *dc_ctx = dc->ctx;
2172 struct dcp_gsl_params gsl_params = { 0 };
2173 int i;
2174
2175 DC_SYNC_INFO("GSL: Setting-up...\n");
2176
2177 /* Designate a single TG in the group as a master.
2178 * Since HW doesn't care which one, we always assign
2179 * the 1st one in the group. */
2180 gsl_params.gsl_group = 0;
2181 gsl_params.gsl_master = grouped_pipes[0]->tg->inst;
2182
2183 for (i = 0; i < group_size; i++)
2184 grouped_pipes[i]->tg->funcs->setup_global_swap_lock(
2185 grouped_pipes[i]->tg, &gsl_params);
2186
2187 /* Reset slave controllers on master VSync */
2188 DC_SYNC_INFO("GSL: enabling trigger-reset\n");
2189
2190 for (i = 1 /* skip the master */; i < group_size; i++)
2191 grouped_pipes[i]->tg->funcs->enable_reset_trigger(
2192 grouped_pipes[i]->tg, gsl_params.gsl_group);
2193
2194
2195
2196 for (i = 1 /* skip the master */; i < group_size; i++) {
2197 DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
2198 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->tg);
2199 /* Regardless of success of the wait above, remove the reset or
2200 * the driver will start timing out on Display requests. */
2201 DC_SYNC_INFO("GSL: disabling trigger-reset.\n");
2202 grouped_pipes[i]->tg->funcs->disable_reset_trigger(grouped_pipes[i]->tg);
2203 }
2204
2205
2206 /* GSL Vblank synchronization is a one time sync mechanism, assumption
2207 * is that the sync'ed displays will not drift out of sync over time*/
2208 DC_SYNC_INFO("GSL: Restoring register states.\n");
2209 for (i = 0; i < group_size; i++)
2210 grouped_pipes[i]->tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->tg);
2211
2212 DC_SYNC_INFO("GSL: Set-up complete.\n");
2213 }
2214
2215 static void init_hw(struct core_dc *dc)
2216 {
2217 int i;
2218 struct dc_bios *bp;
2219 struct transform *xfm;
2220 struct abm *abm;
2221
2222 bp = dc->ctx->dc_bios;
2223 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2224 xfm = dc->res_pool->transforms[i];
2225 xfm->funcs->transform_reset(xfm);
2226
2227 dc->hwss.enable_display_power_gating(
2228 dc, i, bp,
2229 PIPE_GATING_CONTROL_INIT);
2230 dc->hwss.enable_display_power_gating(
2231 dc, i, bp,
2232 PIPE_GATING_CONTROL_DISABLE);
2233 dc->hwss.enable_display_pipe_clock_gating(
2234 dc->ctx,
2235 true);
2236 }
2237
2238 dce_clock_gating_power_up(dc->hwseq, false);;
2239 /***************************************/
2240
2241 for (i = 0; i < dc->link_count; i++) {
2242 /****************************************/
2243 /* Power up AND update implementation according to the
2244 * required signal (which may be different from the
2245 * default signal on connector). */
2246 struct core_link *link = dc->links[i];
2247 link->link_enc->funcs->hw_init(link->link_enc);
2248 }
2249
2250 for (i = 0; i < dc->res_pool->pipe_count; i++) {
2251 struct timing_generator *tg = dc->res_pool->timing_generators[i];
2252
2253 tg->funcs->disable_vga(tg);
2254
2255 /* Blank controller using driver code instead of
2256 * command table. */
2257 tg->funcs->set_blank(tg, true);
2258 hwss_wait_for_blank_complete(tg);
2259 }
2260
2261 for (i = 0; i < dc->res_pool->audio_count; i++) {
2262 struct audio *audio = dc->res_pool->audios[i];
2263 audio->funcs->hw_init(audio);
2264 }
2265
2266 abm = dc->res_pool->abm;
2267 if (abm != NULL) {
2268 abm->funcs->init_backlight(abm);
2269 abm->funcs->abm_init(abm);
2270 }
2271 }
2272
2273 /* TODO: move this to apply_ctx_tohw some how?*/
2274 static void dce110_power_on_pipe_if_needed(
2275 struct core_dc *dc,
2276 struct pipe_ctx *pipe_ctx,
2277 struct validate_context *context)
2278 {
2279 struct pipe_ctx *old_pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
2280 struct dc_bios *dcb = dc->ctx->dc_bios;
2281 struct tg_color black_color = {0};
2282
2283 if (!old_pipe_ctx->stream && pipe_ctx->stream) {
2284 dc->hwss.enable_display_power_gating(
2285 dc,
2286 pipe_ctx->pipe_idx,
2287 dcb, PIPE_GATING_CONTROL_DISABLE);
2288
2289 /*
2290 * This is for powering on underlay, so crtc does not
2291 * need to be enabled
2292 */
2293
2294 pipe_ctx->tg->funcs->program_timing(pipe_ctx->tg,
2295 &pipe_ctx->stream->public.timing,
2296 false);
2297
2298 pipe_ctx->tg->funcs->enable_advanced_request(
2299 pipe_ctx->tg,
2300 true,
2301 &pipe_ctx->stream->public.timing);
2302
2303 pipe_ctx->mi->funcs->allocate_mem_input(pipe_ctx->mi,
2304 pipe_ctx->stream->public.timing.h_total,
2305 pipe_ctx->stream->public.timing.v_total,
2306 pipe_ctx->stream->public.timing.pix_clk_khz,
2307 context->stream_count);
2308
2309 /* TODO unhardcode*/
2310 color_space_to_black_color(dc,
2311 COLOR_SPACE_YCBCR601, &black_color);
2312 pipe_ctx->tg->funcs->set_blank_color(
2313 pipe_ctx->tg,
2314 &black_color);
2315 }
2316 }
2317
2318 static void dce110_increase_watermarks_for_pipe(
2319 struct core_dc *dc,
2320 struct pipe_ctx *pipe_ctx,
2321 struct validate_context *context)
2322 {
2323 if (did_watermarks_increase(pipe_ctx, context, dc->current_context))
2324 program_wm_for_pipe(dc, pipe_ctx, context);
2325 }
2326
2327 static void dce110_set_bandwidth(struct core_dc *dc)
2328 {
2329 int i;
2330
2331 for (i = 0; i < dc->current_context->res_ctx.pool->pipe_count; i++) {
2332 struct pipe_ctx *pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[i];
2333
2334 if (!pipe_ctx->stream)
2335 continue;
2336
2337 program_wm_for_pipe(dc, pipe_ctx, dc->current_context);
2338 }
2339
2340 dc->current_context->res_ctx.pool->display_clock->funcs->set_clock(
2341 dc->current_context->res_ctx.pool->display_clock,
2342 dc->current_context->dispclk_khz * 115 / 100);
2343 }
2344
2345 static void dce110_program_front_end_for_pipe(
2346 struct core_dc *dc, struct pipe_ctx *pipe_ctx)
2347 {
2348 struct mem_input *mi = pipe_ctx->mi;
2349 struct pipe_ctx *old_pipe = NULL;
2350 struct core_surface *surface = pipe_ctx->surface;
2351 struct xfm_grph_csc_adjustment adjust;
2352 struct out_csc_color_matrix tbl_entry;
2353 unsigned int i;
2354
2355 memset(&tbl_entry, 0, sizeof(tbl_entry));
2356
2357 if (dc->current_context)
2358 old_pipe = &dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
2359
2360 memset(&adjust, 0, sizeof(adjust));
2361 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
2362
2363 dce_enable_fe_clock(dc->hwseq, pipe_ctx->pipe_idx, true);
2364
2365 set_default_colors(pipe_ctx);
2366 if (pipe_ctx->stream->public.csc_color_matrix.enable_adjustment
2367 == true) {
2368 tbl_entry.color_space =
2369 pipe_ctx->stream->public.output_color_space;
2370
2371 for (i = 0; i < 12; i++)
2372 tbl_entry.regval[i] =
2373 pipe_ctx->stream->public.csc_color_matrix.matrix[i];
2374
2375 pipe_ctx->opp->funcs->opp_set_csc_adjustment
2376 (pipe_ctx->opp, &tbl_entry);
2377 }
2378
2379 if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
2380 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
2381 adjust.temperature_matrix[0] =
2382 pipe_ctx->stream->
2383 public.gamut_remap_matrix.matrix[0];
2384 adjust.temperature_matrix[1] =
2385 pipe_ctx->stream->
2386 public.gamut_remap_matrix.matrix[1];
2387 adjust.temperature_matrix[2] =
2388 pipe_ctx->stream->
2389 public.gamut_remap_matrix.matrix[2];
2390 adjust.temperature_matrix[3] =
2391 pipe_ctx->stream->
2392 public.gamut_remap_matrix.matrix[4];
2393 adjust.temperature_matrix[4] =
2394 pipe_ctx->stream->
2395 public.gamut_remap_matrix.matrix[5];
2396 adjust.temperature_matrix[5] =
2397 pipe_ctx->stream->
2398 public.gamut_remap_matrix.matrix[6];
2399 adjust.temperature_matrix[6] =
2400 pipe_ctx->stream->
2401 public.gamut_remap_matrix.matrix[8];
2402 adjust.temperature_matrix[7] =
2403 pipe_ctx->stream->
2404 public.gamut_remap_matrix.matrix[9];
2405 adjust.temperature_matrix[8] =
2406 pipe_ctx->stream->
2407 public.gamut_remap_matrix.matrix[10];
2408 }
2409
2410 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
2411
2412 pipe_ctx->scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
2413 if (old_pipe && memcmp(&old_pipe->scl_data,
2414 &pipe_ctx->scl_data,
2415 sizeof(struct scaler_data)) != 0)
2416 program_scaler(dc, pipe_ctx);
2417
2418 mi->funcs->mem_input_program_surface_config(
2419 mi,
2420 surface->public.format,
2421 &surface->public.tiling_info,
2422 &surface->public.plane_size,
2423 surface->public.rotation,
2424 NULL,
2425 false,
2426 pipe_ctx->surface->public.visible);
2427
2428 if (dc->public.config.gpu_vm_support)
2429 mi->funcs->mem_input_program_pte_vm(
2430 pipe_ctx->mi,
2431 surface->public.format,
2432 &surface->public.tiling_info,
2433 surface->public.rotation);
2434
2435 dm_logger_write(dc->ctx->logger, LOG_SURFACE,
2436 "Pipe:%d 0x%x: addr hi:0x%x, "
2437 "addr low:0x%x, "
2438 "src: %d, %d, %d,"
2439 " %d; dst: %d, %d, %d, %d;"
2440 "clip: %d, %d, %d, %d\n",
2441 pipe_ctx->pipe_idx,
2442 pipe_ctx->surface,
2443 pipe_ctx->surface->public.address.grph.addr.high_part,
2444 pipe_ctx->surface->public.address.grph.addr.low_part,
2445 pipe_ctx->surface->public.src_rect.x,
2446 pipe_ctx->surface->public.src_rect.y,
2447 pipe_ctx->surface->public.src_rect.width,
2448 pipe_ctx->surface->public.src_rect.height,
2449 pipe_ctx->surface->public.dst_rect.x,
2450 pipe_ctx->surface->public.dst_rect.y,
2451 pipe_ctx->surface->public.dst_rect.width,
2452 pipe_ctx->surface->public.dst_rect.height,
2453 pipe_ctx->surface->public.clip_rect.x,
2454 pipe_ctx->surface->public.clip_rect.y,
2455 pipe_ctx->surface->public.clip_rect.width,
2456 pipe_ctx->surface->public.clip_rect.height);
2457
2458 dm_logger_write(dc->ctx->logger, LOG_SURFACE,
2459 "Pipe %d: width, height, x, y\n"
2460 "viewport:%d, %d, %d, %d\n"
2461 "recout: %d, %d, %d, %d\n",
2462 pipe_ctx->pipe_idx,
2463 pipe_ctx->scl_data.viewport.width,
2464 pipe_ctx->scl_data.viewport.height,
2465 pipe_ctx->scl_data.viewport.x,
2466 pipe_ctx->scl_data.viewport.y,
2467 pipe_ctx->scl_data.recout.width,
2468 pipe_ctx->scl_data.recout.height,
2469 pipe_ctx->scl_data.recout.x,
2470 pipe_ctx->scl_data.recout.y);
2471 }
2472
2473 static void dce110_prepare_pipe_for_context(
2474 struct core_dc *dc,
2475 struct pipe_ctx *pipe_ctx,
2476 struct validate_context *context)
2477 {
2478 dce110_power_on_pipe_if_needed(dc, pipe_ctx, context);
2479 dc->hwss.increase_watermarks_for_pipe(dc, pipe_ctx, context);
2480 }
2481
2482 static void dce110_apply_ctx_for_surface(
2483 struct core_dc *dc,
2484 struct core_surface *surface,
2485 struct validate_context *context)
2486 {
2487 int i;
2488
2489 /* TODO remove when removing the surface reset workaroud*/
2490 if (!surface)
2491 return;
2492
2493 for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
2494 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2495
2496 if (pipe_ctx->surface != surface)
2497 continue;
2498
2499 dce110_program_front_end_for_pipe(dc, pipe_ctx);
2500 program_surface_visibility(dc, pipe_ctx);
2501
2502 }
2503 }
2504
2505 static void dce110_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
2506 {
2507 int i;
2508
2509 for (i = 0; i < dc->res_pool->pipe_count; i++)
2510 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe)
2511 break;
2512
2513 if (i == dc->res_pool->pipe_count)
2514 return;
2515
2516 dc->hwss.enable_display_power_gating(
2517 dc, i, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE);
2518 if (pipe->xfm)
2519 pipe->xfm->funcs->transform_reset(pipe->xfm);
2520 memset(&pipe->scl_data, 0, sizeof(struct scaler_data));
2521 }
2522
2523 static const struct hw_sequencer_funcs dce110_funcs = {
2524 .init_hw = init_hw,
2525 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
2526 .prepare_pipe_for_context = dce110_prepare_pipe_for_context,
2527 .apply_ctx_for_surface = dce110_apply_ctx_for_surface,
2528 .set_plane_config = set_plane_config,
2529 .update_plane_addr = update_plane_addr,
2530 .update_pending_status = dce110_update_pending_status,
2531 .set_input_transfer_func = dce110_set_input_transfer_func,
2532 .set_output_transfer_func = dce110_set_output_transfer_func,
2533 .power_down = dce110_power_down,
2534 .enable_accelerated_mode = dce110_enable_accelerated_mode,
2535 .enable_timing_synchronization = dce110_enable_timing_synchronization,
2536 .update_info_frame = dce110_update_info_frame,
2537 .enable_stream = dce110_enable_stream,
2538 .disable_stream = dce110_disable_stream,
2539 .unblank_stream = dce110_unblank_stream,
2540 .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating,
2541 .enable_display_power_gating = dce110_enable_display_power_gating,
2542 .power_down_front_end = dce110_power_down_fe,
2543 .pipe_control_lock = dce_pipe_control_lock,
2544 .set_displaymarks = dce110_set_displaymarks,
2545 .increase_watermarks_for_pipe = dce110_increase_watermarks_for_pipe,
2546 .set_bandwidth = dce110_set_bandwidth,
2547 .set_drr = set_drr,
2548 .set_static_screen_control = set_static_screen_control,
2549 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
2550 .prog_pixclk_crtc_otg = dce110_prog_pixclk_crtc_otg,
2551 };
2552
2553 bool dce110_hw_sequencer_construct(struct core_dc *dc)
2554 {
2555 dc->hwss = dce110_funcs;
2556
2557 return true;
2558 }
2559