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