Line data Source code
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 :
26 : #include "dm_services.h"
27 : #include "dc.h"
28 : #include "dc_bios_types.h"
29 : #include "core_types.h"
30 : #include "core_status.h"
31 : #include "resource.h"
32 : #include "dm_helpers.h"
33 : #include "dce110_timing_generator.h"
34 : #include "dce/dce_hwseq.h"
35 : #include "gpio_service_interface.h"
36 :
37 : #include "dce110_compressor.h"
38 :
39 : #include "bios/bios_parser_helper.h"
40 : #include "timing_generator.h"
41 : #include "mem_input.h"
42 : #include "opp.h"
43 : #include "ipp.h"
44 : #include "transform.h"
45 : #include "stream_encoder.h"
46 : #include "link_encoder.h"
47 : #include "link_enc_cfg.h"
48 : #include "link_hwss.h"
49 : #include "dc_link_dp.h"
50 : #include "dccg.h"
51 : #include "clock_source.h"
52 : #include "clk_mgr.h"
53 : #include "abm.h"
54 : #include "audio.h"
55 : #include "reg_helper.h"
56 : #include "panel_cntl.h"
57 : #include "inc/link_dpcd.h"
58 : #include "dpcd_defs.h"
59 : /* include DCE11 register header files */
60 : #include "dce/dce_11_0_d.h"
61 : #include "dce/dce_11_0_sh_mask.h"
62 : #include "custom_float.h"
63 :
64 : #include "atomfirmware.h"
65 :
66 : #include "dcn10/dcn10_hw_sequencer.h"
67 :
68 : #include "link/link_dp_trace.h"
69 : #include "dce110_hw_sequencer.h"
70 :
71 : #define GAMMA_HW_POINTS_NUM 256
72 :
73 : /*
74 : * All values are in milliseconds;
75 : * For eDP, after power-up/power/down,
76 : * 300/500 msec max. delay from LCDVCC to black video generation
77 : */
78 : #define PANEL_POWER_UP_TIMEOUT 300
79 : #define PANEL_POWER_DOWN_TIMEOUT 500
80 : #define HPD_CHECK_INTERVAL 10
81 : #define OLED_POST_T7_DELAY 100
82 : #define OLED_PRE_T11_DELAY 150
83 :
84 : #define CTX \
85 : hws->ctx
86 :
87 : #define DC_LOGGER_INIT()
88 :
89 : #define REG(reg)\
90 : hws->regs->reg
91 :
92 : #undef FN
93 : #define FN(reg_name, field_name) \
94 : hws->shifts->field_name, hws->masks->field_name
95 :
96 : struct dce110_hw_seq_reg_offsets {
97 : uint32_t crtc;
98 : };
99 :
100 : static const struct dce110_hw_seq_reg_offsets reg_offsets[] = {
101 : {
102 : .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
103 : },
104 : {
105 : .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
106 : },
107 : {
108 : .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
109 : },
110 : {
111 : .crtc = (mmCRTCV_GSL_CONTROL - mmCRTC_GSL_CONTROL),
112 : }
113 : };
114 :
115 : #define HW_REG_BLND(reg, id)\
116 : (reg + reg_offsets[id].blnd)
117 :
118 : #define HW_REG_CRTC(reg, id)\
119 : (reg + reg_offsets[id].crtc)
120 :
121 : #define MAX_WATERMARK 0xFFFF
122 : #define SAFE_NBP_MARK 0x7FFF
123 :
124 : /*******************************************************************************
125 : * Private definitions
126 : ******************************************************************************/
127 : /***************************PIPE_CONTROL***********************************/
128 0 : static void dce110_init_pte(struct dc_context *ctx)
129 : {
130 : uint32_t addr;
131 0 : uint32_t value = 0;
132 0 : uint32_t chunk_int = 0;
133 0 : uint32_t chunk_mul = 0;
134 :
135 0 : addr = mmUNP_DVMM_PTE_CONTROL;
136 0 : value = dm_read_reg(ctx, addr);
137 :
138 0 : set_reg_field_value(
139 : value,
140 : 0,
141 : DVMM_PTE_CONTROL,
142 : DVMM_USE_SINGLE_PTE);
143 :
144 0 : set_reg_field_value(
145 : value,
146 : 1,
147 : DVMM_PTE_CONTROL,
148 : DVMM_PTE_BUFFER_MODE0);
149 :
150 0 : set_reg_field_value(
151 : value,
152 : 1,
153 : DVMM_PTE_CONTROL,
154 : DVMM_PTE_BUFFER_MODE1);
155 :
156 0 : dm_write_reg(ctx, addr, value);
157 :
158 0 : addr = mmDVMM_PTE_REQ;
159 0 : value = dm_read_reg(ctx, addr);
160 :
161 0 : chunk_int = get_reg_field_value(
162 : value,
163 : DVMM_PTE_REQ,
164 : HFLIP_PTEREQ_PER_CHUNK_INT);
165 :
166 0 : chunk_mul = get_reg_field_value(
167 : value,
168 : DVMM_PTE_REQ,
169 : HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
170 :
171 0 : if (chunk_int != 0x4 || chunk_mul != 0x4) {
172 :
173 0 : set_reg_field_value(
174 : value,
175 : 255,
176 : DVMM_PTE_REQ,
177 : MAX_PTEREQ_TO_ISSUE);
178 :
179 0 : set_reg_field_value(
180 : value,
181 : 4,
182 : DVMM_PTE_REQ,
183 : HFLIP_PTEREQ_PER_CHUNK_INT);
184 :
185 0 : set_reg_field_value(
186 : value,
187 : 4,
188 : DVMM_PTE_REQ,
189 : HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
190 :
191 0 : dm_write_reg(ctx, addr, value);
192 : }
193 0 : }
194 : /**************************************************************************/
195 :
196 0 : static void enable_display_pipe_clock_gating(
197 : struct dc_context *ctx,
198 : bool clock_gating)
199 : {
200 : /*TODO*/
201 0 : }
202 :
203 0 : static bool dce110_enable_display_power_gating(
204 : struct dc *dc,
205 : uint8_t controller_id,
206 : struct dc_bios *dcb,
207 : enum pipe_gating_control power_gating)
208 : {
209 0 : enum bp_result bp_result = BP_RESULT_OK;
210 : enum bp_pipe_control_action cntl;
211 0 : struct dc_context *ctx = dc->ctx;
212 0 : unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
213 :
214 0 : if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
215 : return true;
216 :
217 0 : if (power_gating == PIPE_GATING_CONTROL_INIT)
218 : cntl = ASIC_PIPE_INIT;
219 0 : else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
220 : cntl = ASIC_PIPE_ENABLE;
221 : else
222 0 : cntl = ASIC_PIPE_DISABLE;
223 :
224 0 : if (controller_id == underlay_idx)
225 0 : controller_id = CONTROLLER_ID_UNDERLAY0 - 1;
226 :
227 0 : if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0){
228 :
229 0 : bp_result = dcb->funcs->enable_disp_power_gating(
230 0 : dcb, controller_id + 1, cntl);
231 :
232 : /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2
233 : * by default when command table is called
234 : *
235 : * Bios parser accepts controller_id = 6 as indicative of
236 : * underlay pipe in dce110. But we do not support more
237 : * than 3.
238 : */
239 0 : if (controller_id < CONTROLLER_ID_MAX - 1)
240 0 : dm_write_reg(ctx,
241 : HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id),
242 : 0);
243 : }
244 :
245 0 : if (power_gating != PIPE_GATING_CONTROL_ENABLE)
246 0 : dce110_init_pte(ctx);
247 :
248 0 : if (bp_result == BP_RESULT_OK)
249 : return true;
250 : else
251 0 : return false;
252 : }
253 :
254 0 : static void build_prescale_params(struct ipp_prescale_params *prescale_params,
255 : const struct dc_plane_state *plane_state)
256 : {
257 0 : prescale_params->mode = IPP_PRESCALE_MODE_FIXED_UNSIGNED;
258 :
259 0 : switch (plane_state->format) {
260 : case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
261 0 : prescale_params->scale = 0x2082;
262 : break;
263 : case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
264 : case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
265 0 : prescale_params->scale = 0x2020;
266 : break;
267 : case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
268 : case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
269 0 : prescale_params->scale = 0x2008;
270 : break;
271 : case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
272 : case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
273 : case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
274 0 : prescale_params->scale = 0x2000;
275 : break;
276 : default:
277 0 : ASSERT(false);
278 : break;
279 : }
280 0 : }
281 :
282 : static bool
283 0 : dce110_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
284 : const struct dc_plane_state *plane_state)
285 : {
286 0 : struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;
287 0 : const struct dc_transfer_func *tf = NULL;
288 0 : struct ipp_prescale_params prescale_params = { 0 };
289 0 : bool result = true;
290 :
291 0 : if (ipp == NULL)
292 : return false;
293 :
294 0 : if (plane_state->in_transfer_func)
295 0 : tf = plane_state->in_transfer_func;
296 :
297 0 : build_prescale_params(&prescale_params, plane_state);
298 0 : ipp->funcs->ipp_program_prescale(ipp, &prescale_params);
299 :
300 0 : if (plane_state->gamma_correction &&
301 0 : !plane_state->gamma_correction->is_identity &&
302 0 : dce_use_lut(plane_state->format))
303 0 : ipp->funcs->ipp_program_input_lut(ipp, plane_state->gamma_correction);
304 :
305 0 : if (tf == NULL) {
306 : /* Default case if no input transfer function specified */
307 0 : ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB);
308 0 : } else if (tf->type == TF_TYPE_PREDEFINED) {
309 0 : switch (tf->tf) {
310 : case TRANSFER_FUNCTION_SRGB:
311 0 : ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB);
312 0 : break;
313 : case TRANSFER_FUNCTION_BT709:
314 0 : ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_xvYCC);
315 0 : break;
316 : case TRANSFER_FUNCTION_LINEAR:
317 0 : ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
318 0 : break;
319 : case TRANSFER_FUNCTION_PQ:
320 : default:
321 : result = false;
322 : break;
323 : }
324 0 : } else if (tf->type == TF_TYPE_BYPASS) {
325 0 : ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
326 : } else {
327 : /*TF_TYPE_DISTRIBUTED_POINTS - Not supported in DCE 11*/
328 : result = false;
329 : }
330 :
331 : return result;
332 : }
333 :
334 0 : static bool convert_to_custom_float(struct pwl_result_data *rgb_resulted,
335 : struct curve_points *arr_points,
336 : uint32_t hw_points_num)
337 : {
338 : struct custom_float_format fmt;
339 :
340 0 : struct pwl_result_data *rgb = rgb_resulted;
341 :
342 0 : uint32_t i = 0;
343 :
344 0 : fmt.exponenta_bits = 6;
345 0 : fmt.mantissa_bits = 12;
346 0 : fmt.sign = true;
347 :
348 0 : if (!convert_to_custom_float_format(arr_points[0].x, &fmt,
349 : &arr_points[0].custom_float_x)) {
350 0 : BREAK_TO_DEBUGGER();
351 0 : return false;
352 : }
353 :
354 0 : if (!convert_to_custom_float_format(arr_points[0].offset, &fmt,
355 : &arr_points[0].custom_float_offset)) {
356 0 : BREAK_TO_DEBUGGER();
357 0 : return false;
358 : }
359 :
360 0 : if (!convert_to_custom_float_format(arr_points[0].slope, &fmt,
361 : &arr_points[0].custom_float_slope)) {
362 0 : BREAK_TO_DEBUGGER();
363 0 : return false;
364 : }
365 :
366 0 : fmt.mantissa_bits = 10;
367 0 : fmt.sign = false;
368 :
369 0 : if (!convert_to_custom_float_format(arr_points[1].x, &fmt,
370 : &arr_points[1].custom_float_x)) {
371 0 : BREAK_TO_DEBUGGER();
372 0 : return false;
373 : }
374 :
375 0 : if (!convert_to_custom_float_format(arr_points[1].y, &fmt,
376 : &arr_points[1].custom_float_y)) {
377 0 : BREAK_TO_DEBUGGER();
378 0 : return false;
379 : }
380 :
381 0 : if (!convert_to_custom_float_format(arr_points[1].slope, &fmt,
382 : &arr_points[1].custom_float_slope)) {
383 0 : BREAK_TO_DEBUGGER();
384 0 : return false;
385 : }
386 :
387 0 : fmt.mantissa_bits = 12;
388 0 : fmt.sign = true;
389 :
390 0 : while (i != hw_points_num) {
391 0 : if (!convert_to_custom_float_format(rgb->red, &fmt,
392 : &rgb->red_reg)) {
393 0 : BREAK_TO_DEBUGGER();
394 0 : return false;
395 : }
396 :
397 0 : if (!convert_to_custom_float_format(rgb->green, &fmt,
398 : &rgb->green_reg)) {
399 0 : BREAK_TO_DEBUGGER();
400 0 : return false;
401 : }
402 :
403 0 : if (!convert_to_custom_float_format(rgb->blue, &fmt,
404 : &rgb->blue_reg)) {
405 0 : BREAK_TO_DEBUGGER();
406 0 : return false;
407 : }
408 :
409 0 : if (!convert_to_custom_float_format(rgb->delta_red, &fmt,
410 : &rgb->delta_red_reg)) {
411 0 : BREAK_TO_DEBUGGER();
412 0 : return false;
413 : }
414 :
415 0 : if (!convert_to_custom_float_format(rgb->delta_green, &fmt,
416 : &rgb->delta_green_reg)) {
417 0 : BREAK_TO_DEBUGGER();
418 0 : return false;
419 : }
420 :
421 0 : if (!convert_to_custom_float_format(rgb->delta_blue, &fmt,
422 : &rgb->delta_blue_reg)) {
423 0 : BREAK_TO_DEBUGGER();
424 0 : return false;
425 : }
426 :
427 0 : ++rgb;
428 0 : ++i;
429 : }
430 :
431 : return true;
432 : }
433 :
434 : #define MAX_LOW_POINT 25
435 : #define NUMBER_REGIONS 16
436 : #define NUMBER_SW_SEGMENTS 16
437 :
438 : static bool
439 0 : dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf,
440 : struct pwl_params *regamma_params)
441 : {
442 : struct curve_points *arr_points;
443 : struct pwl_result_data *rgb_resulted;
444 : struct pwl_result_data *rgb;
445 : struct pwl_result_data *rgb_plus_1;
446 : struct fixed31_32 y_r;
447 : struct fixed31_32 y_g;
448 : struct fixed31_32 y_b;
449 : struct fixed31_32 y1_min;
450 : struct fixed31_32 y3_max;
451 :
452 : int32_t region_start, region_end;
453 : uint32_t i, j, k, seg_distr[NUMBER_REGIONS], increment, start_index, hw_points;
454 :
455 0 : if (output_tf == NULL || regamma_params == NULL || output_tf->type == TF_TYPE_BYPASS)
456 : return false;
457 :
458 0 : arr_points = regamma_params->arr_points;
459 0 : rgb_resulted = regamma_params->rgb_resulted;
460 0 : hw_points = 0;
461 :
462 0 : memset(regamma_params, 0, sizeof(struct pwl_params));
463 :
464 0 : if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
465 : /* 16 segments
466 : * segments are from 2^-11 to 2^5
467 : */
468 : region_start = -11;
469 : region_end = region_start + NUMBER_REGIONS;
470 :
471 0 : for (i = 0; i < NUMBER_REGIONS; i++)
472 0 : seg_distr[i] = 4;
473 :
474 : } else {
475 : /* 10 segments
476 : * segment is from 2^-10 to 2^1
477 : * We include an extra segment for range [2^0, 2^1). This is to
478 : * ensure that colors with normalized values of 1 don't miss the
479 : * LUT.
480 : */
481 0 : region_start = -10;
482 0 : region_end = 1;
483 :
484 0 : seg_distr[0] = 4;
485 0 : seg_distr[1] = 4;
486 0 : seg_distr[2] = 4;
487 0 : seg_distr[3] = 4;
488 0 : seg_distr[4] = 4;
489 0 : seg_distr[5] = 4;
490 0 : seg_distr[6] = 4;
491 0 : seg_distr[7] = 4;
492 0 : seg_distr[8] = 4;
493 0 : seg_distr[9] = 4;
494 0 : seg_distr[10] = 0;
495 0 : seg_distr[11] = -1;
496 0 : seg_distr[12] = -1;
497 0 : seg_distr[13] = -1;
498 0 : seg_distr[14] = -1;
499 0 : seg_distr[15] = -1;
500 : }
501 :
502 0 : for (k = 0; k < 16; k++) {
503 0 : if (seg_distr[k] != -1)
504 0 : hw_points += (1 << seg_distr[k]);
505 : }
506 :
507 : j = 0;
508 0 : for (k = 0; k < (region_end - region_start); k++) {
509 0 : increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
510 0 : start_index = (region_start + k + MAX_LOW_POINT) *
511 : NUMBER_SW_SEGMENTS;
512 0 : for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
513 0 : i += increment) {
514 0 : if (j == hw_points - 1)
515 : break;
516 0 : rgb_resulted[j].red = output_tf->tf_pts.red[i];
517 0 : rgb_resulted[j].green = output_tf->tf_pts.green[i];
518 0 : rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
519 0 : j++;
520 : }
521 : }
522 :
523 : /* last point */
524 0 : start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
525 0 : rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
526 0 : rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
527 0 : rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
528 :
529 0 : arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
530 : dc_fixpt_from_int(region_start));
531 0 : arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
532 : dc_fixpt_from_int(region_end));
533 :
534 0 : y_r = rgb_resulted[0].red;
535 0 : y_g = rgb_resulted[0].green;
536 0 : y_b = rgb_resulted[0].blue;
537 :
538 : y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
539 :
540 0 : arr_points[0].y = y1_min;
541 0 : arr_points[0].slope = dc_fixpt_div(arr_points[0].y,
542 : arr_points[0].x);
543 :
544 0 : y_r = rgb_resulted[hw_points - 1].red;
545 0 : y_g = rgb_resulted[hw_points - 1].green;
546 0 : y_b = rgb_resulted[hw_points - 1].blue;
547 :
548 : /* see comment above, m_arrPoints[1].y should be the Y value for the
549 : * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
550 : */
551 : y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
552 :
553 0 : arr_points[1].y = y3_max;
554 :
555 0 : arr_points[1].slope = dc_fixpt_zero;
556 :
557 0 : if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
558 : /* for PQ, we want to have a straight line from last HW X point,
559 : * and the slope to be such that we hit 1.0 at 10000 nits.
560 : */
561 0 : const struct fixed31_32 end_value = dc_fixpt_from_int(125);
562 :
563 0 : arr_points[1].slope = dc_fixpt_div(
564 : dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
565 : dc_fixpt_sub(end_value, arr_points[1].x));
566 : }
567 :
568 0 : regamma_params->hw_points_num = hw_points;
569 :
570 0 : k = 0;
571 0 : for (i = 1; i < 16; i++) {
572 0 : if (seg_distr[k] != -1) {
573 0 : regamma_params->arr_curve_points[k].segments_num = seg_distr[k];
574 0 : regamma_params->arr_curve_points[i].offset =
575 0 : regamma_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
576 : }
577 0 : k++;
578 : }
579 :
580 0 : if (seg_distr[k] != -1)
581 0 : regamma_params->arr_curve_points[k].segments_num = seg_distr[k];
582 :
583 0 : rgb = rgb_resulted;
584 0 : rgb_plus_1 = rgb_resulted + 1;
585 :
586 0 : i = 1;
587 :
588 0 : while (i != hw_points + 1) {
589 0 : if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
590 0 : rgb_plus_1->red = rgb->red;
591 0 : if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
592 0 : rgb_plus_1->green = rgb->green;
593 0 : if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
594 0 : rgb_plus_1->blue = rgb->blue;
595 :
596 0 : rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
597 0 : rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
598 0 : rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue);
599 :
600 0 : ++rgb_plus_1;
601 0 : ++rgb;
602 0 : ++i;
603 : }
604 :
605 0 : convert_to_custom_float(rgb_resulted, arr_points, hw_points);
606 :
607 0 : return true;
608 : }
609 :
610 : static bool
611 0 : dce110_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
612 : const struct dc_stream_state *stream)
613 : {
614 0 : struct transform *xfm = pipe_ctx->plane_res.xfm;
615 :
616 0 : xfm->funcs->opp_power_on_regamma_lut(xfm, true);
617 0 : xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
618 :
619 0 : if (stream->out_transfer_func &&
620 0 : stream->out_transfer_func->type == TF_TYPE_PREDEFINED &&
621 0 : stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) {
622 0 : xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_SRGB);
623 0 : } else if (dce110_translate_regamma_to_hw_format(stream->out_transfer_func,
624 : &xfm->regamma_params)) {
625 0 : xfm->funcs->opp_program_regamma_pwl(xfm, &xfm->regamma_params);
626 0 : xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_USER);
627 : } else {
628 0 : xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_BYPASS);
629 : }
630 :
631 0 : xfm->funcs->opp_power_on_regamma_lut(xfm, false);
632 :
633 0 : return true;
634 : }
635 :
636 0 : void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
637 : {
638 : bool is_hdmi_tmds;
639 : bool is_dp;
640 :
641 0 : ASSERT(pipe_ctx->stream);
642 :
643 0 : if (pipe_ctx->stream_res.stream_enc == NULL)
644 : return; /* this is not root pipe */
645 :
646 0 : is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
647 0 : is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
648 :
649 0 : if (!is_hdmi_tmds && !is_dp)
650 : return;
651 :
652 0 : if (is_hdmi_tmds)
653 0 : pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
654 : pipe_ctx->stream_res.stream_enc,
655 0 : &pipe_ctx->stream_res.encoder_info_frame);
656 : else
657 0 : pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
658 : pipe_ctx->stream_res.stream_enc,
659 0 : &pipe_ctx->stream_res.encoder_info_frame);
660 : }
661 :
662 0 : void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
663 : {
664 0 : enum dc_lane_count lane_count =
665 0 : pipe_ctx->stream->link->cur_link_settings.lane_count;
666 0 : struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
667 0 : struct dc_link *link = pipe_ctx->stream->link;
668 0 : const struct dc *dc = link->dc;
669 0 : const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
670 : uint32_t active_total_with_borders;
671 0 : uint32_t early_control = 0;
672 0 : struct timing_generator *tg = pipe_ctx->stream_res.tg;
673 :
674 0 : link_hwss->setup_stream_encoder(pipe_ctx);
675 :
676 0 : dc->hwss.update_info_frame(pipe_ctx);
677 :
678 : /* enable early control to avoid corruption on DP monitor*/
679 0 : active_total_with_borders =
680 0 : timing->h_addressable
681 0 : + timing->h_border_left
682 0 : + timing->h_border_right;
683 :
684 0 : if (lane_count != 0)
685 0 : early_control = active_total_with_borders % lane_count;
686 :
687 0 : if (early_control == 0)
688 0 : early_control = lane_count;
689 :
690 0 : tg->funcs->set_early_control(tg, early_control);
691 :
692 : /* enable audio only within mode set */
693 0 : if (pipe_ctx->stream_res.audio != NULL) {
694 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
695 0 : pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
696 : }
697 :
698 :
699 :
700 :
701 0 : }
702 :
703 : static enum bp_result link_transmitter_control(
704 : struct dc_bios *bios,
705 : struct bp_transmitter_control *cntl)
706 : {
707 : enum bp_result result;
708 :
709 0 : result = bios->funcs->transmitter_control(bios, cntl);
710 :
711 : return result;
712 : }
713 :
714 : /*
715 : * @brief
716 : * eDP only.
717 : */
718 0 : void dce110_edp_wait_for_hpd_ready(
719 : struct dc_link *link,
720 : bool power_up)
721 : {
722 0 : struct dc_context *ctx = link->ctx;
723 0 : struct graphics_object_id connector = link->link_enc->connector;
724 : struct gpio *hpd;
725 0 : struct dc_sink *sink = link->local_sink;
726 0 : bool edp_hpd_high = false;
727 0 : uint32_t time_elapsed = 0;
728 0 : uint32_t timeout = power_up ?
729 0 : PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
730 :
731 0 : if (dal_graphics_object_id_get_connector_id(connector)
732 : != CONNECTOR_ID_EDP) {
733 0 : BREAK_TO_DEBUGGER();
734 0 : return;
735 : }
736 :
737 0 : if (!power_up)
738 : /*
739 : * From KV, we will not HPD low after turning off VCC -
740 : * instead, we will check the SW timer in power_up().
741 : */
742 : return;
743 :
744 : /*
745 : * When we power on/off the eDP panel,
746 : * we need to wait until SENSE bit is high/low.
747 : */
748 :
749 : /* obtain HPD */
750 : /* TODO what to do with this? */
751 0 : hpd = get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
752 :
753 0 : if (!hpd) {
754 0 : BREAK_TO_DEBUGGER();
755 0 : return;
756 : }
757 :
758 0 : if (sink != NULL) {
759 0 : if (sink->edid_caps.panel_patch.extra_t3_ms > 0) {
760 0 : int extra_t3_in_ms = sink->edid_caps.panel_patch.extra_t3_ms;
761 :
762 0 : msleep(extra_t3_in_ms);
763 : }
764 : }
765 :
766 0 : dal_gpio_open(hpd, GPIO_MODE_INTERRUPT);
767 :
768 : /* wait until timeout or panel detected */
769 :
770 : do {
771 0 : uint32_t detected = 0;
772 :
773 0 : dal_gpio_get_value(hpd, &detected);
774 :
775 0 : if (!(detected ^ power_up)) {
776 0 : edp_hpd_high = true;
777 0 : break;
778 : }
779 :
780 0 : msleep(HPD_CHECK_INTERVAL);
781 :
782 0 : time_elapsed += HPD_CHECK_INTERVAL;
783 0 : } while (time_elapsed < timeout);
784 :
785 0 : dal_gpio_close(hpd);
786 :
787 0 : dal_gpio_destroy_irq(&hpd);
788 :
789 0 : if (false == edp_hpd_high) {
790 0 : DC_LOG_WARNING(
791 : "%s: wait timed out!\n", __func__);
792 : }
793 : }
794 :
795 0 : void dce110_edp_power_control(
796 : struct dc_link *link,
797 : bool power_up)
798 : {
799 0 : struct dc_context *ctx = link->ctx;
800 0 : struct bp_transmitter_control cntl = { 0 };
801 : enum bp_result bp_result;
802 : uint8_t panel_instance;
803 :
804 :
805 0 : if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
806 : != CONNECTOR_ID_EDP) {
807 0 : BREAK_TO_DEBUGGER();
808 0 : return;
809 : }
810 :
811 0 : if (!link->panel_cntl)
812 : return;
813 0 : if (power_up !=
814 0 : link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl)) {
815 :
816 0 : unsigned long long current_ts = dm_get_timestamp(ctx);
817 0 : unsigned long long time_since_edp_poweroff_ms =
818 0 : div64_u64(dm_get_elapse_time_in_ns(
819 : ctx,
820 : current_ts,
821 : dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
822 0 : unsigned long long time_since_edp_poweron_ms =
823 0 : div64_u64(dm_get_elapse_time_in_ns(
824 : ctx,
825 : current_ts,
826 : dp_trace_get_edp_poweron_timestamp(link)), 1000000);
827 0 : DC_LOG_HW_RESUME_S3(
828 : "%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu",
829 : __func__,
830 : power_up,
831 : current_ts,
832 : dp_trace_get_edp_poweroff_timestamp(link),
833 : dp_trace_get_edp_poweron_timestamp(link),
834 : time_since_edp_poweroff_ms,
835 : time_since_edp_poweron_ms);
836 :
837 : /* Send VBIOS command to prompt eDP panel power */
838 0 : if (power_up) {
839 : /* edp requires a min of 500ms from LCDVDD off to on */
840 0 : unsigned long long remaining_min_edp_poweroff_time_ms = 500;
841 :
842 : /* add time defined by a patch, if any (usually patch extra_t12_ms is 0) */
843 0 : if (link->local_sink != NULL)
844 0 : remaining_min_edp_poweroff_time_ms +=
845 0 : link->local_sink->edid_caps.panel_patch.extra_t12_ms;
846 :
847 : /* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */
848 0 : if (dp_trace_get_edp_poweroff_timestamp(link) != 0) {
849 0 : if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms)
850 0 : remaining_min_edp_poweroff_time_ms =
851 : remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms;
852 : else
853 : remaining_min_edp_poweroff_time_ms = 0;
854 : }
855 :
856 0 : if (remaining_min_edp_poweroff_time_ms) {
857 0 : DC_LOG_HW_RESUME_S3(
858 : "%s: remaining_min_edp_poweroff_time_ms=%llu: begin wait.\n",
859 : __func__, remaining_min_edp_poweroff_time_ms);
860 0 : msleep(remaining_min_edp_poweroff_time_ms);
861 0 : DC_LOG_HW_RESUME_S3(
862 : "%s: remaining_min_edp_poweroff_time_ms=%llu: end wait.\n",
863 : __func__, remaining_min_edp_poweroff_time_ms);
864 0 : dm_output_to_console("%s: wait %lld ms to power on eDP.\n",
865 : __func__, remaining_min_edp_poweroff_time_ms);
866 : } else {
867 0 : DC_LOG_HW_RESUME_S3(
868 : "%s: remaining_min_edp_poweroff_time_ms=%llu: no wait required.\n",
869 : __func__, remaining_min_edp_poweroff_time_ms);
870 : }
871 : }
872 :
873 0 : DC_LOG_HW_RESUME_S3(
874 : "%s: BEGIN: Panel Power action: %s\n",
875 : __func__, (power_up ? "On":"Off"));
876 :
877 0 : cntl.action = power_up ?
878 0 : TRANSMITTER_CONTROL_POWER_ON :
879 : TRANSMITTER_CONTROL_POWER_OFF;
880 0 : cntl.transmitter = link->link_enc->transmitter;
881 0 : cntl.connector_obj_id = link->link_enc->connector;
882 0 : cntl.coherent = false;
883 0 : cntl.lanes_number = LANE_COUNT_FOUR;
884 0 : cntl.hpd_sel = link->link_enc->hpd_source;
885 0 : panel_instance = link->panel_cntl->inst;
886 :
887 0 : if (ctx->dc->ctx->dmub_srv &&
888 0 : ctx->dc->debug.dmub_command_table) {
889 0 : if (cntl.action == TRANSMITTER_CONTROL_POWER_ON)
890 0 : bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
891 : LVTMA_CONTROL_POWER_ON,
892 : panel_instance);
893 : else
894 0 : bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
895 : LVTMA_CONTROL_POWER_OFF,
896 : panel_instance);
897 : }
898 :
899 0 : bp_result = link_transmitter_control(ctx->dc_bios, &cntl);
900 :
901 0 : DC_LOG_HW_RESUME_S3(
902 : "%s: END: Panel Power action: %s bp_result=%u\n",
903 : __func__, (power_up ? "On":"Off"),
904 : bp_result);
905 :
906 0 : dp_trace_set_edp_power_timestamp(link, power_up);
907 :
908 0 : DC_LOG_HW_RESUME_S3(
909 : "%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n",
910 : __func__,
911 : dp_trace_get_edp_poweroff_timestamp(link),
912 : dp_trace_get_edp_poweron_timestamp(link));
913 :
914 0 : if (bp_result != BP_RESULT_OK)
915 0 : DC_LOG_ERROR(
916 : "%s: Panel Power bp_result: %d\n",
917 : __func__, bp_result);
918 : } else {
919 0 : DC_LOG_HW_RESUME_S3(
920 : "%s: Skipping Panel Power action: %s\n",
921 : __func__, (power_up ? "On":"Off"));
922 : }
923 : }
924 :
925 0 : void dce110_edp_wait_for_T12(
926 : struct dc_link *link)
927 : {
928 0 : struct dc_context *ctx = link->ctx;
929 :
930 0 : if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
931 : != CONNECTOR_ID_EDP) {
932 0 : BREAK_TO_DEBUGGER();
933 0 : return;
934 : }
935 :
936 0 : if (!link->panel_cntl)
937 : return;
938 :
939 0 : if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) &&
940 0 : dp_trace_get_edp_poweroff_timestamp(link) != 0) {
941 0 : unsigned int t12_duration = 500; // Default T12 as per spec
942 0 : unsigned long long current_ts = dm_get_timestamp(ctx);
943 0 : unsigned long long time_since_edp_poweroff_ms =
944 0 : div64_u64(dm_get_elapse_time_in_ns(
945 : ctx,
946 : current_ts,
947 : dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
948 :
949 0 : t12_duration += link->local_sink->edid_caps.panel_patch.extra_t12_ms; // Add extra T12
950 :
951 0 : if (time_since_edp_poweroff_ms < t12_duration)
952 0 : msleep(t12_duration - time_since_edp_poweroff_ms);
953 : }
954 : }
955 :
956 : /*todo: cloned in stream enc, fix*/
957 : /*
958 : * @brief
959 : * eDP only. Control the backlight of the eDP panel
960 : */
961 0 : void dce110_edp_backlight_control(
962 : struct dc_link *link,
963 : bool enable)
964 : {
965 0 : struct dc_context *ctx = link->ctx;
966 0 : struct bp_transmitter_control cntl = { 0 };
967 : uint8_t panel_instance;
968 :
969 0 : if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
970 : != CONNECTOR_ID_EDP) {
971 0 : BREAK_TO_DEBUGGER();
972 0 : return;
973 : }
974 :
975 0 : if (link->panel_cntl) {
976 0 : bool is_backlight_on = link->panel_cntl->funcs->is_panel_backlight_on(link->panel_cntl);
977 :
978 0 : if ((enable && is_backlight_on) || (!enable && !is_backlight_on)) {
979 0 : DC_LOG_HW_RESUME_S3(
980 : "%s: panel already powered up/off. Do nothing.\n",
981 : __func__);
982 0 : return;
983 : }
984 : }
985 :
986 : /* Send VBIOS command to control eDP panel backlight */
987 :
988 0 : DC_LOG_HW_RESUME_S3(
989 : "%s: backlight action: %s\n",
990 : __func__, (enable ? "On":"Off"));
991 :
992 0 : cntl.action = enable ?
993 0 : TRANSMITTER_CONTROL_BACKLIGHT_ON :
994 : TRANSMITTER_CONTROL_BACKLIGHT_OFF;
995 :
996 : /*cntl.engine_id = ctx->engine;*/
997 0 : cntl.transmitter = link->link_enc->transmitter;
998 0 : cntl.connector_obj_id = link->link_enc->connector;
999 : /*todo: unhardcode*/
1000 0 : cntl.lanes_number = LANE_COUNT_FOUR;
1001 0 : cntl.hpd_sel = link->link_enc->hpd_source;
1002 0 : cntl.signal = SIGNAL_TYPE_EDP;
1003 :
1004 : /* For eDP, the following delays might need to be considered
1005 : * after link training completed:
1006 : * idle period - min. accounts for required BS-Idle pattern,
1007 : * max. allows for source frame synchronization);
1008 : * 50 msec max. delay from valid video data from source
1009 : * to video on dislpay or backlight enable.
1010 : *
1011 : * Disable the delay for now.
1012 : * Enable it in the future if necessary.
1013 : */
1014 : /* dc_service_sleep_in_milliseconds(50); */
1015 : /*edp 1.2*/
1016 0 : panel_instance = link->panel_cntl->inst;
1017 :
1018 0 : if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) {
1019 0 : if (!link->dc->config.edp_no_power_sequencing)
1020 : /*
1021 : * Sometimes, DP receiver chip power-controlled externally by an
1022 : * Embedded Controller could be treated and used as eDP,
1023 : * if it drives mobile display. In this case,
1024 : * we shouldn't be doing power-sequencing, hence we can skip
1025 : * waiting for T7-ready.
1026 : */
1027 0 : edp_receiver_ready_T7(link);
1028 : else
1029 0 : DC_LOG_DC("edp_receiver_ready_T7 skipped\n");
1030 : }
1031 :
1032 0 : if (ctx->dc->ctx->dmub_srv &&
1033 0 : ctx->dc->debug.dmub_command_table) {
1034 0 : if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
1035 0 : ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
1036 : LVTMA_CONTROL_LCD_BLON,
1037 : panel_instance);
1038 : else
1039 0 : ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
1040 : LVTMA_CONTROL_LCD_BLOFF,
1041 : panel_instance);
1042 : }
1043 :
1044 0 : link_transmitter_control(ctx->dc_bios, &cntl);
1045 :
1046 0 : if (enable && link->dpcd_sink_ext_caps.bits.oled)
1047 0 : msleep(OLED_POST_T7_DELAY);
1048 :
1049 0 : if (link->dpcd_sink_ext_caps.bits.oled ||
1050 0 : link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
1051 : link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)
1052 0 : dc_link_backlight_enable_aux(link, enable);
1053 :
1054 : /*edp 1.2*/
1055 0 : if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) {
1056 0 : if (!link->dc->config.edp_no_power_sequencing)
1057 : /*
1058 : * Sometimes, DP receiver chip power-controlled externally by an
1059 : * Embedded Controller could be treated and used as eDP,
1060 : * if it drives mobile display. In this case,
1061 : * we shouldn't be doing power-sequencing, hence we can skip
1062 : * waiting for T9-ready.
1063 : */
1064 0 : edp_add_delay_for_T9(link);
1065 : else
1066 0 : DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
1067 : }
1068 :
1069 0 : if (!enable && link->dpcd_sink_ext_caps.bits.oled)
1070 0 : msleep(OLED_PRE_T11_DELAY);
1071 : }
1072 :
1073 0 : void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
1074 : {
1075 : /* notify audio driver for audio modes of monitor */
1076 : struct dc *dc;
1077 : struct clk_mgr *clk_mgr;
1078 0 : unsigned int i, num_audio = 1;
1079 :
1080 0 : if (!pipe_ctx->stream)
1081 : return;
1082 :
1083 0 : dc = pipe_ctx->stream->ctx->dc;
1084 0 : clk_mgr = dc->clk_mgr;
1085 :
1086 0 : if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true)
1087 : return;
1088 :
1089 0 : if (pipe_ctx->stream_res.audio) {
1090 0 : for (i = 0; i < MAX_PIPES; i++) {
1091 : /*current_state not updated yet*/
1092 0 : if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL)
1093 0 : num_audio++;
1094 : }
1095 :
1096 0 : pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio);
1097 :
1098 0 : if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa)
1099 : /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
1100 0 : clk_mgr->funcs->enable_pme_wa(clk_mgr);
1101 : /* un-mute audio */
1102 : /* TODO: audio should be per stream rather than per link */
1103 0 : if (is_dp_128b_132b_signal(pipe_ctx))
1104 0 : pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
1105 : pipe_ctx->stream_res.hpo_dp_stream_enc, false);
1106 : else
1107 0 : pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
1108 : pipe_ctx->stream_res.stream_enc, false);
1109 0 : if (pipe_ctx->stream_res.audio)
1110 0 : pipe_ctx->stream_res.audio->enabled = true;
1111 : }
1112 :
1113 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
1114 0 : dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
1115 : }
1116 :
1117 0 : void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
1118 : {
1119 : struct dc *dc;
1120 : struct clk_mgr *clk_mgr;
1121 :
1122 0 : if (!pipe_ctx || !pipe_ctx->stream)
1123 : return;
1124 :
1125 0 : dc = pipe_ctx->stream->ctx->dc;
1126 0 : clk_mgr = dc->clk_mgr;
1127 :
1128 0 : if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false)
1129 : return;
1130 :
1131 0 : if (is_dp_128b_132b_signal(pipe_ctx))
1132 0 : pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
1133 : pipe_ctx->stream_res.hpo_dp_stream_enc, true);
1134 : else
1135 0 : pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
1136 : pipe_ctx->stream_res.stream_enc, true);
1137 0 : if (pipe_ctx->stream_res.audio) {
1138 0 : pipe_ctx->stream_res.audio->enabled = false;
1139 :
1140 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
1141 0 : if (is_dp_128b_132b_signal(pipe_ctx))
1142 0 : pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
1143 : pipe_ctx->stream_res.hpo_dp_stream_enc);
1144 : else
1145 0 : pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
1146 : pipe_ctx->stream_res.stream_enc);
1147 : else
1148 0 : pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
1149 : pipe_ctx->stream_res.stream_enc);
1150 :
1151 0 : if (clk_mgr->funcs->enable_pme_wa)
1152 : /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
1153 0 : clk_mgr->funcs->enable_pme_wa(clk_mgr);
1154 :
1155 : /* TODO: notify audio driver for if audio modes list changed
1156 : * add audio mode list change flag */
1157 : /* dal_audio_disable_azalia_audio_jack_presence(stream->audio,
1158 : * stream->stream_engine_id);
1159 : */
1160 : }
1161 :
1162 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
1163 0 : dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
1164 : }
1165 :
1166 0 : void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
1167 : {
1168 0 : struct dc_stream_state *stream = pipe_ctx->stream;
1169 0 : struct dc_link *link = stream->link;
1170 0 : struct dc *dc = pipe_ctx->stream->ctx->dc;
1171 0 : const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
1172 :
1173 0 : if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) {
1174 0 : pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets(
1175 : pipe_ctx->stream_res.stream_enc);
1176 0 : pipe_ctx->stream_res.stream_enc->funcs->hdmi_reset_stream_attribute(
1177 : pipe_ctx->stream_res.stream_enc);
1178 : }
1179 :
1180 0 : if (is_dp_128b_132b_signal(pipe_ctx)) {
1181 0 : pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
1182 : pipe_ctx->stream_res.hpo_dp_stream_enc);
1183 0 : } else if (dc_is_dp_signal(pipe_ctx->stream->signal))
1184 0 : pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets(
1185 : pipe_ctx->stream_res.stream_enc);
1186 :
1187 0 : dc->hwss.disable_audio_stream(pipe_ctx);
1188 :
1189 0 : link_hwss->reset_stream_encoder(pipe_ctx);
1190 :
1191 0 : if (is_dp_128b_132b_signal(pipe_ctx)) {
1192 : /* TODO: This looks like a bug to me as we are disabling HPO IO when
1193 : * we are just disabling a single HPO stream. Shouldn't we disable HPO
1194 : * HW control only when HPOs for all streams are disabled?
1195 : */
1196 0 : if (pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control)
1197 0 : pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control(
1198 : pipe_ctx->stream->ctx->dc->hwseq, false);
1199 : }
1200 0 : }
1201 :
1202 0 : void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
1203 : struct dc_link_settings *link_settings)
1204 : {
1205 0 : struct encoder_unblank_param params = { { 0 } };
1206 0 : struct dc_stream_state *stream = pipe_ctx->stream;
1207 0 : struct dc_link *link = stream->link;
1208 0 : struct dce_hwseq *hws = link->dc->hwseq;
1209 :
1210 : /* only 3 items below are used by unblank */
1211 0 : params.timing = pipe_ctx->stream->timing;
1212 0 : params.link_settings.link_rate = link_settings->link_rate;
1213 :
1214 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
1215 0 : pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);
1216 :
1217 0 : if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
1218 0 : hws->funcs.edp_backlight_control(link, true);
1219 : }
1220 0 : }
1221 :
1222 0 : void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
1223 : {
1224 0 : struct dc_stream_state *stream = pipe_ctx->stream;
1225 0 : struct dc_link *link = stream->link;
1226 0 : struct dce_hwseq *hws = link->dc->hwseq;
1227 :
1228 0 : if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
1229 0 : hws->funcs.edp_backlight_control(link, false);
1230 0 : link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
1231 : }
1232 :
1233 0 : if (is_dp_128b_132b_signal(pipe_ctx)) {
1234 : /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
1235 0 : pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
1236 : pipe_ctx->stream_res.hpo_dp_stream_enc);
1237 0 : } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
1238 0 : pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
1239 :
1240 0 : if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) {
1241 : /*
1242 : * After output is idle pattern some sinks need time to recognize the stream
1243 : * has changed or they enter protection state and hang.
1244 : */
1245 0 : msleep(60);
1246 0 : } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
1247 0 : if (!link->dc->config.edp_no_power_sequencing) {
1248 : /*
1249 : * Sometimes, DP receiver chip power-controlled externally by an
1250 : * Embedded Controller could be treated and used as eDP,
1251 : * if it drives mobile display. In this case,
1252 : * we shouldn't be doing power-sequencing, hence we can skip
1253 : * waiting for T9-ready.
1254 : */
1255 0 : edp_receiver_ready_T9(link);
1256 : }
1257 : }
1258 : }
1259 :
1260 0 : }
1261 :
1262 :
1263 0 : void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
1264 : {
1265 0 : if (pipe_ctx != NULL && pipe_ctx->stream_res.stream_enc != NULL)
1266 0 : pipe_ctx->stream_res.stream_enc->funcs->set_avmute(pipe_ctx->stream_res.stream_enc, enable);
1267 0 : }
1268 :
1269 : static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
1270 : {
1271 : switch (crtc_id) {
1272 : case CONTROLLER_ID_D0:
1273 : return DTO_SOURCE_ID0;
1274 : case CONTROLLER_ID_D1:
1275 : return DTO_SOURCE_ID1;
1276 : case CONTROLLER_ID_D2:
1277 : return DTO_SOURCE_ID2;
1278 : case CONTROLLER_ID_D3:
1279 : return DTO_SOURCE_ID3;
1280 : case CONTROLLER_ID_D4:
1281 : return DTO_SOURCE_ID4;
1282 : case CONTROLLER_ID_D5:
1283 : return DTO_SOURCE_ID5;
1284 : default:
1285 : return DTO_SOURCE_UNKNOWN;
1286 : }
1287 : }
1288 :
1289 0 : static void build_audio_output(
1290 : struct dc_state *state,
1291 : const struct pipe_ctx *pipe_ctx,
1292 : struct audio_output *audio_output)
1293 : {
1294 0 : const struct dc_stream_state *stream = pipe_ctx->stream;
1295 0 : audio_output->engine_id = pipe_ctx->stream_res.stream_enc->id;
1296 :
1297 0 : audio_output->signal = pipe_ctx->stream->signal;
1298 :
1299 : /* audio_crtc_info */
1300 :
1301 0 : audio_output->crtc_info.h_total =
1302 0 : stream->timing.h_total;
1303 :
1304 : /*
1305 : * Audio packets are sent during actual CRTC blank physical signal, we
1306 : * need to specify actual active signal portion
1307 : */
1308 0 : audio_output->crtc_info.h_active =
1309 0 : stream->timing.h_addressable
1310 0 : + stream->timing.h_border_left
1311 0 : + stream->timing.h_border_right;
1312 :
1313 0 : audio_output->crtc_info.v_active =
1314 0 : stream->timing.v_addressable
1315 0 : + stream->timing.v_border_top
1316 0 : + stream->timing.v_border_bottom;
1317 :
1318 0 : audio_output->crtc_info.pixel_repetition = 1;
1319 :
1320 0 : audio_output->crtc_info.interlaced =
1321 0 : stream->timing.flags.INTERLACE;
1322 :
1323 0 : audio_output->crtc_info.refresh_rate =
1324 0 : (stream->timing.pix_clk_100hz*100)/
1325 0 : (stream->timing.h_total*stream->timing.v_total);
1326 :
1327 0 : audio_output->crtc_info.color_depth =
1328 0 : stream->timing.display_color_depth;
1329 :
1330 0 : audio_output->crtc_info.requested_pixel_clock_100Hz =
1331 0 : pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz;
1332 :
1333 0 : audio_output->crtc_info.calculated_pixel_clock_100Hz =
1334 0 : pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz;
1335 :
1336 : /*for HDMI, audio ACR is with deep color ratio factor*/
1337 0 : if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) &&
1338 : audio_output->crtc_info.requested_pixel_clock_100Hz ==
1339 0 : (stream->timing.pix_clk_100hz)) {
1340 0 : if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
1341 0 : audio_output->crtc_info.requested_pixel_clock_100Hz =
1342 0 : audio_output->crtc_info.requested_pixel_clock_100Hz/2;
1343 0 : audio_output->crtc_info.calculated_pixel_clock_100Hz =
1344 0 : pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2;
1345 :
1346 : }
1347 : }
1348 :
1349 0 : if (state->clk_mgr &&
1350 0 : (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
1351 : pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) {
1352 0 : audio_output->pll_info.dp_dto_source_clock_in_khz =
1353 0 : state->clk_mgr->funcs->get_dp_ref_clk_frequency(
1354 : state->clk_mgr);
1355 : }
1356 :
1357 0 : audio_output->pll_info.feed_back_divider =
1358 0 : pipe_ctx->pll_settings.feedback_divider;
1359 :
1360 0 : audio_output->pll_info.dto_source =
1361 0 : translate_to_dto_source(
1362 0 : pipe_ctx->stream_res.tg->inst + 1);
1363 :
1364 : /* TODO hard code to enable for now. Need get from stream */
1365 0 : audio_output->pll_info.ss_enabled = true;
1366 :
1367 0 : audio_output->pll_info.ss_percentage =
1368 0 : pipe_ctx->pll_settings.ss_percentage;
1369 0 : }
1370 :
1371 0 : static void program_scaler(const struct dc *dc,
1372 : const struct pipe_ctx *pipe_ctx)
1373 : {
1374 0 : struct tg_color color = {0};
1375 :
1376 : /* TOFPGA */
1377 0 : if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL)
1378 0 : return;
1379 :
1380 0 : if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
1381 0 : get_surface_visual_confirm_color(pipe_ctx, &color);
1382 : else
1383 0 : color_space_to_black_color(dc,
1384 0 : pipe_ctx->stream->output_color_space,
1385 : &color);
1386 :
1387 0 : pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth(
1388 : pipe_ctx->plane_res.xfm,
1389 : pipe_ctx->plane_res.scl_data.lb_params.depth,
1390 0 : &pipe_ctx->stream->bit_depth_params);
1391 :
1392 0 : if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) {
1393 : /*
1394 : * The way 420 is packed, 2 channels carry Y component, 1 channel
1395 : * alternate between Cb and Cr, so both channels need the pixel
1396 : * value for Y
1397 : */
1398 0 : if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
1399 0 : color.color_r_cr = color.color_g_y;
1400 :
1401 0 : pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color(
1402 : pipe_ctx->stream_res.tg,
1403 : &color);
1404 : }
1405 :
1406 0 : pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm,
1407 : &pipe_ctx->plane_res.scl_data);
1408 : }
1409 :
1410 0 : static enum dc_status dce110_enable_stream_timing(
1411 : struct pipe_ctx *pipe_ctx,
1412 : struct dc_state *context,
1413 : struct dc *dc)
1414 : {
1415 0 : struct dc_stream_state *stream = pipe_ctx->stream;
1416 0 : struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx.
1417 0 : pipe_ctx[pipe_ctx->pipe_idx];
1418 0 : struct tg_color black_color = {0};
1419 :
1420 0 : if (!pipe_ctx_old->stream) {
1421 :
1422 : /* program blank color */
1423 0 : color_space_to_black_color(dc,
1424 : stream->output_color_space, &black_color);
1425 0 : pipe_ctx->stream_res.tg->funcs->set_blank_color(
1426 : pipe_ctx->stream_res.tg,
1427 : &black_color);
1428 :
1429 : /*
1430 : * Must blank CRTC after disabling power gating and before any
1431 : * programming, otherwise CRTC will be hung in bad state
1432 : */
1433 0 : pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true);
1434 :
1435 0 : if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
1436 : pipe_ctx->clock_source,
1437 : &pipe_ctx->stream_res.pix_clk_params,
1438 0 : dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
1439 : &pipe_ctx->pll_settings)) {
1440 0 : BREAK_TO_DEBUGGER();
1441 0 : return DC_ERROR_UNEXPECTED;
1442 : }
1443 :
1444 0 : pipe_ctx->stream_res.tg->funcs->program_timing(
1445 : pipe_ctx->stream_res.tg,
1446 0 : &stream->timing,
1447 : 0,
1448 : 0,
1449 : 0,
1450 : 0,
1451 0 : pipe_ctx->stream->signal,
1452 : true);
1453 : }
1454 :
1455 0 : if (!pipe_ctx_old->stream) {
1456 0 : if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(
1457 : pipe_ctx->stream_res.tg)) {
1458 0 : BREAK_TO_DEBUGGER();
1459 0 : return DC_ERROR_UNEXPECTED;
1460 : }
1461 : }
1462 :
1463 : return DC_OK;
1464 : }
1465 :
1466 0 : static enum dc_status apply_single_controller_ctx_to_hw(
1467 : struct pipe_ctx *pipe_ctx,
1468 : struct dc_state *context,
1469 : struct dc *dc)
1470 : {
1471 0 : struct dc_stream_state *stream = pipe_ctx->stream;
1472 0 : struct dc_link *link = stream->link;
1473 0 : struct drr_params params = {0};
1474 0 : unsigned int event_triggers = 0;
1475 0 : struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
1476 0 : struct dce_hwseq *hws = dc->hwseq;
1477 :
1478 0 : if (hws->funcs.disable_stream_gating) {
1479 0 : hws->funcs.disable_stream_gating(dc, pipe_ctx);
1480 : }
1481 :
1482 0 : if (pipe_ctx->stream_res.audio != NULL) {
1483 : struct audio_output audio_output;
1484 :
1485 0 : build_audio_output(context, pipe_ctx, &audio_output);
1486 :
1487 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
1488 0 : if (is_dp_128b_132b_signal(pipe_ctx))
1489 0 : pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
1490 : pipe_ctx->stream_res.hpo_dp_stream_enc,
1491 0 : pipe_ctx->stream_res.audio->inst,
1492 0 : &pipe_ctx->stream->audio_info);
1493 : else
1494 0 : pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
1495 : pipe_ctx->stream_res.stream_enc,
1496 0 : pipe_ctx->stream_res.audio->inst,
1497 0 : &pipe_ctx->stream->audio_info);
1498 : else
1499 0 : pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
1500 : pipe_ctx->stream_res.stream_enc,
1501 0 : pipe_ctx->stream_res.audio->inst,
1502 : &pipe_ctx->stream->audio_info,
1503 : &audio_output.crtc_info);
1504 :
1505 0 : pipe_ctx->stream_res.audio->funcs->az_configure(
1506 : pipe_ctx->stream_res.audio,
1507 : pipe_ctx->stream->signal,
1508 : &audio_output.crtc_info,
1509 0 : &pipe_ctx->stream->audio_info);
1510 : }
1511 :
1512 : /* make sure no pipes syncd to the pipe being enabled */
1513 0 : if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
1514 0 : check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
1515 :
1516 0 : pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
1517 : pipe_ctx->stream_res.opp,
1518 : &stream->bit_depth_params,
1519 : &stream->clamping);
1520 :
1521 0 : pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
1522 : pipe_ctx->stream_res.opp,
1523 : COLOR_SPACE_YCBCR601,
1524 : stream->timing.display_color_depth,
1525 : stream->signal);
1526 :
1527 0 : while (odm_pipe) {
1528 0 : odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
1529 : odm_pipe->stream_res.opp,
1530 : COLOR_SPACE_YCBCR601,
1531 : stream->timing.display_color_depth,
1532 : stream->signal);
1533 :
1534 0 : odm_pipe->stream_res.opp->funcs->opp_program_fmt(
1535 : odm_pipe->stream_res.opp,
1536 : &stream->bit_depth_params,
1537 : &stream->clamping);
1538 0 : odm_pipe = odm_pipe->next_odm_pipe;
1539 : }
1540 :
1541 : /* DCN3.1 FPGA Workaround
1542 : * Need to enable HPO DP Stream Encoder before setting OTG master enable.
1543 : * To do so, move calling function enable_stream_timing to only be done AFTER calling
1544 : * function core_link_enable_stream
1545 : */
1546 0 : if (!(hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)))
1547 : /* */
1548 : /* Do not touch stream timing on seamless boot optimization. */
1549 0 : if (!pipe_ctx->stream->apply_seamless_boot_optimization)
1550 0 : hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
1551 :
1552 0 : if (hws->funcs.setup_vupdate_interrupt)
1553 0 : hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
1554 :
1555 0 : params.vertical_total_min = stream->adjust.v_total_min;
1556 0 : params.vertical_total_max = stream->adjust.v_total_max;
1557 0 : if (pipe_ctx->stream_res.tg->funcs->set_drr)
1558 0 : pipe_ctx->stream_res.tg->funcs->set_drr(
1559 : pipe_ctx->stream_res.tg, ¶ms);
1560 :
1561 : // DRR should set trigger event to monitor surface update event
1562 0 : if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
1563 0 : event_triggers = 0x80;
1564 : /* Event triggers and num frames initialized for DRR, but can be
1565 : * later updated for PSR use. Note DRR trigger events are generated
1566 : * regardless of whether num frames met.
1567 : */
1568 0 : if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
1569 0 : pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
1570 : pipe_ctx->stream_res.tg, event_triggers, 2);
1571 :
1572 0 : if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
1573 0 : pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
1574 : pipe_ctx->stream_res.stream_enc,
1575 0 : pipe_ctx->stream_res.tg->inst);
1576 :
1577 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal))
1578 0 : dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
1579 :
1580 : /* Have to setup DSC before DIG FE and BE are connected (which happens before the
1581 : * link training). This is to make sure the bandwidth sent to DIG BE won't be
1582 : * bigger than what the link and/or DIG BE can handle. VBID[6]/CompressedStream_flag
1583 : * will be automatically set at a later time when the video is enabled
1584 : * (DP_VID_STREAM_EN = 1).
1585 : */
1586 0 : if (pipe_ctx->stream->timing.flags.DSC) {
1587 0 : if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
1588 0 : dc_is_virtual_signal(pipe_ctx->stream->signal))
1589 0 : dp_set_dsc_enable(pipe_ctx, true);
1590 :
1591 : }
1592 :
1593 0 : if (!stream->dpms_off) {
1594 0 : if (dc->hwss.update_phy_state)
1595 0 : dc->hwss.update_phy_state(context, pipe_ctx, TX_ON_SYMCLK_ON);
1596 : else
1597 0 : core_link_enable_stream(context, pipe_ctx);
1598 : }
1599 :
1600 : /* DCN3.1 FPGA Workaround
1601 : * Need to enable HPO DP Stream Encoder before setting OTG master enable.
1602 : * To do so, move calling function enable_stream_timing to only be done AFTER calling
1603 : * function core_link_enable_stream
1604 : */
1605 0 : if (hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)) {
1606 0 : if (!pipe_ctx->stream->apply_seamless_boot_optimization)
1607 0 : hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
1608 : }
1609 :
1610 0 : pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
1611 :
1612 0 : pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
1613 :
1614 0 : return DC_OK;
1615 : }
1616 :
1617 : /******************************************************************************/
1618 :
1619 0 : static void power_down_encoders(struct dc *dc)
1620 : {
1621 : int i;
1622 :
1623 0 : for (i = 0; i < dc->link_count; i++) {
1624 0 : enum signal_type signal = dc->links[i]->connector_signal;
1625 :
1626 0 : dc_link_blank_dp_stream(dc->links[i], false);
1627 :
1628 0 : if (signal != SIGNAL_TYPE_EDP)
1629 0 : signal = SIGNAL_TYPE_NONE;
1630 :
1631 0 : if (dc->links[i]->ep_type == DISPLAY_ENDPOINT_PHY)
1632 0 : dc->links[i]->link_enc->funcs->disable_output(
1633 : dc->links[i]->link_enc, signal);
1634 :
1635 0 : dc->links[i]->link_status.link_active = false;
1636 0 : memset(&dc->links[i]->cur_link_settings, 0,
1637 : sizeof(dc->links[i]->cur_link_settings));
1638 : }
1639 0 : }
1640 :
1641 : static void power_down_controllers(struct dc *dc)
1642 : {
1643 : int i;
1644 :
1645 0 : for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
1646 0 : dc->res_pool->timing_generators[i]->funcs->disable_crtc(
1647 : dc->res_pool->timing_generators[i]);
1648 : }
1649 : }
1650 :
1651 0 : static void power_down_clock_sources(struct dc *dc)
1652 : {
1653 : int i;
1654 :
1655 0 : if (dc->res_pool->dp_clock_source->funcs->cs_power_down(
1656 : dc->res_pool->dp_clock_source) == false)
1657 0 : dm_error("Failed to power down pll! (dp clk src)\n");
1658 :
1659 0 : for (i = 0; i < dc->res_pool->clk_src_count; i++) {
1660 0 : if (dc->res_pool->clock_sources[i]->funcs->cs_power_down(
1661 : dc->res_pool->clock_sources[i]) == false)
1662 0 : dm_error("Failed to power down pll! (clk src index=%d)\n", i);
1663 : }
1664 0 : }
1665 :
1666 0 : static void power_down_all_hw_blocks(struct dc *dc)
1667 : {
1668 0 : power_down_encoders(dc);
1669 :
1670 0 : power_down_controllers(dc);
1671 :
1672 0 : power_down_clock_sources(dc);
1673 :
1674 0 : if (dc->fbc_compressor)
1675 0 : dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
1676 0 : }
1677 :
1678 0 : static void disable_vga_and_power_gate_all_controllers(
1679 : struct dc *dc)
1680 : {
1681 : int i;
1682 : struct timing_generator *tg;
1683 0 : struct dc_context *ctx = dc->ctx;
1684 :
1685 0 : for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
1686 0 : tg = dc->res_pool->timing_generators[i];
1687 :
1688 0 : if (tg->funcs->disable_vga)
1689 0 : tg->funcs->disable_vga(tg);
1690 : }
1691 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
1692 : /* Enable CLOCK gating for each pipe BEFORE controller
1693 : * powergating. */
1694 0 : enable_display_pipe_clock_gating(ctx,
1695 : true);
1696 :
1697 0 : dc->current_state->res_ctx.pipe_ctx[i].pipe_idx = i;
1698 0 : dc->hwss.disable_plane(dc,
1699 0 : &dc->current_state->res_ctx.pipe_ctx[i]);
1700 : }
1701 0 : }
1702 :
1703 :
1704 : static void get_edp_streams(struct dc_state *context,
1705 : struct dc_stream_state **edp_streams,
1706 : int *edp_stream_num)
1707 : {
1708 : int i;
1709 :
1710 : *edp_stream_num = 0;
1711 0 : for (i = 0; i < context->stream_count; i++) {
1712 0 : if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
1713 0 : edp_streams[*edp_stream_num] = context->streams[i];
1714 0 : if (++(*edp_stream_num) == MAX_NUM_EDP)
1715 : return;
1716 : }
1717 : }
1718 : }
1719 :
1720 : static void get_edp_links_with_sink(
1721 : struct dc *dc,
1722 : struct dc_link **edp_links_with_sink,
1723 : int *edp_with_sink_num)
1724 : {
1725 : int i;
1726 :
1727 : /* check if there is an eDP panel not in use */
1728 0 : *edp_with_sink_num = 0;
1729 0 : for (i = 0; i < dc->link_count; i++) {
1730 0 : if (dc->links[i]->local_sink &&
1731 0 : dc->links[i]->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
1732 0 : edp_links_with_sink[*edp_with_sink_num] = dc->links[i];
1733 0 : if (++(*edp_with_sink_num) == MAX_NUM_EDP)
1734 : return;
1735 : }
1736 : }
1737 : }
1738 :
1739 : /*
1740 : * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need:
1741 : * 1. Power down all DC HW blocks
1742 : * 2. Disable VGA engine on all controllers
1743 : * 3. Enable power gating for controller
1744 : * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS)
1745 : */
1746 0 : void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
1747 : {
1748 : struct dc_link *edp_links_with_sink[MAX_NUM_EDP];
1749 : struct dc_link *edp_links[MAX_NUM_EDP];
1750 : struct dc_stream_state *edp_streams[MAX_NUM_EDP];
1751 0 : struct dc_link *edp_link_with_sink = NULL;
1752 0 : struct dc_link *edp_link = NULL;
1753 0 : struct dce_hwseq *hws = dc->hwseq;
1754 : int edp_with_sink_num;
1755 : int edp_num;
1756 : int edp_stream_num;
1757 : int i;
1758 0 : bool can_apply_edp_fast_boot = false;
1759 0 : bool can_apply_seamless_boot = false;
1760 0 : bool keep_edp_vdd_on = false;
1761 : DC_LOGGER_INIT();
1762 :
1763 :
1764 0 : get_edp_links_with_sink(dc, edp_links_with_sink, &edp_with_sink_num);
1765 0 : get_edp_links(dc, edp_links, &edp_num);
1766 :
1767 0 : if (hws->funcs.init_pipes)
1768 0 : hws->funcs.init_pipes(dc, context);
1769 :
1770 0 : get_edp_streams(context, edp_streams, &edp_stream_num);
1771 :
1772 : // Check fastboot support, disable on DCE8 because of blank screens
1773 0 : if (edp_num && edp_stream_num && dc->ctx->dce_version != DCE_VERSION_8_0 &&
1774 0 : dc->ctx->dce_version != DCE_VERSION_8_1 &&
1775 : dc->ctx->dce_version != DCE_VERSION_8_3) {
1776 0 : for (i = 0; i < edp_num; i++) {
1777 0 : edp_link = edp_links[i];
1778 0 : if (edp_link != edp_streams[0]->link)
1779 0 : continue;
1780 : // enable fastboot if backend is enabled on eDP
1781 0 : if (edp_link->link_enc->funcs->is_dig_enabled &&
1782 0 : edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
1783 0 : edp_link->link_status.link_active) {
1784 0 : struct dc_stream_state *edp_stream = edp_streams[0];
1785 :
1786 0 : can_apply_edp_fast_boot = dc_validate_boot_timing(dc,
1787 0 : edp_stream->sink, &edp_stream->timing);
1788 0 : edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot;
1789 0 : if (can_apply_edp_fast_boot)
1790 0 : DC_LOG_EVENT_LINK_TRAINING("eDP fast boot disabled to optimize link rate\n");
1791 :
1792 : break;
1793 : }
1794 : }
1795 : // We are trying to enable eDP, don't power down VDD
1796 0 : if (can_apply_edp_fast_boot)
1797 0 : keep_edp_vdd_on = true;
1798 : }
1799 :
1800 : // Check seamless boot support
1801 0 : for (i = 0; i < context->stream_count; i++) {
1802 0 : if (context->streams[i]->apply_seamless_boot_optimization) {
1803 : can_apply_seamless_boot = true;
1804 : break;
1805 : }
1806 : }
1807 :
1808 : /* eDP should not have stream in resume from S4 and so even with VBios post
1809 : * it should get turned off
1810 : */
1811 0 : if (edp_with_sink_num)
1812 0 : edp_link_with_sink = edp_links_with_sink[0];
1813 :
1814 0 : if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) {
1815 0 : if (edp_link_with_sink && !keep_edp_vdd_on) {
1816 : /*turn off backlight before DP_blank and encoder powered down*/
1817 0 : hws->funcs.edp_backlight_control(edp_link_with_sink, false);
1818 : }
1819 : /*resume from S3, no vbios posting, no need to power down again*/
1820 0 : power_down_all_hw_blocks(dc);
1821 0 : disable_vga_and_power_gate_all_controllers(dc);
1822 0 : if (edp_link_with_sink && !keep_edp_vdd_on)
1823 0 : dc->hwss.edp_power_control(edp_link_with_sink, false);
1824 : }
1825 0 : bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1);
1826 0 : }
1827 :
1828 : static uint32_t compute_pstate_blackout_duration(
1829 : struct bw_fixed blackout_duration,
1830 : const struct dc_stream_state *stream)
1831 : {
1832 : uint32_t total_dest_line_time_ns;
1833 : uint32_t pstate_blackout_duration_ns;
1834 :
1835 0 : pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24;
1836 :
1837 0 : total_dest_line_time_ns = 1000000UL *
1838 0 : (stream->timing.h_total * 10) /
1839 0 : stream->timing.pix_clk_100hz +
1840 : pstate_blackout_duration_ns;
1841 :
1842 : return total_dest_line_time_ns;
1843 : }
1844 :
1845 0 : static void dce110_set_displaymarks(
1846 : const struct dc *dc,
1847 : struct dc_state *context)
1848 : {
1849 : uint8_t i, num_pipes;
1850 0 : unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
1851 :
1852 0 : for (i = 0, num_pipes = 0; i < MAX_PIPES; i++) {
1853 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1854 : uint32_t total_dest_line_time_ns;
1855 :
1856 0 : if (pipe_ctx->stream == NULL)
1857 0 : continue;
1858 :
1859 0 : total_dest_line_time_ns = compute_pstate_blackout_duration(
1860 0 : dc->bw_vbios->blackout_duration, pipe_ctx->stream);
1861 0 : pipe_ctx->plane_res.mi->funcs->mem_input_program_display_marks(
1862 : pipe_ctx->plane_res.mi,
1863 : context->bw_ctx.bw.dce.nbp_state_change_wm_ns[num_pipes],
1864 : context->bw_ctx.bw.dce.stutter_exit_wm_ns[num_pipes],
1865 : context->bw_ctx.bw.dce.stutter_entry_wm_ns[num_pipes],
1866 : context->bw_ctx.bw.dce.urgent_wm_ns[num_pipes],
1867 : total_dest_line_time_ns);
1868 0 : if (i == underlay_idx) {
1869 0 : num_pipes++;
1870 0 : pipe_ctx->plane_res.mi->funcs->mem_input_program_chroma_display_marks(
1871 : pipe_ctx->plane_res.mi,
1872 : context->bw_ctx.bw.dce.nbp_state_change_wm_ns[num_pipes],
1873 : context->bw_ctx.bw.dce.stutter_exit_wm_ns[num_pipes],
1874 : context->bw_ctx.bw.dce.urgent_wm_ns[num_pipes],
1875 : total_dest_line_time_ns);
1876 : }
1877 0 : num_pipes++;
1878 : }
1879 0 : }
1880 :
1881 0 : void dce110_set_safe_displaymarks(
1882 : struct resource_context *res_ctx,
1883 : const struct resource_pool *pool)
1884 : {
1885 : int i;
1886 0 : int underlay_idx = pool->underlay_pipe_index;
1887 0 : struct dce_watermarks max_marks = {
1888 : MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK };
1889 0 : struct dce_watermarks nbp_marks = {
1890 : SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK };
1891 0 : struct dce_watermarks min_marks = { 0, 0, 0, 0};
1892 :
1893 0 : for (i = 0; i < MAX_PIPES; i++) {
1894 0 : if (res_ctx->pipe_ctx[i].stream == NULL || res_ctx->pipe_ctx[i].plane_res.mi == NULL)
1895 0 : continue;
1896 :
1897 0 : res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_display_marks(
1898 : res_ctx->pipe_ctx[i].plane_res.mi,
1899 : nbp_marks,
1900 : max_marks,
1901 : min_marks,
1902 : max_marks,
1903 : MAX_WATERMARK);
1904 :
1905 0 : if (i == underlay_idx)
1906 0 : res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_chroma_display_marks(
1907 : res_ctx->pipe_ctx[i].plane_res.mi,
1908 : nbp_marks,
1909 : max_marks,
1910 : max_marks,
1911 : MAX_WATERMARK);
1912 :
1913 : }
1914 0 : }
1915 :
1916 : /*******************************************************************************
1917 : * Public functions
1918 : ******************************************************************************/
1919 :
1920 0 : static void set_drr(struct pipe_ctx **pipe_ctx,
1921 : int num_pipes, struct dc_crtc_timing_adjust adjust)
1922 : {
1923 0 : int i = 0;
1924 0 : struct drr_params params = {0};
1925 : // DRR should set trigger event to monitor surface update event
1926 0 : unsigned int event_triggers = 0x80;
1927 : // Note DRR trigger events are generated regardless of whether num frames met.
1928 0 : unsigned int num_frames = 2;
1929 :
1930 0 : params.vertical_total_max = adjust.v_total_max;
1931 0 : params.vertical_total_min = adjust.v_total_min;
1932 :
1933 : /* TODO: If multiple pipes are to be supported, you need
1934 : * some GSL stuff. Static screen triggers may be programmed differently
1935 : * as well.
1936 : */
1937 0 : for (i = 0; i < num_pipes; i++) {
1938 0 : pipe_ctx[i]->stream_res.tg->funcs->set_drr(
1939 : pipe_ctx[i]->stream_res.tg, ¶ms);
1940 :
1941 0 : if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
1942 0 : pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
1943 : pipe_ctx[i]->stream_res.tg,
1944 : event_triggers, num_frames);
1945 : }
1946 0 : }
1947 :
1948 0 : static void get_position(struct pipe_ctx **pipe_ctx,
1949 : int num_pipes,
1950 : struct crtc_position *position)
1951 : {
1952 0 : int i = 0;
1953 :
1954 : /* TODO: handle pipes > 1
1955 : */
1956 0 : for (i = 0; i < num_pipes; i++)
1957 0 : pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position);
1958 0 : }
1959 :
1960 0 : static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
1961 : int num_pipes, const struct dc_static_screen_params *params)
1962 : {
1963 : unsigned int i;
1964 0 : unsigned int triggers = 0;
1965 :
1966 0 : if (params->triggers.overlay_update)
1967 0 : triggers |= 0x100;
1968 0 : if (params->triggers.surface_update)
1969 0 : triggers |= 0x80;
1970 0 : if (params->triggers.cursor_update)
1971 0 : triggers |= 0x2;
1972 0 : if (params->triggers.force_trigger)
1973 0 : triggers |= 0x1;
1974 :
1975 0 : if (num_pipes) {
1976 0 : struct dc *dc = pipe_ctx[0]->stream->ctx->dc;
1977 :
1978 0 : if (dc->fbc_compressor)
1979 0 : triggers |= 0x84;
1980 : }
1981 :
1982 0 : for (i = 0; i < num_pipes; i++)
1983 0 : pipe_ctx[i]->stream_res.tg->funcs->
1984 : set_static_screen_control(pipe_ctx[i]->stream_res.tg,
1985 : triggers, params->num_frames);
1986 0 : }
1987 :
1988 : /*
1989 : * Check if FBC can be enabled
1990 : */
1991 0 : static bool should_enable_fbc(struct dc *dc,
1992 : struct dc_state *context,
1993 : uint32_t *pipe_idx)
1994 : {
1995 : uint32_t i;
1996 0 : struct pipe_ctx *pipe_ctx = NULL;
1997 0 : struct resource_context *res_ctx = &context->res_ctx;
1998 0 : unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
1999 :
2000 :
2001 0 : ASSERT(dc->fbc_compressor);
2002 :
2003 : /* FBC memory should be allocated */
2004 0 : if (!dc->ctx->fbc_gpu_addr)
2005 : return false;
2006 :
2007 : /* Only supports single display */
2008 0 : if (context->stream_count != 1)
2009 : return false;
2010 :
2011 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2012 0 : if (res_ctx->pipe_ctx[i].stream) {
2013 :
2014 0 : pipe_ctx = &res_ctx->pipe_ctx[i];
2015 :
2016 0 : if (!pipe_ctx)
2017 0 : continue;
2018 :
2019 : /* fbc not applicable on underlay pipe */
2020 0 : if (pipe_ctx->pipe_idx != underlay_idx) {
2021 0 : *pipe_idx = i;
2022 0 : break;
2023 : }
2024 : }
2025 : }
2026 :
2027 0 : if (i == dc->res_pool->pipe_count)
2028 : return false;
2029 :
2030 0 : if (!pipe_ctx->stream->link)
2031 : return false;
2032 :
2033 : /* Only supports eDP */
2034 0 : if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP)
2035 : return false;
2036 :
2037 : /* PSR should not be enabled */
2038 0 : if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled)
2039 : return false;
2040 :
2041 : /* Nothing to compress */
2042 0 : if (!pipe_ctx->plane_state)
2043 : return false;
2044 :
2045 : /* Only for non-linear tiling */
2046 0 : if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL)
2047 : return false;
2048 :
2049 0 : return true;
2050 : }
2051 :
2052 : /*
2053 : * Enable FBC
2054 : */
2055 0 : static void enable_fbc(
2056 : struct dc *dc,
2057 : struct dc_state *context)
2058 : {
2059 0 : uint32_t pipe_idx = 0;
2060 :
2061 0 : if (should_enable_fbc(dc, context, &pipe_idx)) {
2062 : /* Program GRPH COMPRESSED ADDRESS and PITCH */
2063 : struct compr_addr_and_pitch_params params = {0, 0, 0};
2064 0 : struct compressor *compr = dc->fbc_compressor;
2065 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
2066 :
2067 0 : params.source_view_width = pipe_ctx->stream->timing.h_addressable;
2068 0 : params.source_view_height = pipe_ctx->stream->timing.v_addressable;
2069 0 : params.inst = pipe_ctx->stream_res.tg->inst;
2070 0 : compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr;
2071 :
2072 0 : compr->funcs->surface_address_and_pitch(compr, ¶ms);
2073 0 : compr->funcs->set_fbc_invalidation_triggers(compr, 1);
2074 :
2075 0 : compr->funcs->enable_fbc(compr, ¶ms);
2076 : }
2077 0 : }
2078 :
2079 0 : static void dce110_reset_hw_ctx_wrap(
2080 : struct dc *dc,
2081 : struct dc_state *context)
2082 : {
2083 : int i;
2084 :
2085 : /* Reset old context */
2086 : /* look up the targets that have been removed since last commit */
2087 0 : for (i = 0; i < MAX_PIPES; i++) {
2088 0 : struct pipe_ctx *pipe_ctx_old =
2089 0 : &dc->current_state->res_ctx.pipe_ctx[i];
2090 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2091 :
2092 : /* Note: We need to disable output if clock sources change,
2093 : * since bios does optimization and doesn't apply if changing
2094 : * PHY when not already disabled.
2095 : */
2096 :
2097 : /* Skip underlay pipe since it will be handled in commit surface*/
2098 0 : if (!pipe_ctx_old->stream || pipe_ctx_old->top_pipe)
2099 0 : continue;
2100 :
2101 0 : if (!pipe_ctx->stream ||
2102 0 : pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
2103 0 : struct clock_source *old_clk = pipe_ctx_old->clock_source;
2104 :
2105 : /* Disable if new stream is null. O/w, if stream is
2106 : * disabled already, no need to disable again.
2107 : */
2108 0 : if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) {
2109 0 : core_link_disable_stream(pipe_ctx_old);
2110 :
2111 : /* free acquired resources*/
2112 0 : if (pipe_ctx_old->stream_res.audio) {
2113 : /*disable az_endpoint*/
2114 0 : pipe_ctx_old->stream_res.audio->funcs->
2115 : az_disable(pipe_ctx_old->stream_res.audio);
2116 :
2117 : /*free audio*/
2118 0 : if (dc->caps.dynamic_audio == true) {
2119 : /*we have to dynamic arbitrate the audio endpoints*/
2120 : /*we free the resource, need reset is_audio_acquired*/
2121 0 : update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
2122 : pipe_ctx_old->stream_res.audio, false);
2123 0 : pipe_ctx_old->stream_res.audio = NULL;
2124 : }
2125 : }
2126 : }
2127 :
2128 0 : pipe_ctx_old->stream_res.tg->funcs->set_blank(pipe_ctx_old->stream_res.tg, true);
2129 0 : if (!hwss_wait_for_blank_complete(pipe_ctx_old->stream_res.tg)) {
2130 0 : dm_error("DC: failed to blank crtc!\n");
2131 0 : BREAK_TO_DEBUGGER();
2132 : }
2133 0 : pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg);
2134 0 : pipe_ctx_old->plane_res.mi->funcs->free_mem_input(
2135 0 : pipe_ctx_old->plane_res.mi, dc->current_state->stream_count);
2136 :
2137 0 : if (old_clk && 0 == resource_get_clock_source_reference(&context->res_ctx,
2138 0 : dc->res_pool,
2139 : old_clk))
2140 0 : old_clk->funcs->cs_power_down(old_clk);
2141 :
2142 0 : dc->hwss.disable_plane(dc, pipe_ctx_old);
2143 :
2144 0 : pipe_ctx_old->stream = NULL;
2145 : }
2146 : }
2147 0 : }
2148 :
2149 0 : static void dce110_setup_audio_dto(
2150 : struct dc *dc,
2151 : struct dc_state *context)
2152 : {
2153 : int i;
2154 :
2155 : /* program audio wall clock. use HDMI as clock source if HDMI
2156 : * audio active. Otherwise, use DP as clock source
2157 : * first, loop to find any HDMI audio, if not, loop find DP audio
2158 : */
2159 : /* Setup audio rate clock source */
2160 : /* Issue:
2161 : * Audio lag happened on DP monitor when unplug a HDMI monitor
2162 : *
2163 : * Cause:
2164 : * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL
2165 : * is set to either dto0 or dto1, audio should work fine.
2166 : * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1,
2167 : * set to dto0 will cause audio lag.
2168 : *
2169 : * Solution:
2170 : * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx,
2171 : * find first available pipe with audio, setup audio wall DTO per topology
2172 : * instead of per pipe.
2173 : */
2174 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2175 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2176 :
2177 0 : if (pipe_ctx->stream == NULL)
2178 0 : continue;
2179 :
2180 0 : if (pipe_ctx->top_pipe)
2181 0 : continue;
2182 0 : if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A)
2183 0 : continue;
2184 0 : if (pipe_ctx->stream_res.audio != NULL) {
2185 : struct audio_output audio_output;
2186 :
2187 0 : build_audio_output(context, pipe_ctx, &audio_output);
2188 :
2189 0 : if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
2190 0 : struct dtbclk_dto_params dto_params = {0};
2191 :
2192 0 : dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
2193 : dc->res_pool->dccg, &dto_params);
2194 :
2195 0 : pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
2196 : pipe_ctx->stream_res.audio,
2197 0 : pipe_ctx->stream->signal,
2198 : &audio_output.crtc_info,
2199 : &audio_output.pll_info);
2200 : } else
2201 0 : pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
2202 : pipe_ctx->stream_res.audio,
2203 0 : pipe_ctx->stream->signal,
2204 : &audio_output.crtc_info,
2205 : &audio_output.pll_info);
2206 : break;
2207 : }
2208 : }
2209 :
2210 : /* no HDMI audio is found, try DP audio */
2211 0 : if (i == dc->res_pool->pipe_count) {
2212 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2213 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2214 :
2215 0 : if (pipe_ctx->stream == NULL)
2216 0 : continue;
2217 :
2218 0 : if (pipe_ctx->top_pipe)
2219 0 : continue;
2220 :
2221 0 : if (!dc_is_dp_signal(pipe_ctx->stream->signal))
2222 0 : continue;
2223 :
2224 0 : if (pipe_ctx->stream_res.audio != NULL) {
2225 : struct audio_output audio_output;
2226 :
2227 0 : build_audio_output(context, pipe_ctx, &audio_output);
2228 :
2229 0 : pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
2230 : pipe_ctx->stream_res.audio,
2231 0 : pipe_ctx->stream->signal,
2232 : &audio_output.crtc_info,
2233 : &audio_output.pll_info);
2234 : break;
2235 : }
2236 : }
2237 : }
2238 0 : }
2239 :
2240 0 : enum dc_status dce110_apply_ctx_to_hw(
2241 : struct dc *dc,
2242 : struct dc_state *context)
2243 : {
2244 0 : struct dce_hwseq *hws = dc->hwseq;
2245 0 : struct dc_bios *dcb = dc->ctx->dc_bios;
2246 : enum dc_status status;
2247 : int i;
2248 :
2249 : /* reset syncd pipes from disabled pipes */
2250 0 : if (dc->config.use_pipe_ctx_sync_logic)
2251 0 : reset_syncd_pipes_from_disabled_pipes(dc, context);
2252 :
2253 : /* Reset old context */
2254 : /* look up the targets that have been removed since last commit */
2255 0 : hws->funcs.reset_hw_ctx_wrap(dc, context);
2256 :
2257 : /* Skip applying if no targets */
2258 0 : if (context->stream_count <= 0)
2259 : return DC_OK;
2260 :
2261 : /* Apply new context */
2262 0 : dcb->funcs->set_scratch_critical_state(dcb, true);
2263 :
2264 : /* below is for real asic only */
2265 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2266 0 : struct pipe_ctx *pipe_ctx_old =
2267 0 : &dc->current_state->res_ctx.pipe_ctx[i];
2268 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2269 :
2270 0 : if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
2271 0 : continue;
2272 :
2273 0 : if (pipe_ctx->stream == pipe_ctx_old->stream) {
2274 0 : if (pipe_ctx_old->clock_source != pipe_ctx->clock_source)
2275 0 : dce_crtc_switch_to_clk_src(dc->hwseq,
2276 : pipe_ctx->clock_source, i);
2277 0 : continue;
2278 : }
2279 :
2280 0 : hws->funcs.enable_display_power_gating(
2281 0 : dc, i, dc->ctx->dc_bios,
2282 : PIPE_GATING_CONTROL_DISABLE);
2283 : }
2284 :
2285 0 : if (dc->fbc_compressor)
2286 0 : dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
2287 :
2288 0 : dce110_setup_audio_dto(dc, context);
2289 :
2290 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2291 0 : struct pipe_ctx *pipe_ctx_old =
2292 0 : &dc->current_state->res_ctx.pipe_ctx[i];
2293 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2294 :
2295 0 : if (pipe_ctx->stream == NULL)
2296 0 : continue;
2297 :
2298 0 : if (pipe_ctx->stream == pipe_ctx_old->stream &&
2299 0 : pipe_ctx->stream->link->link_state_valid) {
2300 0 : continue;
2301 : }
2302 :
2303 0 : if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
2304 0 : continue;
2305 :
2306 0 : if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
2307 0 : continue;
2308 :
2309 0 : status = apply_single_controller_ctx_to_hw(
2310 : pipe_ctx,
2311 : context,
2312 : dc);
2313 :
2314 0 : if (DC_OK != status)
2315 : return status;
2316 : }
2317 :
2318 0 : if (dc->fbc_compressor)
2319 0 : enable_fbc(dc, dc->current_state);
2320 :
2321 0 : dcb->funcs->set_scratch_critical_state(dcb, false);
2322 :
2323 0 : return DC_OK;
2324 : }
2325 :
2326 : /*******************************************************************************
2327 : * Front End programming
2328 : ******************************************************************************/
2329 0 : static void set_default_colors(struct pipe_ctx *pipe_ctx)
2330 : {
2331 0 : struct default_adjustment default_adjust = { 0 };
2332 :
2333 : default_adjust.force_hw_default = false;
2334 0 : default_adjust.in_color_space = pipe_ctx->plane_state->color_space;
2335 0 : default_adjust.out_color_space = pipe_ctx->stream->output_color_space;
2336 0 : default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW;
2337 0 : default_adjust.surface_pixel_format = pipe_ctx->plane_res.scl_data.format;
2338 :
2339 : /* display color depth */
2340 0 : default_adjust.color_depth =
2341 0 : pipe_ctx->stream->timing.display_color_depth;
2342 :
2343 : /* Lb color depth */
2344 0 : default_adjust.lb_color_depth = pipe_ctx->plane_res.scl_data.lb_params.depth;
2345 :
2346 0 : pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default(
2347 : pipe_ctx->plane_res.xfm, &default_adjust);
2348 0 : }
2349 :
2350 :
2351 : /*******************************************************************************
2352 : * In order to turn on/off specific surface we will program
2353 : * Blender + CRTC
2354 : *
2355 : * In case that we have two surfaces and they have a different visibility
2356 : * we can't turn off the CRTC since it will turn off the entire display
2357 : *
2358 : * |----------------------------------------------- |
2359 : * |bottom pipe|curr pipe | | |
2360 : * |Surface |Surface | Blender | CRCT |
2361 : * |visibility |visibility | Configuration| |
2362 : * |------------------------------------------------|
2363 : * | off | off | CURRENT_PIPE | blank |
2364 : * | off | on | CURRENT_PIPE | unblank |
2365 : * | on | off | OTHER_PIPE | unblank |
2366 : * | on | on | BLENDING | unblank |
2367 : * -------------------------------------------------|
2368 : *
2369 : ******************************************************************************/
2370 0 : static void program_surface_visibility(const struct dc *dc,
2371 : struct pipe_ctx *pipe_ctx)
2372 : {
2373 0 : enum blnd_mode blender_mode = BLND_MODE_CURRENT_PIPE;
2374 0 : bool blank_target = false;
2375 :
2376 0 : if (pipe_ctx->bottom_pipe) {
2377 :
2378 : /* For now we are supporting only two pipes */
2379 0 : ASSERT(pipe_ctx->bottom_pipe->bottom_pipe == NULL);
2380 :
2381 0 : if (pipe_ctx->bottom_pipe->plane_state->visible) {
2382 0 : if (pipe_ctx->plane_state->visible)
2383 : blender_mode = BLND_MODE_BLENDING;
2384 : else
2385 0 : blender_mode = BLND_MODE_OTHER_PIPE;
2386 :
2387 0 : } else if (!pipe_ctx->plane_state->visible)
2388 0 : blank_target = true;
2389 :
2390 0 : } else if (!pipe_ctx->plane_state->visible)
2391 0 : blank_target = true;
2392 :
2393 0 : dce_set_blender_mode(dc->hwseq, pipe_ctx->stream_res.tg->inst, blender_mode);
2394 0 : pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target);
2395 :
2396 0 : }
2397 :
2398 0 : static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
2399 : {
2400 0 : int i = 0;
2401 : struct xfm_grph_csc_adjustment adjust;
2402 0 : memset(&adjust, 0, sizeof(adjust));
2403 0 : adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
2404 :
2405 :
2406 0 : if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
2407 0 : adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
2408 :
2409 0 : for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
2410 0 : adjust.temperature_matrix[i] =
2411 : pipe_ctx->stream->gamut_remap_matrix.matrix[i];
2412 : }
2413 :
2414 0 : pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust);
2415 0 : }
2416 0 : static void update_plane_addr(const struct dc *dc,
2417 : struct pipe_ctx *pipe_ctx)
2418 : {
2419 0 : struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2420 :
2421 0 : if (plane_state == NULL)
2422 : return;
2423 :
2424 0 : pipe_ctx->plane_res.mi->funcs->mem_input_program_surface_flip_and_addr(
2425 : pipe_ctx->plane_res.mi,
2426 0 : &plane_state->address,
2427 0 : plane_state->flip_immediate);
2428 :
2429 0 : plane_state->status.requested_address = plane_state->address;
2430 : }
2431 :
2432 0 : static void dce110_update_pending_status(struct pipe_ctx *pipe_ctx)
2433 : {
2434 0 : struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2435 :
2436 0 : if (plane_state == NULL)
2437 : return;
2438 :
2439 0 : plane_state->status.is_flip_pending =
2440 0 : pipe_ctx->plane_res.mi->funcs->mem_input_is_flip_pending(
2441 : pipe_ctx->plane_res.mi);
2442 :
2443 0 : if (plane_state->status.is_flip_pending && !plane_state->visible)
2444 0 : pipe_ctx->plane_res.mi->current_address = pipe_ctx->plane_res.mi->request_address;
2445 :
2446 0 : plane_state->status.current_address = pipe_ctx->plane_res.mi->current_address;
2447 0 : if (pipe_ctx->plane_res.mi->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2448 0 : pipe_ctx->stream_res.tg->funcs->is_stereo_left_eye) {
2449 0 : plane_state->status.is_right_eye =\
2450 0 : !pipe_ctx->stream_res.tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg);
2451 : }
2452 : }
2453 :
2454 0 : void dce110_power_down(struct dc *dc)
2455 : {
2456 0 : power_down_all_hw_blocks(dc);
2457 0 : disable_vga_and_power_gate_all_controllers(dc);
2458 0 : }
2459 :
2460 0 : static bool wait_for_reset_trigger_to_occur(
2461 : struct dc_context *dc_ctx,
2462 : struct timing_generator *tg)
2463 : {
2464 0 : bool rc = false;
2465 :
2466 : /* To avoid endless loop we wait at most
2467 : * frames_to_wait_on_triggered_reset frames for the reset to occur. */
2468 0 : const uint32_t frames_to_wait_on_triggered_reset = 10;
2469 : uint32_t i;
2470 :
2471 0 : for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
2472 :
2473 0 : if (!tg->funcs->is_counter_moving(tg)) {
2474 0 : DC_ERROR("TG counter is not moving!\n");
2475 : break;
2476 : }
2477 :
2478 0 : if (tg->funcs->did_triggered_reset_occur(tg)) {
2479 0 : rc = true;
2480 : /* usually occurs at i=1 */
2481 0 : DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
2482 : i);
2483 : break;
2484 : }
2485 :
2486 : /* Wait for one frame. */
2487 0 : tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
2488 0 : tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
2489 : }
2490 :
2491 0 : if (false == rc)
2492 0 : DC_ERROR("GSL: Timeout on reset trigger!\n");
2493 :
2494 0 : return rc;
2495 : }
2496 :
2497 : /* Enable timing synchronization for a group of Timing Generators. */
2498 0 : static void dce110_enable_timing_synchronization(
2499 : struct dc *dc,
2500 : int group_index,
2501 : int group_size,
2502 : struct pipe_ctx *grouped_pipes[])
2503 : {
2504 0 : struct dc_context *dc_ctx = dc->ctx;
2505 0 : struct dcp_gsl_params gsl_params = { 0 };
2506 : int i;
2507 :
2508 0 : DC_SYNC_INFO("GSL: Setting-up...\n");
2509 :
2510 : /* Designate a single TG in the group as a master.
2511 : * Since HW doesn't care which one, we always assign
2512 : * the 1st one in the group. */
2513 0 : gsl_params.gsl_group = 0;
2514 0 : gsl_params.gsl_master = grouped_pipes[0]->stream_res.tg->inst;
2515 :
2516 0 : for (i = 0; i < group_size; i++)
2517 0 : grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock(
2518 : grouped_pipes[i]->stream_res.tg, &gsl_params);
2519 :
2520 : /* Reset slave controllers on master VSync */
2521 0 : DC_SYNC_INFO("GSL: enabling trigger-reset\n");
2522 :
2523 0 : for (i = 1 /* skip the master */; i < group_size; i++)
2524 0 : grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger(
2525 : grouped_pipes[i]->stream_res.tg,
2526 : gsl_params.gsl_group);
2527 :
2528 0 : for (i = 1 /* skip the master */; i < group_size; i++) {
2529 0 : DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
2530 0 : wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
2531 0 : grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(
2532 : grouped_pipes[i]->stream_res.tg);
2533 : }
2534 :
2535 : /* GSL Vblank synchronization is a one time sync mechanism, assumption
2536 : * is that the sync'ed displays will not drift out of sync over time*/
2537 0 : DC_SYNC_INFO("GSL: Restoring register states.\n");
2538 0 : for (i = 0; i < group_size; i++)
2539 0 : grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg);
2540 :
2541 0 : DC_SYNC_INFO("GSL: Set-up complete.\n");
2542 0 : }
2543 :
2544 0 : static void dce110_enable_per_frame_crtc_position_reset(
2545 : struct dc *dc,
2546 : int group_size,
2547 : struct pipe_ctx *grouped_pipes[])
2548 : {
2549 0 : struct dc_context *dc_ctx = dc->ctx;
2550 0 : struct dcp_gsl_params gsl_params = { 0 };
2551 : int i;
2552 :
2553 : gsl_params.gsl_group = 0;
2554 : gsl_params.gsl_master = 0;
2555 :
2556 0 : for (i = 0; i < group_size; i++)
2557 0 : grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock(
2558 : grouped_pipes[i]->stream_res.tg, &gsl_params);
2559 :
2560 0 : DC_SYNC_INFO("GSL: enabling trigger-reset\n");
2561 :
2562 0 : for (i = 1; i < group_size; i++)
2563 0 : grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
2564 : grouped_pipes[i]->stream_res.tg,
2565 : gsl_params.gsl_master,
2566 0 : &grouped_pipes[i]->stream->triggered_crtc_reset);
2567 :
2568 0 : DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
2569 0 : for (i = 1; i < group_size; i++)
2570 0 : wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
2571 :
2572 0 : for (i = 0; i < group_size; i++)
2573 0 : grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg);
2574 :
2575 0 : }
2576 :
2577 0 : static void init_pipes(struct dc *dc, struct dc_state *context)
2578 : {
2579 : // Do nothing
2580 0 : }
2581 :
2582 0 : static void init_hw(struct dc *dc)
2583 : {
2584 : int i;
2585 : struct dc_bios *bp;
2586 : struct transform *xfm;
2587 : struct abm *abm;
2588 : struct dmcu *dmcu;
2589 0 : struct dce_hwseq *hws = dc->hwseq;
2590 0 : uint32_t backlight = MAX_BACKLIGHT_LEVEL;
2591 :
2592 0 : bp = dc->ctx->dc_bios;
2593 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2594 0 : xfm = dc->res_pool->transforms[i];
2595 0 : xfm->funcs->transform_reset(xfm);
2596 :
2597 0 : hws->funcs.enable_display_power_gating(
2598 : dc, i, bp,
2599 : PIPE_GATING_CONTROL_INIT);
2600 0 : hws->funcs.enable_display_power_gating(
2601 : dc, i, bp,
2602 : PIPE_GATING_CONTROL_DISABLE);
2603 0 : hws->funcs.enable_display_pipe_clock_gating(
2604 : dc->ctx,
2605 : true);
2606 : }
2607 :
2608 0 : dce_clock_gating_power_up(dc->hwseq, false);
2609 : /***************************************/
2610 :
2611 0 : for (i = 0; i < dc->link_count; i++) {
2612 : /****************************************/
2613 : /* Power up AND update implementation according to the
2614 : * required signal (which may be different from the
2615 : * default signal on connector). */
2616 0 : struct dc_link *link = dc->links[i];
2617 :
2618 0 : link->link_enc->funcs->hw_init(link->link_enc);
2619 : }
2620 :
2621 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2622 0 : struct timing_generator *tg = dc->res_pool->timing_generators[i];
2623 :
2624 0 : tg->funcs->disable_vga(tg);
2625 :
2626 : /* Blank controller using driver code instead of
2627 : * command table. */
2628 0 : tg->funcs->set_blank(tg, true);
2629 0 : hwss_wait_for_blank_complete(tg);
2630 : }
2631 :
2632 0 : for (i = 0; i < dc->res_pool->audio_count; i++) {
2633 0 : struct audio *audio = dc->res_pool->audios[i];
2634 0 : audio->funcs->hw_init(audio);
2635 : }
2636 :
2637 0 : for (i = 0; i < dc->link_count; i++) {
2638 0 : struct dc_link *link = dc->links[i];
2639 :
2640 0 : if (link->panel_cntl)
2641 0 : backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
2642 : }
2643 :
2644 0 : abm = dc->res_pool->abm;
2645 0 : if (abm != NULL)
2646 0 : abm->funcs->abm_init(abm, backlight);
2647 :
2648 0 : dmcu = dc->res_pool->dmcu;
2649 0 : if (dmcu != NULL && abm != NULL)
2650 0 : abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu);
2651 :
2652 0 : if (dc->fbc_compressor)
2653 0 : dc->fbc_compressor->funcs->power_up_fbc(dc->fbc_compressor);
2654 :
2655 0 : }
2656 :
2657 :
2658 0 : void dce110_prepare_bandwidth(
2659 : struct dc *dc,
2660 : struct dc_state *context)
2661 : {
2662 0 : struct clk_mgr *dccg = dc->clk_mgr;
2663 :
2664 0 : dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
2665 :
2666 0 : dccg->funcs->update_clocks(
2667 : dccg,
2668 : context,
2669 : false);
2670 0 : }
2671 :
2672 0 : void dce110_optimize_bandwidth(
2673 : struct dc *dc,
2674 : struct dc_state *context)
2675 : {
2676 0 : struct clk_mgr *dccg = dc->clk_mgr;
2677 :
2678 0 : dce110_set_displaymarks(dc, context);
2679 :
2680 0 : dccg->funcs->update_clocks(
2681 : dccg,
2682 : context,
2683 : true);
2684 0 : }
2685 :
2686 0 : static void dce110_program_front_end_for_pipe(
2687 : struct dc *dc, struct pipe_ctx *pipe_ctx)
2688 : {
2689 0 : struct mem_input *mi = pipe_ctx->plane_res.mi;
2690 0 : struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2691 : struct xfm_grph_csc_adjustment adjust;
2692 : struct out_csc_color_matrix tbl_entry;
2693 : unsigned int i;
2694 0 : struct dce_hwseq *hws = dc->hwseq;
2695 :
2696 : DC_LOGGER_INIT();
2697 0 : memset(&tbl_entry, 0, sizeof(tbl_entry));
2698 :
2699 0 : memset(&adjust, 0, sizeof(adjust));
2700 0 : adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
2701 :
2702 0 : dce_enable_fe_clock(dc->hwseq, mi->inst, true);
2703 :
2704 0 : set_default_colors(pipe_ctx);
2705 0 : if (pipe_ctx->stream->csc_color_matrix.enable_adjustment
2706 : == true) {
2707 0 : tbl_entry.color_space =
2708 0 : pipe_ctx->stream->output_color_space;
2709 :
2710 0 : for (i = 0; i < 12; i++)
2711 0 : tbl_entry.regval[i] =
2712 0 : pipe_ctx->stream->csc_color_matrix.matrix[i];
2713 :
2714 0 : pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment
2715 : (pipe_ctx->plane_res.xfm, &tbl_entry);
2716 : }
2717 :
2718 0 : if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
2719 0 : adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
2720 :
2721 0 : for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
2722 0 : adjust.temperature_matrix[i] =
2723 : pipe_ctx->stream->gamut_remap_matrix.matrix[i];
2724 : }
2725 :
2726 0 : pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust);
2727 :
2728 0 : pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
2729 :
2730 0 : program_scaler(dc, pipe_ctx);
2731 :
2732 0 : mi->funcs->mem_input_program_surface_config(
2733 : mi,
2734 : plane_state->format,
2735 : &plane_state->tiling_info,
2736 : &plane_state->plane_size,
2737 : plane_state->rotation,
2738 : NULL,
2739 : false);
2740 0 : if (mi->funcs->set_blank)
2741 0 : mi->funcs->set_blank(mi, pipe_ctx->plane_state->visible);
2742 :
2743 0 : if (dc->config.gpu_vm_support)
2744 0 : mi->funcs->mem_input_program_pte_vm(
2745 : pipe_ctx->plane_res.mi,
2746 : plane_state->format,
2747 : &plane_state->tiling_info,
2748 : plane_state->rotation);
2749 :
2750 : /* Moved programming gamma from dc to hwss */
2751 0 : if (pipe_ctx->plane_state->update_flags.bits.full_update ||
2752 0 : pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
2753 : pipe_ctx->plane_state->update_flags.bits.gamma_change)
2754 0 : hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
2755 :
2756 0 : if (pipe_ctx->plane_state->update_flags.bits.full_update)
2757 0 : hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
2758 :
2759 : DC_LOG_SURFACE(
2760 : "Pipe:%d %p: addr hi:0x%x, "
2761 : "addr low:0x%x, "
2762 : "src: %d, %d, %d,"
2763 : " %d; dst: %d, %d, %d, %d;"
2764 : "clip: %d, %d, %d, %d\n",
2765 : pipe_ctx->pipe_idx,
2766 : (void *) pipe_ctx->plane_state,
2767 : pipe_ctx->plane_state->address.grph.addr.high_part,
2768 : pipe_ctx->plane_state->address.grph.addr.low_part,
2769 : pipe_ctx->plane_state->src_rect.x,
2770 : pipe_ctx->plane_state->src_rect.y,
2771 : pipe_ctx->plane_state->src_rect.width,
2772 : pipe_ctx->plane_state->src_rect.height,
2773 : pipe_ctx->plane_state->dst_rect.x,
2774 : pipe_ctx->plane_state->dst_rect.y,
2775 : pipe_ctx->plane_state->dst_rect.width,
2776 : pipe_ctx->plane_state->dst_rect.height,
2777 : pipe_ctx->plane_state->clip_rect.x,
2778 : pipe_ctx->plane_state->clip_rect.y,
2779 : pipe_ctx->plane_state->clip_rect.width,
2780 : pipe_ctx->plane_state->clip_rect.height);
2781 :
2782 : DC_LOG_SURFACE(
2783 : "Pipe %d: width, height, x, y\n"
2784 : "viewport:%d, %d, %d, %d\n"
2785 : "recout: %d, %d, %d, %d\n",
2786 : pipe_ctx->pipe_idx,
2787 : pipe_ctx->plane_res.scl_data.viewport.width,
2788 : pipe_ctx->plane_res.scl_data.viewport.height,
2789 : pipe_ctx->plane_res.scl_data.viewport.x,
2790 : pipe_ctx->plane_res.scl_data.viewport.y,
2791 : pipe_ctx->plane_res.scl_data.recout.width,
2792 : pipe_ctx->plane_res.scl_data.recout.height,
2793 : pipe_ctx->plane_res.scl_data.recout.x,
2794 : pipe_ctx->plane_res.scl_data.recout.y);
2795 0 : }
2796 :
2797 0 : static void dce110_apply_ctx_for_surface(
2798 : struct dc *dc,
2799 : const struct dc_stream_state *stream,
2800 : int num_planes,
2801 : struct dc_state *context)
2802 : {
2803 : int i;
2804 :
2805 0 : if (num_planes == 0)
2806 : return;
2807 :
2808 0 : if (dc->fbc_compressor)
2809 0 : dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
2810 :
2811 0 : for (i = 0; i < dc->res_pool->pipe_count; i++) {
2812 0 : struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2813 :
2814 0 : if (pipe_ctx->stream != stream)
2815 0 : continue;
2816 :
2817 : /* Need to allocate mem before program front end for Fiji */
2818 0 : pipe_ctx->plane_res.mi->funcs->allocate_mem_input(
2819 : pipe_ctx->plane_res.mi,
2820 : pipe_ctx->stream->timing.h_total,
2821 : pipe_ctx->stream->timing.v_total,
2822 0 : pipe_ctx->stream->timing.pix_clk_100hz / 10,
2823 0 : context->stream_count);
2824 :
2825 0 : dce110_program_front_end_for_pipe(dc, pipe_ctx);
2826 :
2827 0 : dc->hwss.update_plane_addr(dc, pipe_ctx);
2828 :
2829 0 : program_surface_visibility(dc, pipe_ctx);
2830 :
2831 : }
2832 :
2833 0 : if (dc->fbc_compressor)
2834 0 : enable_fbc(dc, context);
2835 : }
2836 :
2837 0 : static void dce110_post_unlock_program_front_end(
2838 : struct dc *dc,
2839 : struct dc_state *context)
2840 : {
2841 0 : }
2842 :
2843 0 : static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx)
2844 : {
2845 0 : struct dce_hwseq *hws = dc->hwseq;
2846 0 : int fe_idx = pipe_ctx->plane_res.mi ?
2847 0 : pipe_ctx->plane_res.mi->inst : pipe_ctx->pipe_idx;
2848 :
2849 : /* Do not power down fe when stream is active on dce*/
2850 0 : if (dc->current_state->res_ctx.pipe_ctx[fe_idx].stream)
2851 : return;
2852 :
2853 0 : hws->funcs.enable_display_power_gating(
2854 0 : dc, fe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE);
2855 :
2856 0 : dc->res_pool->transforms[fe_idx]->funcs->transform_reset(
2857 : dc->res_pool->transforms[fe_idx]);
2858 : }
2859 :
2860 0 : static void dce110_wait_for_mpcc_disconnect(
2861 : struct dc *dc,
2862 : struct resource_pool *res_pool,
2863 : struct pipe_ctx *pipe_ctx)
2864 : {
2865 : /* do nothing*/
2866 0 : }
2867 :
2868 0 : static void program_output_csc(struct dc *dc,
2869 : struct pipe_ctx *pipe_ctx,
2870 : enum dc_color_space colorspace,
2871 : uint16_t *matrix,
2872 : int opp_id)
2873 : {
2874 : int i;
2875 : struct out_csc_color_matrix tbl_entry;
2876 :
2877 0 : if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
2878 0 : enum dc_color_space color_space = pipe_ctx->stream->output_color_space;
2879 :
2880 0 : for (i = 0; i < 12; i++)
2881 0 : tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i];
2882 :
2883 0 : tbl_entry.color_space = color_space;
2884 :
2885 0 : pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment(
2886 : pipe_ctx->plane_res.xfm, &tbl_entry);
2887 : }
2888 0 : }
2889 :
2890 0 : static void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
2891 : {
2892 0 : struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
2893 0 : struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;
2894 0 : struct mem_input *mi = pipe_ctx->plane_res.mi;
2895 0 : struct dc_cursor_mi_param param = {
2896 0 : .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
2897 0 : .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.xtalin_clock_inKhz,
2898 : .viewport = pipe_ctx->plane_res.scl_data.viewport,
2899 : .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
2900 : .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
2901 0 : .rotation = pipe_ctx->plane_state->rotation,
2902 0 : .mirror = pipe_ctx->plane_state->horizontal_mirror
2903 : };
2904 :
2905 : /**
2906 : * If the cursor's source viewport is clipped then we need to
2907 : * translate the cursor to appear in the correct position on
2908 : * the screen.
2909 : *
2910 : * This translation isn't affected by scaling so it needs to be
2911 : * done *after* we adjust the position for the scale factor.
2912 : *
2913 : * This is only done by opt-in for now since there are still
2914 : * some usecases like tiled display that might enable the
2915 : * cursor on both streams while expecting dc to clip it.
2916 : */
2917 0 : if (pos_cpy.translate_by_source) {
2918 0 : pos_cpy.x += pipe_ctx->plane_state->src_rect.x;
2919 0 : pos_cpy.y += pipe_ctx->plane_state->src_rect.y;
2920 : }
2921 :
2922 0 : if (pipe_ctx->plane_state->address.type
2923 : == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
2924 0 : pos_cpy.enable = false;
2925 :
2926 0 : if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
2927 0 : pos_cpy.enable = false;
2928 :
2929 0 : if (ipp->funcs->ipp_cursor_set_position)
2930 0 : ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m);
2931 0 : if (mi->funcs->set_cursor_position)
2932 0 : mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m);
2933 0 : }
2934 :
2935 0 : static void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
2936 : {
2937 0 : struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
2938 :
2939 0 : if (pipe_ctx->plane_res.ipp &&
2940 0 : pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes)
2941 0 : pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes(
2942 : pipe_ctx->plane_res.ipp, attributes);
2943 :
2944 0 : if (pipe_ctx->plane_res.mi &&
2945 0 : pipe_ctx->plane_res.mi->funcs->set_cursor_attributes)
2946 0 : pipe_ctx->plane_res.mi->funcs->set_cursor_attributes(
2947 : pipe_ctx->plane_res.mi, attributes);
2948 :
2949 0 : if (pipe_ctx->plane_res.xfm &&
2950 0 : pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes)
2951 0 : pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes(
2952 : pipe_ctx->plane_res.xfm, attributes);
2953 0 : }
2954 :
2955 0 : bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx,
2956 : uint32_t backlight_pwm_u16_16,
2957 : uint32_t frame_ramp)
2958 : {
2959 0 : struct dc_link *link = pipe_ctx->stream->link;
2960 0 : struct dc *dc = link->ctx->dc;
2961 0 : struct abm *abm = pipe_ctx->stream_res.abm;
2962 0 : struct panel_cntl *panel_cntl = link->panel_cntl;
2963 0 : struct dmcu *dmcu = dc->res_pool->dmcu;
2964 0 : bool fw_set_brightness = true;
2965 : /* DMCU -1 for all controller id values,
2966 : * therefore +1 here
2967 : */
2968 0 : uint32_t controller_id = pipe_ctx->stream_res.tg->inst + 1;
2969 :
2970 0 : if (abm == NULL || panel_cntl == NULL || (abm->funcs->set_backlight_level_pwm == NULL))
2971 : return false;
2972 :
2973 0 : if (dmcu)
2974 0 : fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
2975 :
2976 0 : if (!fw_set_brightness && panel_cntl->funcs->driver_set_backlight)
2977 0 : panel_cntl->funcs->driver_set_backlight(panel_cntl, backlight_pwm_u16_16);
2978 : else
2979 0 : abm->funcs->set_backlight_level_pwm(
2980 : abm,
2981 : backlight_pwm_u16_16,
2982 : frame_ramp,
2983 : controller_id,
2984 0 : link->panel_cntl->inst);
2985 :
2986 : return true;
2987 : }
2988 :
2989 0 : void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx)
2990 : {
2991 0 : struct abm *abm = pipe_ctx->stream_res.abm;
2992 0 : struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
2993 :
2994 0 : if (abm)
2995 0 : abm->funcs->set_abm_immediate_disable(abm,
2996 : pipe_ctx->stream->link->panel_cntl->inst);
2997 :
2998 0 : if (panel_cntl)
2999 0 : panel_cntl->funcs->store_backlight_level(panel_cntl);
3000 0 : }
3001 :
3002 0 : void dce110_set_pipe(struct pipe_ctx *pipe_ctx)
3003 : {
3004 0 : struct abm *abm = pipe_ctx->stream_res.abm;
3005 0 : struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
3006 0 : uint32_t otg_inst = pipe_ctx->stream_res.tg->inst + 1;
3007 :
3008 0 : if (abm && panel_cntl)
3009 0 : abm->funcs->set_pipe(abm, otg_inst, panel_cntl->inst);
3010 0 : }
3011 :
3012 : static const struct hw_sequencer_funcs dce110_funcs = {
3013 : .program_gamut_remap = program_gamut_remap,
3014 : .program_output_csc = program_output_csc,
3015 : .init_hw = init_hw,
3016 : .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
3017 : .apply_ctx_for_surface = dce110_apply_ctx_for_surface,
3018 : .post_unlock_program_front_end = dce110_post_unlock_program_front_end,
3019 : .update_plane_addr = update_plane_addr,
3020 : .update_pending_status = dce110_update_pending_status,
3021 : .enable_accelerated_mode = dce110_enable_accelerated_mode,
3022 : .enable_timing_synchronization = dce110_enable_timing_synchronization,
3023 : .enable_per_frame_crtc_position_reset = dce110_enable_per_frame_crtc_position_reset,
3024 : .update_info_frame = dce110_update_info_frame,
3025 : .enable_stream = dce110_enable_stream,
3026 : .disable_stream = dce110_disable_stream,
3027 : .unblank_stream = dce110_unblank_stream,
3028 : .blank_stream = dce110_blank_stream,
3029 : .enable_audio_stream = dce110_enable_audio_stream,
3030 : .disable_audio_stream = dce110_disable_audio_stream,
3031 : .disable_plane = dce110_power_down_fe,
3032 : .pipe_control_lock = dce_pipe_control_lock,
3033 : .interdependent_update_lock = NULL,
3034 : .cursor_lock = dce_pipe_control_lock,
3035 : .prepare_bandwidth = dce110_prepare_bandwidth,
3036 : .optimize_bandwidth = dce110_optimize_bandwidth,
3037 : .set_drr = set_drr,
3038 : .get_position = get_position,
3039 : .set_static_screen_control = set_static_screen_control,
3040 : .setup_stereo = NULL,
3041 : .set_avmute = dce110_set_avmute,
3042 : .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect,
3043 : .edp_backlight_control = dce110_edp_backlight_control,
3044 : .edp_power_control = dce110_edp_power_control,
3045 : .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
3046 : .set_cursor_position = dce110_set_cursor_position,
3047 : .set_cursor_attribute = dce110_set_cursor_attribute,
3048 : .set_backlight_level = dce110_set_backlight_level,
3049 : .set_abm_immediate_disable = dce110_set_abm_immediate_disable,
3050 : .set_pipe = dce110_set_pipe,
3051 : };
3052 :
3053 : static const struct hwseq_private_funcs dce110_private_funcs = {
3054 : .init_pipes = init_pipes,
3055 : .update_plane_addr = update_plane_addr,
3056 : .set_input_transfer_func = dce110_set_input_transfer_func,
3057 : .set_output_transfer_func = dce110_set_output_transfer_func,
3058 : .power_down = dce110_power_down,
3059 : .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating,
3060 : .enable_display_power_gating = dce110_enable_display_power_gating,
3061 : .reset_hw_ctx_wrap = dce110_reset_hw_ctx_wrap,
3062 : .enable_stream_timing = dce110_enable_stream_timing,
3063 : .disable_stream_gating = NULL,
3064 : .enable_stream_gating = NULL,
3065 : .edp_backlight_control = dce110_edp_backlight_control,
3066 : };
3067 :
3068 0 : void dce110_hw_sequencer_construct(struct dc *dc)
3069 : {
3070 0 : dc->hwss = dce110_funcs;
3071 0 : dc->hwseq->funcs = dce110_private_funcs;
3072 0 : }
3073 :
|