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