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