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