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