]>
Commit | Line | Data |
---|---|---|
4562236b HW |
1 | /* |
2 | * Copyright 2012-15 Advanced Micro Devices, Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: AMD | |
23 | * | |
24 | */ | |
25 | ||
26 | #include "reg_helper.h" | |
27 | ||
28 | #include "core_types.h" | |
29 | #include "link_encoder.h" | |
30 | #include "dce_link_encoder.h" | |
31 | #include "stream_encoder.h" | |
32 | #include "i2caux_interface.h" | |
33 | #include "dc_bios_types.h" | |
34 | ||
35 | #include "gpio_service_interface.h" | |
36 | ||
37 | #include "dce/dce_11_0_d.h" | |
38 | #include "dce/dce_11_0_sh_mask.h" | |
39 | #include "dce/dce_11_0_enum.h" | |
40 | ||
871ffb60 DL |
41 | #ifndef DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE__SHIFT |
42 | #define DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE__SHIFT 0xa | |
43 | #endif | |
44 | ||
45 | #ifndef DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE_MASK | |
46 | #define DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE_MASK 0x00000400L | |
47 | #endif | |
48 | ||
4562236b HW |
49 | #ifndef HPD0_DC_HPD_CONTROL__DC_HPD_EN_MASK |
50 | #define HPD0_DC_HPD_CONTROL__DC_HPD_EN_MASK 0x10000000L | |
51 | #endif | |
52 | ||
53 | #ifndef HPD0_DC_HPD_CONTROL__DC_HPD_EN__SHIFT | |
54 | #define HPD0_DC_HPD_CONTROL__DC_HPD_EN__SHIFT 0x1c | |
55 | #endif | |
56 | ||
57 | #define CTX \ | |
58 | enc110->base.ctx | |
59 | ||
60 | #define REG(reg)\ | |
61 | (enc110->link_regs->reg) | |
62 | ||
63 | #define AUX_REG(reg)\ | |
64 | (enc110->aux_regs->reg) | |
65 | ||
66 | #define HPD_REG(reg)\ | |
67 | (enc110->hpd_regs->reg) | |
68 | ||
4562236b HW |
69 | #define DEFAULT_AUX_MAX_DATA_SIZE 16 |
70 | #define AUX_MAX_DEFER_WRITE_RETRY 20 | |
71 | /* | |
72 | * @brief | |
73 | * Trigger Source Select | |
74 | * ASIC-dependent, actual values for register programming | |
75 | */ | |
76 | #define DCE110_DIG_FE_SOURCE_SELECT_INVALID 0x0 | |
77 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGA 0x1 | |
78 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGB 0x2 | |
79 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGC 0x4 | |
80 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGD 0x08 | |
81 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGE 0x10 | |
82 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20 | |
83 | ||
84 | /* all values are in milliseconds */ | |
85 | /* For eDP, after power-up/power/down, | |
86 | * 300/500 msec max. delay from LCDVCC to black video generation */ | |
87 | #define PANEL_POWER_UP_TIMEOUT 300 | |
88 | #define PANEL_POWER_DOWN_TIMEOUT 500 | |
89 | #define HPD_CHECK_INTERVAL 10 | |
90 | ||
91 | /* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ | |
92 | #define TMDS_MIN_PIXEL_CLOCK 25000 | |
93 | /* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ | |
94 | #define TMDS_MAX_PIXEL_CLOCK 165000 | |
95 | /* For current ASICs pixel clock - 600MHz */ | |
96 | #define MAX_ENCODER_CLOCK 600000 | |
97 | ||
4562236b HW |
98 | enum { |
99 | DP_MST_UPDATE_MAX_RETRY = 50 | |
100 | }; | |
101 | ||
102 | #define DIG_REG(reg)\ | |
103 | (reg + enc110->offsets.dig) | |
104 | ||
105 | #define DP_REG(reg)\ | |
106 | (reg + enc110->offsets.dp) | |
107 | ||
108 | static const struct link_encoder_funcs dce110_lnk_enc_funcs = { | |
109 | .validate_output_with_stream = | |
110 | dce110_link_encoder_validate_output_with_stream, | |
111 | .hw_init = dce110_link_encoder_hw_init, | |
112 | .setup = dce110_link_encoder_setup, | |
113 | .enable_tmds_output = dce110_link_encoder_enable_tmds_output, | |
114 | .enable_dp_output = dce110_link_encoder_enable_dp_output, | |
115 | .enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output, | |
116 | .disable_output = dce110_link_encoder_disable_output, | |
117 | .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, | |
118 | .dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern, | |
119 | .update_mst_stream_allocation_table = | |
120 | dce110_link_encoder_update_mst_stream_allocation_table, | |
3548f073 AZ |
121 | .psr_program_dp_dphy_fast_training = |
122 | dce110_psr_program_dp_dphy_fast_training, | |
123 | .psr_program_secondary_packet = dce110_psr_program_secondary_packet, | |
4562236b HW |
124 | .backlight_control = dce110_link_encoder_edp_backlight_control, |
125 | .power_control = dce110_link_encoder_edp_power_control, | |
126 | .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe, | |
127 | .enable_hpd = dce110_link_encoder_enable_hpd, | |
128 | .disable_hpd = dce110_link_encoder_disable_hpd, | |
129 | .destroy = dce110_link_encoder_destroy | |
130 | }; | |
131 | ||
4562236b HW |
132 | static enum bp_result link_transmitter_control( |
133 | struct dce110_link_encoder *enc110, | |
134 | struct bp_transmitter_control *cntl) | |
135 | { | |
136 | enum bp_result result; | |
137 | struct dc_bios *bp = enc110->base.ctx->dc_bios; | |
138 | ||
139 | result = bp->funcs->transmitter_control(bp, cntl); | |
140 | ||
141 | return result; | |
142 | } | |
143 | ||
144 | static void enable_phy_bypass_mode( | |
145 | struct dce110_link_encoder *enc110, | |
146 | bool enable) | |
147 | { | |
148 | /* This register resides in DP back end block; | |
149 | * transmitter is used for the offset */ | |
150 | ||
151 | REG_UPDATE(DP_DPHY_CNTL, DPHY_BYPASS, enable); | |
152 | ||
153 | } | |
154 | ||
155 | static void disable_prbs_symbols( | |
156 | struct dce110_link_encoder *enc110, | |
157 | bool disable) | |
158 | { | |
159 | /* This register resides in DP back end block; | |
160 | * transmitter is used for the offset */ | |
161 | ||
162 | REG_UPDATE_4(DP_DPHY_CNTL, | |
163 | DPHY_ATEST_SEL_LANE0, disable, | |
164 | DPHY_ATEST_SEL_LANE1, disable, | |
165 | DPHY_ATEST_SEL_LANE2, disable, | |
166 | DPHY_ATEST_SEL_LANE3, disable); | |
167 | } | |
168 | ||
169 | static void disable_prbs_mode( | |
170 | struct dce110_link_encoder *enc110) | |
171 | { | |
4562236b HW |
172 | REG_UPDATE(DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN, 0); |
173 | } | |
174 | ||
175 | static void program_pattern_symbols( | |
176 | struct dce110_link_encoder *enc110, | |
177 | uint16_t pattern_symbols[8]) | |
178 | { | |
179 | /* This register resides in DP back end block; | |
180 | * transmitter is used for the offset */ | |
181 | ||
182 | REG_SET_3(DP_DPHY_SYM0, 0, | |
183 | DPHY_SYM1, pattern_symbols[0], | |
184 | DPHY_SYM2, pattern_symbols[1], | |
185 | DPHY_SYM3, pattern_symbols[2]); | |
186 | ||
187 | /* This register resides in DP back end block; | |
188 | * transmitter is used for the offset */ | |
189 | ||
190 | REG_SET_3(DP_DPHY_SYM1, 0, | |
191 | DPHY_SYM4, pattern_symbols[3], | |
192 | DPHY_SYM5, pattern_symbols[4], | |
193 | DPHY_SYM6, pattern_symbols[5]); | |
194 | ||
195 | /* This register resides in DP back end block; | |
196 | * transmitter is used for the offset */ | |
197 | ||
198 | REG_SET_2(DP_DPHY_SYM2, 0, | |
199 | DPHY_SYM7, pattern_symbols[6], | |
200 | DPHY_SYM8, pattern_symbols[7]); | |
201 | } | |
202 | ||
203 | static void set_dp_phy_pattern_d102( | |
204 | struct dce110_link_encoder *enc110) | |
205 | { | |
206 | /* Disable PHY Bypass mode to setup the test pattern */ | |
207 | enable_phy_bypass_mode(enc110, false); | |
208 | ||
209 | /* For 10-bit PRBS or debug symbols | |
210 | * please use the following sequence: */ | |
211 | ||
212 | /* Enable debug symbols on the lanes */ | |
213 | ||
214 | disable_prbs_symbols(enc110, true); | |
215 | ||
3f8a9440 | 216 | /* Disable PRBS mode */ |
4562236b HW |
217 | disable_prbs_mode(enc110); |
218 | ||
219 | /* Program debug symbols to be output */ | |
220 | { | |
221 | uint16_t pattern_symbols[8] = { | |
222 | 0x2AA, 0x2AA, 0x2AA, 0x2AA, | |
223 | 0x2AA, 0x2AA, 0x2AA, 0x2AA | |
224 | }; | |
225 | ||
226 | program_pattern_symbols(enc110, pattern_symbols); | |
227 | } | |
228 | ||
229 | /* Enable phy bypass mode to enable the test pattern */ | |
230 | ||
231 | enable_phy_bypass_mode(enc110, true); | |
232 | } | |
233 | ||
234 | static void set_link_training_complete( | |
235 | struct dce110_link_encoder *enc110, | |
236 | bool complete) | |
237 | { | |
238 | /* This register resides in DP back end block; | |
239 | * transmitter is used for the offset */ | |
240 | ||
241 | REG_UPDATE(DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE, complete); | |
242 | ||
243 | } | |
244 | ||
245 | void dce110_link_encoder_set_dp_phy_pattern_training_pattern( | |
246 | struct link_encoder *enc, | |
247 | uint32_t index) | |
248 | { | |
249 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
250 | /* Write Training Pattern */ | |
251 | ||
252 | REG_WRITE(DP_DPHY_TRAINING_PATTERN_SEL, index); | |
253 | ||
254 | /* Set HW Register Training Complete to false */ | |
255 | ||
256 | set_link_training_complete(enc110, false); | |
257 | ||
258 | /* Disable PHY Bypass mode to output Training Pattern */ | |
259 | ||
260 | enable_phy_bypass_mode(enc110, false); | |
261 | ||
3f8a9440 | 262 | /* Disable PRBS mode */ |
4562236b HW |
263 | disable_prbs_mode(enc110); |
264 | } | |
265 | ||
3f8a9440 TC |
266 | static void setup_panel_mode( |
267 | struct dce110_link_encoder *enc110, | |
268 | enum dp_panel_mode panel_mode) | |
269 | { | |
270 | uint32_t value; | |
271 | ||
272 | ASSERT(REG(DP_DPHY_INTERNAL_CTRL)); | |
273 | value = REG_READ(DP_DPHY_INTERNAL_CTRL); | |
274 | ||
275 | switch (panel_mode) { | |
276 | case DP_PANEL_MODE_EDP: | |
277 | value = 0x1; | |
278 | break; | |
279 | case DP_PANEL_MODE_SPECIAL: | |
280 | value = 0x11; | |
281 | break; | |
282 | default: | |
283 | value = 0x0; | |
284 | break; | |
285 | } | |
286 | ||
287 | REG_WRITE(DP_DPHY_INTERNAL_CTRL, value); | |
288 | } | |
289 | ||
4562236b HW |
290 | static void set_dp_phy_pattern_symbol_error( |
291 | struct dce110_link_encoder *enc110) | |
292 | { | |
293 | /* Disable PHY Bypass mode to setup the test pattern */ | |
4562236b HW |
294 | enable_phy_bypass_mode(enc110, false); |
295 | ||
296 | /* program correct panel mode*/ | |
3f8a9440 | 297 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); |
4562236b HW |
298 | |
299 | /* A PRBS23 pattern is used for most DP electrical measurements. */ | |
300 | ||
301 | /* Enable PRBS symbols on the lanes */ | |
4562236b HW |
302 | disable_prbs_symbols(enc110, false); |
303 | ||
304 | /* For PRBS23 Set bit DPHY_PRBS_SEL=1 and Set bit DPHY_PRBS_EN=1 */ | |
3f8a9440 TC |
305 | REG_UPDATE_2(DP_DPHY_PRBS_CNTL, |
306 | DPHY_PRBS_SEL, 1, | |
307 | DPHY_PRBS_EN, 1); | |
4562236b HW |
308 | |
309 | /* Enable phy bypass mode to enable the test pattern */ | |
4562236b HW |
310 | enable_phy_bypass_mode(enc110, true); |
311 | } | |
312 | ||
313 | static void set_dp_phy_pattern_prbs7( | |
314 | struct dce110_link_encoder *enc110) | |
315 | { | |
316 | /* Disable PHY Bypass mode to setup the test pattern */ | |
4562236b HW |
317 | enable_phy_bypass_mode(enc110, false); |
318 | ||
319 | /* A PRBS7 pattern is used for most DP electrical measurements. */ | |
320 | ||
321 | /* Enable PRBS symbols on the lanes */ | |
4562236b HW |
322 | disable_prbs_symbols(enc110, false); |
323 | ||
324 | /* For PRBS7 Set bit DPHY_PRBS_SEL=0 and Set bit DPHY_PRBS_EN=1 */ | |
3f8a9440 TC |
325 | REG_UPDATE_2(DP_DPHY_PRBS_CNTL, |
326 | DPHY_PRBS_SEL, 0, | |
327 | DPHY_PRBS_EN, 1); | |
4562236b HW |
328 | |
329 | /* Enable phy bypass mode to enable the test pattern */ | |
4562236b HW |
330 | enable_phy_bypass_mode(enc110, true); |
331 | } | |
332 | ||
333 | static void set_dp_phy_pattern_80bit_custom( | |
334 | struct dce110_link_encoder *enc110, | |
335 | const uint8_t *pattern) | |
336 | { | |
337 | /* Disable PHY Bypass mode to setup the test pattern */ | |
338 | enable_phy_bypass_mode(enc110, false); | |
339 | ||
340 | /* Enable debug symbols on the lanes */ | |
341 | ||
342 | disable_prbs_symbols(enc110, true); | |
343 | ||
344 | /* Enable PHY bypass mode to enable the test pattern */ | |
345 | /* TODO is it really needed ? */ | |
346 | ||
347 | enable_phy_bypass_mode(enc110, true); | |
348 | ||
349 | /* Program 80 bit custom pattern */ | |
350 | { | |
351 | uint16_t pattern_symbols[8]; | |
352 | ||
353 | pattern_symbols[0] = | |
354 | ((pattern[1] & 0x03) << 8) | pattern[0]; | |
355 | pattern_symbols[1] = | |
356 | ((pattern[2] & 0x0f) << 6) | ((pattern[1] >> 2) & 0x3f); | |
357 | pattern_symbols[2] = | |
358 | ((pattern[3] & 0x3f) << 4) | ((pattern[2] >> 4) & 0x0f); | |
359 | pattern_symbols[3] = | |
360 | (pattern[4] << 2) | ((pattern[3] >> 6) & 0x03); | |
361 | pattern_symbols[4] = | |
362 | ((pattern[6] & 0x03) << 8) | pattern[5]; | |
363 | pattern_symbols[5] = | |
364 | ((pattern[7] & 0x0f) << 6) | ((pattern[6] >> 2) & 0x3f); | |
365 | pattern_symbols[6] = | |
366 | ((pattern[8] & 0x3f) << 4) | ((pattern[7] >> 4) & 0x0f); | |
367 | pattern_symbols[7] = | |
368 | (pattern[9] << 2) | ((pattern[8] >> 6) & 0x03); | |
369 | ||
370 | program_pattern_symbols(enc110, pattern_symbols); | |
371 | } | |
372 | ||
373 | /* Enable phy bypass mode to enable the test pattern */ | |
374 | ||
375 | enable_phy_bypass_mode(enc110, true); | |
376 | } | |
377 | ||
3f8a9440 | 378 | static void set_dp_phy_pattern_hbr2_compliance_cp2520_2( |
0e19401f TC |
379 | struct dce110_link_encoder *enc110, |
380 | unsigned int cp2520_pattern) | |
4562236b HW |
381 | { |
382 | ||
383 | /* previously there is a register DP_HBR2_EYE_PATTERN | |
384 | * that is enabled to get the pattern. | |
385 | * But it does not work with the latest spec change, | |
386 | * so we are programming the following registers manually. | |
387 | * | |
388 | * The following settings have been confirmed | |
389 | * by Nick Chorney and Sandra Liu */ | |
390 | ||
391 | /* Disable PHY Bypass mode to setup the test pattern */ | |
392 | ||
393 | enable_phy_bypass_mode(enc110, false); | |
394 | ||
395 | /* Setup DIG encoder in DP SST mode */ | |
4562236b HW |
396 | enc110->base.funcs->setup(&enc110->base, SIGNAL_TYPE_DISPLAY_PORT); |
397 | ||
3f8a9440 TC |
398 | /* ensure normal panel mode. */ |
399 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); | |
4562236b HW |
400 | |
401 | /* no vbid after BS (SR) | |
402 | * DP_LINK_FRAMING_CNTL changed history Sandra Liu | |
403 | * 11000260 / 11000104 / 110000FC */ | |
3f8a9440 TC |
404 | REG_UPDATE_3(DP_LINK_FRAMING_CNTL, |
405 | DP_IDLE_BS_INTERVAL, 0xFC, | |
406 | DP_VBID_DISABLE, 1, | |
407 | DP_VID_ENHANCED_FRAME_MODE, 1); | |
4562236b | 408 | |
4562236b | 409 | /* swap every BS with SR */ |
4562236b HW |
410 | REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_BS_COUNT, 0); |
411 | ||
0e19401f | 412 | /* select cp2520 patterns */ |
3f8a9440 TC |
413 | if (REG(DP_DPHY_HBR2_PATTERN_CONTROL)) |
414 | REG_UPDATE(DP_DPHY_HBR2_PATTERN_CONTROL, | |
0e19401f TC |
415 | DP_DPHY_HBR2_PATTERN_CONTROL, cp2520_pattern); |
416 | else | |
417 | /* pre-DCE11 can only generate CP2520 pattern 2 */ | |
418 | ASSERT(cp2520_pattern == 2); | |
4562236b HW |
419 | |
420 | /* set link training complete */ | |
421 | set_link_training_complete(enc110, true); | |
4562236b | 422 | |
3f8a9440 | 423 | /* disable video stream */ |
4562236b HW |
424 | REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0); |
425 | ||
426 | /* Disable PHY Bypass mode to setup the test pattern */ | |
4562236b HW |
427 | enable_phy_bypass_mode(enc110, false); |
428 | } | |
429 | ||
430 | static void set_dp_phy_pattern_passthrough_mode( | |
431 | struct dce110_link_encoder *enc110, | |
432 | enum dp_panel_mode panel_mode) | |
433 | { | |
4562236b | 434 | /* program correct panel mode */ |
3f8a9440 | 435 | setup_panel_mode(enc110, panel_mode); |
4562236b | 436 | |
3f8a9440 TC |
437 | /* restore LINK_FRAMING_CNTL and DPHY_SCRAMBLER_BS_COUNT |
438 | * in case we were doing HBR2 compliance pattern before | |
439 | */ | |
440 | REG_UPDATE_3(DP_LINK_FRAMING_CNTL, | |
441 | DP_IDLE_BS_INTERVAL, 0x2000, | |
442 | DP_VBID_DISABLE, 0, | |
443 | DP_VID_ENHANCED_FRAME_MODE, 1); | |
4562236b HW |
444 | |
445 | REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_BS_COUNT, 0x1FF); | |
446 | ||
447 | /* set link training complete */ | |
4562236b HW |
448 | set_link_training_complete(enc110, true); |
449 | ||
450 | /* Disable PHY Bypass mode to setup the test pattern */ | |
4562236b HW |
451 | enable_phy_bypass_mode(enc110, false); |
452 | ||
3f8a9440 | 453 | /* Disable PRBS mode */ |
4562236b HW |
454 | disable_prbs_mode(enc110); |
455 | } | |
456 | ||
457 | /* return value is bit-vector */ | |
458 | static uint8_t get_frontend_source( | |
459 | enum engine_id engine) | |
460 | { | |
461 | switch (engine) { | |
462 | case ENGINE_ID_DIGA: | |
463 | return DCE110_DIG_FE_SOURCE_SELECT_DIGA; | |
464 | case ENGINE_ID_DIGB: | |
465 | return DCE110_DIG_FE_SOURCE_SELECT_DIGB; | |
466 | case ENGINE_ID_DIGC: | |
467 | return DCE110_DIG_FE_SOURCE_SELECT_DIGC; | |
468 | case ENGINE_ID_DIGD: | |
469 | return DCE110_DIG_FE_SOURCE_SELECT_DIGD; | |
470 | case ENGINE_ID_DIGE: | |
471 | return DCE110_DIG_FE_SOURCE_SELECT_DIGE; | |
472 | case ENGINE_ID_DIGF: | |
473 | return DCE110_DIG_FE_SOURCE_SELECT_DIGF; | |
474 | default: | |
475 | ASSERT_CRITICAL(false); | |
476 | return DCE110_DIG_FE_SOURCE_SELECT_INVALID; | |
477 | } | |
478 | } | |
479 | ||
480 | static void configure_encoder( | |
481 | struct dce110_link_encoder *enc110, | |
482 | const struct dc_link_settings *link_settings) | |
483 | { | |
484 | /* set number of lanes */ | |
485 | ||
486 | REG_SET(DP_CONFIG, 0, | |
487 | DP_UDI_LANES, link_settings->lane_count - LANE_COUNT_ONE); | |
488 | ||
489 | /* setup scrambler */ | |
490 | REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_ADVANCE, 1); | |
491 | } | |
492 | ||
493 | static bool is_panel_powered_on(struct dce110_link_encoder *enc110) | |
494 | { | |
495 | bool ret; | |
496 | uint32_t value; | |
497 | ||
498 | REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value); | |
499 | ret = value; | |
500 | ||
501 | return ret == 1; | |
502 | } | |
503 | ||
504 | ||
505 | /* TODO duplicate of dc_link.c version */ | |
506 | static struct gpio *get_hpd_gpio(const struct link_encoder *enc) | |
507 | { | |
508 | enum bp_result bp_result; | |
509 | struct dc_bios *dcb = enc->ctx->dc_bios; | |
510 | struct graphics_object_hpd_info hpd_info; | |
511 | struct gpio_pin_info pin_info; | |
512 | ||
513 | if (dcb->funcs->get_hpd_info(dcb, enc->connector, &hpd_info) != BP_RESULT_OK) | |
514 | return NULL; | |
515 | ||
516 | bp_result = dcb->funcs->get_gpio_pin_info(dcb, | |
517 | hpd_info.hpd_int_gpio_uid, &pin_info); | |
518 | ||
519 | if (bp_result != BP_RESULT_OK) { | |
520 | ASSERT(bp_result == BP_RESULT_NORECORD); | |
521 | return NULL; | |
522 | } | |
523 | ||
524 | return dal_gpio_service_create_irq( | |
525 | enc->ctx->gpio_service, | |
526 | pin_info.offset, | |
527 | pin_info.mask); | |
528 | } | |
529 | ||
530 | /* | |
531 | * @brief | |
532 | * eDP only. | |
533 | */ | |
534 | static void link_encoder_edp_wait_for_hpd_ready( | |
535 | struct dce110_link_encoder *enc110, | |
536 | bool power_up) | |
537 | { | |
538 | struct dc_context *ctx = enc110->base.ctx; | |
539 | struct graphics_object_id connector = enc110->base.connector; | |
540 | struct gpio *hpd; | |
541 | bool edp_hpd_high = false; | |
542 | uint32_t time_elapsed = 0; | |
543 | uint32_t timeout = power_up ? | |
544 | PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT; | |
545 | ||
546 | if (dal_graphics_object_id_get_connector_id(connector) != | |
547 | CONNECTOR_ID_EDP) { | |
548 | BREAK_TO_DEBUGGER(); | |
549 | return; | |
550 | } | |
551 | ||
552 | if (!power_up) | |
553 | /* from KV, we will not HPD low after turning off VCC - | |
554 | * instead, we will check the SW timer in power_up(). */ | |
555 | return; | |
556 | ||
557 | /* when we power on/off the eDP panel, | |
558 | * we need to wait until SENSE bit is high/low */ | |
559 | ||
560 | /* obtain HPD */ | |
561 | /* TODO what to do with this? */ | |
562 | hpd = get_hpd_gpio(&enc110->base); | |
563 | ||
564 | if (!hpd) { | |
565 | BREAK_TO_DEBUGGER(); | |
566 | return; | |
567 | } | |
568 | ||
569 | dal_gpio_open(hpd, GPIO_MODE_INTERRUPT); | |
570 | ||
571 | /* wait until timeout or panel detected */ | |
572 | ||
573 | do { | |
574 | uint32_t detected = 0; | |
575 | ||
576 | dal_gpio_get_value(hpd, &detected); | |
577 | ||
578 | if (!(detected ^ power_up)) { | |
579 | edp_hpd_high = true; | |
580 | break; | |
581 | } | |
582 | ||
583 | msleep(HPD_CHECK_INTERVAL); | |
584 | ||
585 | time_elapsed += HPD_CHECK_INTERVAL; | |
586 | } while (time_elapsed < timeout); | |
587 | ||
588 | dal_gpio_close(hpd); | |
589 | ||
590 | dal_gpio_destroy_irq(&hpd); | |
591 | ||
592 | if (false == edp_hpd_high) { | |
593 | dm_logger_write(ctx->logger, LOG_ERROR, | |
594 | "%s: wait timed out!\n", __func__); | |
595 | } | |
596 | } | |
597 | ||
598 | /* | |
599 | * @brief | |
600 | * eDP only. Control the power of the eDP panel. | |
601 | */ | |
602 | void dce110_link_encoder_edp_power_control( | |
603 | struct link_encoder *enc, | |
604 | bool power_up) | |
605 | { | |
606 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
607 | struct dc_context *ctx = enc110->base.ctx; | |
608 | struct bp_transmitter_control cntl = { 0 }; | |
609 | enum bp_result bp_result; | |
610 | ||
611 | if (dal_graphics_object_id_get_connector_id(enc110->base.connector) != | |
612 | CONNECTOR_ID_EDP) { | |
613 | BREAK_TO_DEBUGGER(); | |
614 | return; | |
615 | } | |
616 | ||
617 | if ((power_up && !is_panel_powered_on(enc110)) || | |
618 | (!power_up && is_panel_powered_on(enc110))) { | |
619 | ||
620 | /* Send VBIOS command to prompt eDP panel power */ | |
621 | ||
622 | dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, | |
623 | "%s: Panel Power action: %s\n", | |
624 | __func__, (power_up ? "On":"Off")); | |
625 | ||
626 | cntl.action = power_up ? | |
627 | TRANSMITTER_CONTROL_POWER_ON : | |
628 | TRANSMITTER_CONTROL_POWER_OFF; | |
629 | cntl.transmitter = enc110->base.transmitter; | |
630 | cntl.connector_obj_id = enc110->base.connector; | |
631 | cntl.coherent = false; | |
632 | cntl.lanes_number = LANE_COUNT_FOUR; | |
633 | cntl.hpd_sel = enc110->base.hpd_source; | |
634 | ||
635 | bp_result = link_transmitter_control(enc110, &cntl); | |
636 | ||
637 | if (BP_RESULT_OK != bp_result) { | |
638 | ||
639 | dm_logger_write(ctx->logger, LOG_ERROR, | |
640 | "%s: Panel Power bp_result: %d\n", | |
641 | __func__, bp_result); | |
642 | } | |
643 | } else { | |
644 | dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, | |
645 | "%s: Skipping Panel Power action: %s\n", | |
646 | __func__, (power_up ? "On":"Off")); | |
647 | } | |
648 | ||
649 | link_encoder_edp_wait_for_hpd_ready(enc110, true); | |
650 | } | |
651 | ||
652 | static void aux_initialize( | |
653 | struct dce110_link_encoder *enc110) | |
654 | { | |
655 | struct dc_context *ctx = enc110->base.ctx; | |
656 | enum hpd_source_id hpd_source = enc110->base.hpd_source; | |
657 | uint32_t addr = AUX_REG(AUX_CONTROL); | |
658 | uint32_t value = dm_read_reg(ctx, addr); | |
659 | ||
660 | set_reg_field_value(value, hpd_source, AUX_CONTROL, AUX_HPD_SEL); | |
661 | set_reg_field_value(value, 0, AUX_CONTROL, AUX_LS_READ_EN); | |
662 | dm_write_reg(ctx, addr, value); | |
663 | ||
664 | addr = AUX_REG(AUX_DPHY_RX_CONTROL0); | |
665 | value = dm_read_reg(ctx, addr); | |
666 | ||
667 | /* 1/4 window (the maximum allowed) */ | |
668 | set_reg_field_value(value, 1, | |
669 | AUX_DPHY_RX_CONTROL0, AUX_RX_RECEIVE_WINDOW); | |
670 | dm_write_reg(ctx, addr, value); | |
671 | ||
672 | } | |
673 | ||
674 | /*todo: cloned in stream enc, fix*/ | |
675 | static bool is_panel_backlight_on(struct dce110_link_encoder *enc110) | |
676 | { | |
677 | uint32_t value; | |
678 | ||
679 | REG_GET(LVTMA_PWRSEQ_CNTL, LVTMA_BLON, &value); | |
680 | ||
681 | return value; | |
682 | } | |
683 | ||
3548f073 AZ |
684 | void dce110_psr_program_dp_dphy_fast_training(struct link_encoder *enc, |
685 | bool exit_link_training_required) | |
686 | { | |
687 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
688 | ||
689 | if (exit_link_training_required) | |
690 | REG_UPDATE(DP_DPHY_FAST_TRAINING, | |
691 | DPHY_RX_FAST_TRAINING_CAPABLE, 1); | |
692 | else { | |
693 | REG_UPDATE(DP_DPHY_FAST_TRAINING, | |
694 | DPHY_RX_FAST_TRAINING_CAPABLE, 0); | |
695 | /*In DCE 11, we are able to pre-program a Force SR register | |
696 | * to be able to trigger SR symbol after 5 idle patterns | |
697 | * transmitted. Upon PSR Exit, DMCU can trigger | |
698 | * DPHY_LOAD_BS_COUNT_START = 1. Upon writing 1 to | |
699 | * DPHY_LOAD_BS_COUNT_START and the internal counter | |
700 | * reaches DPHY_LOAD_BS_COUNT, the next BS symbol will be | |
701 | * replaced by SR symbol once. | |
702 | */ | |
703 | ||
704 | REG_UPDATE(DP_DPHY_BS_SR_SWAP_CNTL, DPHY_LOAD_BS_COUNT, 0x5); | |
705 | } | |
706 | } | |
707 | ||
708 | void dce110_psr_program_secondary_packet(struct link_encoder *enc, | |
709 | unsigned int sdp_transmit_line_num_deadline) | |
710 | { | |
711 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
712 | ||
713 | REG_UPDATE_2(DP_SEC_CNTL1, | |
714 | DP_SEC_GSP0_LINE_NUM, sdp_transmit_line_num_deadline, | |
715 | DP_SEC_GSP0_PRIORITY, 1); | |
716 | } | |
717 | ||
4562236b HW |
718 | /*todo: cloned in stream enc, fix*/ |
719 | /* | |
720 | * @brief | |
721 | * eDP only. Control the backlight of the eDP panel | |
722 | */ | |
723 | void dce110_link_encoder_edp_backlight_control( | |
724 | struct link_encoder *enc, | |
725 | bool enable) | |
726 | { | |
727 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
728 | struct dc_context *ctx = enc110->base.ctx; | |
729 | struct bp_transmitter_control cntl = { 0 }; | |
730 | ||
731 | if (dal_graphics_object_id_get_connector_id(enc110->base.connector) | |
732 | != CONNECTOR_ID_EDP) { | |
733 | BREAK_TO_DEBUGGER(); | |
734 | return; | |
735 | } | |
736 | ||
737 | if (enable && is_panel_backlight_on(enc110)) { | |
738 | dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, | |
739 | "%s: panel already powered up. Do nothing.\n", | |
740 | __func__); | |
741 | return; | |
742 | } | |
743 | ||
744 | if (!enable && !is_panel_powered_on(enc110)) { | |
745 | dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, | |
746 | "%s: panel already powered down. Do nothing.\n", | |
747 | __func__); | |
748 | return; | |
749 | } | |
750 | ||
751 | /* Send VBIOS command to control eDP panel backlight */ | |
752 | ||
753 | dm_logger_write(ctx->logger, LOG_HW_RESUME_S3, | |
754 | "%s: backlight action: %s\n", | |
755 | __func__, (enable ? "On":"Off")); | |
756 | ||
757 | cntl.action = enable ? | |
758 | TRANSMITTER_CONTROL_BACKLIGHT_ON : | |
759 | TRANSMITTER_CONTROL_BACKLIGHT_OFF; | |
760 | /*cntl.engine_id = ctx->engine;*/ | |
761 | cntl.transmitter = enc110->base.transmitter; | |
762 | cntl.connector_obj_id = enc110->base.connector; | |
763 | /*todo: unhardcode*/ | |
764 | cntl.lanes_number = LANE_COUNT_FOUR; | |
765 | cntl.hpd_sel = enc110->base.hpd_source; | |
766 | ||
767 | /* For eDP, the following delays might need to be considered | |
768 | * after link training completed: | |
769 | * idle period - min. accounts for required BS-Idle pattern, | |
770 | * max. allows for source frame synchronization); | |
771 | * 50 msec max. delay from valid video data from source | |
772 | * to video on dislpay or backlight enable. | |
773 | * | |
774 | * Disable the delay for now. | |
775 | * Enable it in the future if necessary. | |
776 | */ | |
777 | /* dc_service_sleep_in_milliseconds(50); */ | |
778 | link_transmitter_control(enc110, &cntl); | |
779 | } | |
780 | ||
781 | static bool is_dig_enabled(const struct dce110_link_encoder *enc110) | |
782 | { | |
783 | uint32_t value; | |
784 | ||
785 | REG_GET(DIG_BE_EN_CNTL, DIG_ENABLE, &value); | |
786 | return value; | |
787 | } | |
788 | ||
789 | static void link_encoder_disable(struct dce110_link_encoder *enc110) | |
790 | { | |
791 | /* reset training pattern */ | |
792 | REG_SET(DP_DPHY_TRAINING_PATTERN_SEL, 0, | |
793 | DPHY_TRAINING_PATTERN_SEL, 0); | |
794 | ||
795 | /* reset training complete */ | |
796 | REG_UPDATE(DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE, 0); | |
797 | ||
798 | /* reset panel mode */ | |
3f8a9440 | 799 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); |
4562236b HW |
800 | } |
801 | ||
802 | static void hpd_initialize( | |
803 | struct dce110_link_encoder *enc110) | |
804 | { | |
805 | /* Associate HPD with DIG_BE */ | |
806 | enum hpd_source_id hpd_source = enc110->base.hpd_source; | |
807 | ||
808 | REG_UPDATE(DIG_BE_CNTL, DIG_HPD_SELECT, hpd_source); | |
809 | } | |
810 | ||
811 | bool dce110_link_encoder_validate_dvi_output( | |
812 | const struct dce110_link_encoder *enc110, | |
813 | enum signal_type connector_signal, | |
814 | enum signal_type signal, | |
815 | const struct dc_crtc_timing *crtc_timing) | |
816 | { | |
817 | uint32_t max_pixel_clock = TMDS_MAX_PIXEL_CLOCK; | |
818 | ||
4562236b | 819 | if (signal == SIGNAL_TYPE_DVI_DUAL_LINK) |
4dfb0bad | 820 | max_pixel_clock *= 2; |
4562236b HW |
821 | |
822 | /* This handles the case of HDMI downgrade to DVI we don't want to | |
823 | * we don't want to cap the pixel clock if the DDI is not DVI. | |
824 | */ | |
825 | if (connector_signal != SIGNAL_TYPE_DVI_DUAL_LINK && | |
826 | connector_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) | |
4dfb0bad | 827 | max_pixel_clock = enc110->base.features.max_hdmi_pixel_clock; |
4562236b HW |
828 | |
829 | /* DVI only support RGB pixel encoding */ | |
830 | if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB) | |
831 | return false; | |
832 | ||
83572340 CL |
833 | /*connect DVI via adpater's HDMI connector*/ |
834 | if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK || | |
835 | connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) && | |
836 | signal != SIGNAL_TYPE_HDMI_TYPE_A && | |
837 | crtc_timing->pix_clk_khz > TMDS_MAX_PIXEL_CLOCK) | |
838 | return false; | |
4562236b HW |
839 | if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK) |
840 | return false; | |
841 | ||
842 | if (crtc_timing->pix_clk_khz > max_pixel_clock) | |
843 | return false; | |
844 | ||
845 | /* DVI supports 6/8bpp single-link and 10/16bpp dual-link */ | |
846 | switch (crtc_timing->display_color_depth) { | |
847 | case COLOR_DEPTH_666: | |
848 | case COLOR_DEPTH_888: | |
849 | break; | |
850 | case COLOR_DEPTH_101010: | |
851 | case COLOR_DEPTH_161616: | |
852 | if (signal != SIGNAL_TYPE_DVI_DUAL_LINK) | |
853 | return false; | |
854 | break; | |
855 | default: | |
856 | return false; | |
857 | } | |
858 | ||
859 | return true; | |
860 | } | |
861 | ||
862 | static bool dce110_link_encoder_validate_hdmi_output( | |
863 | const struct dce110_link_encoder *enc110, | |
864 | const struct dc_crtc_timing *crtc_timing, | |
865 | int adjusted_pix_clk_khz) | |
866 | { | |
867 | enum dc_color_depth max_deep_color = | |
868 | enc110->base.features.max_hdmi_deep_color; | |
869 | ||
4562236b HW |
870 | if (max_deep_color < crtc_timing->display_color_depth) |
871 | return false; | |
872 | ||
87b58768 CL |
873 | if (crtc_timing->display_color_depth < COLOR_DEPTH_888) |
874 | return false; | |
4562236b HW |
875 | if (adjusted_pix_clk_khz < TMDS_MIN_PIXEL_CLOCK) |
876 | return false; | |
877 | ||
878 | if ((adjusted_pix_clk_khz == 0) || | |
4dfb0bad | 879 | (adjusted_pix_clk_khz > enc110->base.features.max_hdmi_pixel_clock)) |
4562236b HW |
880 | return false; |
881 | ||
882 | /* DCE11 HW does not support 420 */ | |
883 | if (!enc110->base.features.ycbcr420_supported && | |
884 | crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) | |
885 | return false; | |
886 | ||
887 | return true; | |
888 | } | |
889 | ||
4562236b HW |
890 | bool dce110_link_encoder_validate_dp_output( |
891 | const struct dce110_link_encoder *enc110, | |
892 | const struct dc_crtc_timing *crtc_timing) | |
893 | { | |
894 | /* default RGB only */ | |
895 | if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) | |
896 | return true; | |
897 | ||
898 | if (enc110->base.features.flags.bits.IS_YCBCR_CAPABLE) | |
899 | return true; | |
900 | ||
901 | /* for DCE 8.x or later DP Y-only feature, | |
902 | * we need ASIC cap + FeatureSupportDPYonly, not support 666 */ | |
903 | if (crtc_timing->flags.Y_ONLY && | |
904 | enc110->base.features.flags.bits.IS_YCBCR_CAPABLE && | |
905 | crtc_timing->display_color_depth != COLOR_DEPTH_666) | |
906 | return true; | |
907 | ||
908 | return false; | |
909 | } | |
910 | ||
4562236b HW |
911 | bool dce110_link_encoder_construct( |
912 | struct dce110_link_encoder *enc110, | |
913 | const struct encoder_init_data *init_data, | |
7fc698a0 | 914 | const struct encoder_feature_support *enc_features, |
4562236b HW |
915 | const struct dce110_link_enc_registers *link_regs, |
916 | const struct dce110_link_enc_aux_registers *aux_regs, | |
917 | const struct dce110_link_enc_hpd_registers *hpd_regs) | |
918 | { | |
7fc698a0 TC |
919 | struct bp_encoder_cap_info bp_cap_info = {0}; |
920 | const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; | |
921 | ||
4562236b HW |
922 | enc110->base.funcs = &dce110_lnk_enc_funcs; |
923 | enc110->base.ctx = init_data->ctx; | |
924 | enc110->base.id = init_data->encoder; | |
925 | ||
926 | enc110->base.hpd_source = init_data->hpd_source; | |
927 | enc110->base.connector = init_data->connector; | |
4562236b HW |
928 | |
929 | enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; | |
930 | ||
7fc698a0 | 931 | enc110->base.features = *enc_features; |
4562236b HW |
932 | |
933 | enc110->base.transmitter = init_data->transmitter; | |
934 | ||
4562236b HW |
935 | /* set the flag to indicate whether driver poll the I2C data pin |
936 | * while doing the DP sink detect | |
937 | */ | |
938 | ||
939 | /* if (dal_adapter_service_is_feature_supported(as, | |
940 | FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) | |
941 | enc110->base.features.flags.bits. | |
942 | DP_SINK_DETECT_POLL_DATA_PIN = true;*/ | |
943 | ||
944 | enc110->base.output_signals = | |
945 | SIGNAL_TYPE_DVI_SINGLE_LINK | | |
946 | SIGNAL_TYPE_DVI_DUAL_LINK | | |
947 | SIGNAL_TYPE_LVDS | | |
948 | SIGNAL_TYPE_DISPLAY_PORT | | |
949 | SIGNAL_TYPE_DISPLAY_PORT_MST | | |
950 | SIGNAL_TYPE_EDP | | |
951 | SIGNAL_TYPE_HDMI_TYPE_A; | |
952 | ||
953 | /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. | |
954 | * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. | |
955 | * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer | |
956 | * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. | |
957 | * Prefer DIG assignment is decided by board design. | |
958 | * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design | |
959 | * and VBIOS will filter out 7 UNIPHY for DCE 8.0. | |
960 | * By this, adding DIGG should not hurt DCE 8.0. | |
961 | * This will let DCE 8.1 share DCE 8.0 as much as possible | |
962 | */ | |
963 | ||
964 | enc110->link_regs = link_regs; | |
965 | enc110->aux_regs = aux_regs; | |
966 | enc110->hpd_regs = hpd_regs; | |
967 | ||
968 | switch (enc110->base.transmitter) { | |
969 | case TRANSMITTER_UNIPHY_A: | |
970 | enc110->base.preferred_engine = ENGINE_ID_DIGA; | |
971 | break; | |
972 | case TRANSMITTER_UNIPHY_B: | |
973 | enc110->base.preferred_engine = ENGINE_ID_DIGB; | |
974 | break; | |
975 | case TRANSMITTER_UNIPHY_C: | |
976 | enc110->base.preferred_engine = ENGINE_ID_DIGC; | |
977 | break; | |
978 | case TRANSMITTER_UNIPHY_D: | |
979 | enc110->base.preferred_engine = ENGINE_ID_DIGD; | |
980 | break; | |
981 | case TRANSMITTER_UNIPHY_E: | |
982 | enc110->base.preferred_engine = ENGINE_ID_DIGE; | |
983 | break; | |
984 | case TRANSMITTER_UNIPHY_F: | |
985 | enc110->base.preferred_engine = ENGINE_ID_DIGF; | |
986 | break; | |
987 | default: | |
988 | ASSERT_CRITICAL(false); | |
989 | enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; | |
990 | } | |
991 | ||
992 | dm_logger_write(init_data->ctx->logger, LOG_I2C_AUX, | |
993 | "Using channel: %s [%d]\n", | |
994 | DECODE_CHANNEL_ID(init_data->channel), | |
995 | init_data->channel); | |
996 | ||
997 | /* Override features with DCE-specific values */ | |
4562236b HW |
998 | if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info( |
999 | enc110->base.ctx->dc_bios, enc110->base.id, | |
5727c77c | 1000 | &bp_cap_info)) { |
4562236b | 1001 | enc110->base.features.flags.bits.IS_HBR2_CAPABLE = |
4e3133c7 | 1002 | bp_cap_info.DP_HBR2_EN; |
5a7a1eeb HW |
1003 | enc110->base.features.flags.bits.IS_HBR3_CAPABLE = |
1004 | bp_cap_info.DP_HBR3_EN; | |
5727c77c | 1005 | } |
5a7a1eeb | 1006 | |
4562236b HW |
1007 | return true; |
1008 | } | |
1009 | ||
1010 | bool dce110_link_encoder_validate_output_with_stream( | |
1011 | struct link_encoder *enc, | |
1012 | struct pipe_ctx *pipe_ctx) | |
1013 | { | |
1014 | struct core_stream *stream = pipe_ctx->stream; | |
1015 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1016 | bool is_valid; | |
1017 | ||
1018 | switch (pipe_ctx->stream->signal) { | |
1019 | case SIGNAL_TYPE_DVI_SINGLE_LINK: | |
1020 | case SIGNAL_TYPE_DVI_DUAL_LINK: | |
1021 | is_valid = dce110_link_encoder_validate_dvi_output( | |
1022 | enc110, | |
1023 | stream->sink->link->public.connector_signal, | |
1024 | pipe_ctx->stream->signal, | |
1025 | &stream->public.timing); | |
1026 | break; | |
1027 | case SIGNAL_TYPE_HDMI_TYPE_A: | |
1028 | is_valid = dce110_link_encoder_validate_hdmi_output( | |
1029 | enc110, | |
1030 | &stream->public.timing, | |
1031 | stream->phy_pix_clk); | |
1032 | break; | |
4562236b HW |
1033 | case SIGNAL_TYPE_DISPLAY_PORT: |
1034 | case SIGNAL_TYPE_DISPLAY_PORT_MST: | |
4562236b | 1035 | is_valid = dce110_link_encoder_validate_dp_output( |
89aed24c ZF |
1036 | enc110, &stream->public.timing); |
1037 | break; | |
1038 | case SIGNAL_TYPE_EDP: | |
1039 | is_valid = | |
1040 | (stream->public.timing. | |
1041 | pixel_encoding == PIXEL_ENCODING_RGB) ? true : false; | |
4562236b | 1042 | break; |
546b9b61 YS |
1043 | case SIGNAL_TYPE_VIRTUAL: |
1044 | is_valid = true; | |
1045 | break; | |
4562236b | 1046 | default: |
4dfb0bad | 1047 | is_valid = false; |
4562236b HW |
1048 | break; |
1049 | } | |
1050 | ||
1051 | return is_valid; | |
1052 | } | |
1053 | ||
1054 | void dce110_link_encoder_hw_init( | |
1055 | struct link_encoder *enc) | |
1056 | { | |
1057 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1058 | struct dc_context *ctx = enc110->base.ctx; | |
1059 | struct bp_transmitter_control cntl = { 0 }; | |
1060 | enum bp_result result; | |
1061 | ||
1062 | cntl.action = TRANSMITTER_CONTROL_INIT; | |
1063 | cntl.engine_id = ENGINE_ID_UNKNOWN; | |
1064 | cntl.transmitter = enc110->base.transmitter; | |
1065 | cntl.connector_obj_id = enc110->base.connector; | |
1066 | cntl.lanes_number = LANE_COUNT_FOUR; | |
1067 | cntl.coherent = false; | |
1068 | cntl.hpd_sel = enc110->base.hpd_source; | |
1069 | ||
1070 | result = link_transmitter_control(enc110, &cntl); | |
1071 | ||
1072 | if (result != BP_RESULT_OK) { | |
1073 | dm_logger_write(ctx->logger, LOG_ERROR, | |
1074 | "%s: Failed to execute VBIOS command table!\n", | |
1075 | __func__); | |
1076 | BREAK_TO_DEBUGGER(); | |
1077 | return; | |
1078 | } | |
1079 | ||
1080 | if (enc110->base.connector.id == CONNECTOR_ID_LVDS) { | |
1081 | cntl.action = TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS; | |
1082 | ||
1083 | result = link_transmitter_control(enc110, &cntl); | |
1084 | ||
1085 | ASSERT(result == BP_RESULT_OK); | |
1086 | ||
1087 | } else if (enc110->base.connector.id == CONNECTOR_ID_EDP) { | |
1088 | enc->funcs->power_control(&enc110->base, true); | |
1089 | } | |
1090 | aux_initialize(enc110); | |
1091 | ||
1092 | /* reinitialize HPD. | |
1093 | * hpd_initialize() will pass DIG_FE id to HW context. | |
1094 | * All other routine within HW context will use fe_engine_offset | |
1095 | * as DIG_FE id even caller pass DIG_FE id. | |
1096 | * So this routine must be called first. */ | |
1097 | hpd_initialize(enc110); | |
1098 | } | |
1099 | ||
1100 | void dce110_link_encoder_destroy(struct link_encoder **enc) | |
1101 | { | |
1102 | dm_free(TO_DCE110_LINK_ENC(*enc)); | |
1103 | *enc = NULL; | |
1104 | } | |
1105 | ||
1106 | void dce110_link_encoder_setup( | |
1107 | struct link_encoder *enc, | |
1108 | enum signal_type signal) | |
1109 | { | |
1110 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1111 | ||
1112 | switch (signal) { | |
1113 | case SIGNAL_TYPE_EDP: | |
1114 | case SIGNAL_TYPE_DISPLAY_PORT: | |
1115 | /* DP SST */ | |
1116 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 0); | |
1117 | break; | |
1118 | case SIGNAL_TYPE_LVDS: | |
1119 | /* LVDS */ | |
1120 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 1); | |
1121 | break; | |
1122 | case SIGNAL_TYPE_DVI_SINGLE_LINK: | |
1123 | case SIGNAL_TYPE_DVI_DUAL_LINK: | |
1124 | /* TMDS-DVI */ | |
1125 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 2); | |
1126 | break; | |
1127 | case SIGNAL_TYPE_HDMI_TYPE_A: | |
1128 | /* TMDS-HDMI */ | |
1129 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 3); | |
1130 | break; | |
1131 | case SIGNAL_TYPE_DISPLAY_PORT_MST: | |
1132 | /* DP MST */ | |
1133 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 5); | |
1134 | break; | |
1135 | default: | |
1136 | ASSERT_CRITICAL(false); | |
1137 | /* invalid mode ! */ | |
1138 | break; | |
1139 | } | |
1140 | ||
1141 | } | |
1142 | ||
1143 | /* TODO: still need depth or just pass in adjusted pixel clock? */ | |
1144 | void dce110_link_encoder_enable_tmds_output( | |
1145 | struct link_encoder *enc, | |
1146 | enum clock_source_id clock_source, | |
1147 | enum dc_color_depth color_depth, | |
1148 | bool hdmi, | |
1149 | bool dual_link, | |
1150 | uint32_t pixel_clock) | |
1151 | { | |
1152 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1153 | struct dc_context *ctx = enc110->base.ctx; | |
1154 | struct bp_transmitter_control cntl = { 0 }; | |
1155 | enum bp_result result; | |
1156 | ||
1157 | /* Enable the PHY */ | |
1158 | ||
1159 | cntl.action = TRANSMITTER_CONTROL_ENABLE; | |
56bc1c42 | 1160 | cntl.engine_id = enc->preferred_engine; |
4562236b HW |
1161 | cntl.transmitter = enc110->base.transmitter; |
1162 | cntl.pll_id = clock_source; | |
1163 | if (hdmi) { | |
1164 | cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; | |
1165 | cntl.lanes_number = 4; | |
1166 | } else if (dual_link) { | |
1167 | cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; | |
1168 | cntl.lanes_number = 8; | |
1169 | } else { | |
1170 | cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; | |
1171 | cntl.lanes_number = 4; | |
1172 | } | |
1173 | cntl.hpd_sel = enc110->base.hpd_source; | |
1174 | ||
1175 | cntl.pixel_clock = pixel_clock; | |
1176 | cntl.color_depth = color_depth; | |
1177 | ||
1178 | result = link_transmitter_control(enc110, &cntl); | |
1179 | ||
1180 | if (result != BP_RESULT_OK) { | |
1181 | dm_logger_write(ctx->logger, LOG_ERROR, | |
1182 | "%s: Failed to execute VBIOS command table!\n", | |
1183 | __func__); | |
1184 | BREAK_TO_DEBUGGER(); | |
1185 | } | |
1186 | } | |
1187 | ||
1188 | /* enables DP PHY output */ | |
1189 | void dce110_link_encoder_enable_dp_output( | |
1190 | struct link_encoder *enc, | |
1191 | const struct dc_link_settings *link_settings, | |
1192 | enum clock_source_id clock_source) | |
1193 | { | |
1194 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1195 | struct dc_context *ctx = enc110->base.ctx; | |
1196 | struct bp_transmitter_control cntl = { 0 }; | |
1197 | enum bp_result result; | |
1198 | ||
1199 | /* Enable the PHY */ | |
1200 | ||
1201 | /* number_of_lanes is used for pixel clock adjust, | |
1202 | * but it's not passed to asic_control. | |
1203 | * We need to set number of lanes manually. | |
1204 | */ | |
1205 | configure_encoder(enc110, link_settings); | |
1206 | ||
1207 | cntl.action = TRANSMITTER_CONTROL_ENABLE; | |
8e545104 | 1208 | cntl.engine_id = enc->preferred_engine; |
4562236b HW |
1209 | cntl.transmitter = enc110->base.transmitter; |
1210 | cntl.pll_id = clock_source; | |
1211 | cntl.signal = SIGNAL_TYPE_DISPLAY_PORT; | |
1212 | cntl.lanes_number = link_settings->lane_count; | |
1213 | cntl.hpd_sel = enc110->base.hpd_source; | |
1214 | cntl.pixel_clock = link_settings->link_rate | |
1215 | * LINK_RATE_REF_FREQ_IN_KHZ; | |
1216 | /* TODO: check if undefined works */ | |
1217 | cntl.color_depth = COLOR_DEPTH_UNDEFINED; | |
1218 | ||
1219 | result = link_transmitter_control(enc110, &cntl); | |
1220 | ||
1221 | if (result != BP_RESULT_OK) { | |
1222 | dm_logger_write(ctx->logger, LOG_ERROR, | |
1223 | "%s: Failed to execute VBIOS command table!\n", | |
1224 | __func__); | |
1225 | BREAK_TO_DEBUGGER(); | |
1226 | } | |
1227 | } | |
1228 | ||
1229 | /* enables DP PHY output in MST mode */ | |
1230 | void dce110_link_encoder_enable_dp_mst_output( | |
1231 | struct link_encoder *enc, | |
1232 | const struct dc_link_settings *link_settings, | |
1233 | enum clock_source_id clock_source) | |
1234 | { | |
1235 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1236 | struct dc_context *ctx = enc110->base.ctx; | |
1237 | struct bp_transmitter_control cntl = { 0 }; | |
1238 | enum bp_result result; | |
1239 | ||
1240 | /* Enable the PHY */ | |
1241 | ||
1242 | /* number_of_lanes is used for pixel clock adjust, | |
1243 | * but it's not passed to asic_control. | |
1244 | * We need to set number of lanes manually. | |
1245 | */ | |
1246 | configure_encoder(enc110, link_settings); | |
1247 | ||
1248 | cntl.action = TRANSMITTER_CONTROL_ENABLE; | |
1249 | cntl.engine_id = ENGINE_ID_UNKNOWN; | |
1250 | cntl.transmitter = enc110->base.transmitter; | |
1251 | cntl.pll_id = clock_source; | |
1252 | cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST; | |
1253 | cntl.lanes_number = link_settings->lane_count; | |
1254 | cntl.hpd_sel = enc110->base.hpd_source; | |
1255 | cntl.pixel_clock = link_settings->link_rate | |
1256 | * LINK_RATE_REF_FREQ_IN_KHZ; | |
1257 | /* TODO: check if undefined works */ | |
1258 | cntl.color_depth = COLOR_DEPTH_UNDEFINED; | |
1259 | ||
1260 | result = link_transmitter_control(enc110, &cntl); | |
1261 | ||
1262 | if (result != BP_RESULT_OK) { | |
1263 | dm_logger_write(ctx->logger, LOG_ERROR, | |
1264 | "%s: Failed to execute VBIOS command table!\n", | |
1265 | __func__); | |
1266 | BREAK_TO_DEBUGGER(); | |
1267 | } | |
1268 | } | |
1269 | /* | |
1270 | * @brief | |
1271 | * Disable transmitter and its encoder | |
1272 | */ | |
1273 | void dce110_link_encoder_disable_output( | |
1274 | struct link_encoder *enc, | |
1275 | enum signal_type signal) | |
1276 | { | |
1277 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1278 | struct dc_context *ctx = enc110->base.ctx; | |
1279 | struct bp_transmitter_control cntl = { 0 }; | |
1280 | enum bp_result result; | |
1281 | ||
1282 | if (!is_dig_enabled(enc110)) { | |
1283 | /* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */ | |
1284 | return; | |
1285 | } | |
1286 | /* Power-down RX and disable GPU PHY should be paired. | |
1287 | * Disabling PHY without powering down RX may cause | |
1288 | * symbol lock loss, on which we will get DP Sink interrupt. */ | |
1289 | ||
1290 | /* There is a case for the DP active dongles | |
1291 | * where we want to disable the PHY but keep RX powered, | |
1292 | * for those we need to ignore DP Sink interrupt | |
1293 | * by checking lane count that has been set | |
1294 | * on the last do_enable_output(). */ | |
1295 | ||
1296 | /* disable transmitter */ | |
1297 | cntl.action = TRANSMITTER_CONTROL_DISABLE; | |
1298 | cntl.transmitter = enc110->base.transmitter; | |
1299 | cntl.hpd_sel = enc110->base.hpd_source; | |
1300 | cntl.signal = signal; | |
1301 | cntl.connector_obj_id = enc110->base.connector; | |
1302 | ||
1303 | result = link_transmitter_control(enc110, &cntl); | |
1304 | ||
1305 | if (result != BP_RESULT_OK) { | |
1306 | dm_logger_write(ctx->logger, LOG_ERROR, | |
1307 | "%s: Failed to execute VBIOS command table!\n", | |
1308 | __func__); | |
1309 | BREAK_TO_DEBUGGER(); | |
1310 | return; | |
1311 | } | |
1312 | ||
1313 | /* disable encoder */ | |
1314 | if (dc_is_dp_signal(signal)) | |
1315 | link_encoder_disable(enc110); | |
1316 | ||
1317 | if (enc110->base.connector.id == CONNECTOR_ID_EDP) { | |
1318 | /* power down eDP panel */ | |
1319 | /* TODO: Power control cause regression, we should implement | |
1320 | * it properly, for now just comment it. | |
1321 | * | |
1322 | * link_encoder_edp_wait_for_hpd_ready( | |
1323 | link_enc, | |
1324 | link_enc->connector, | |
1325 | false); | |
1326 | ||
1327 | * link_encoder_edp_power_control( | |
1328 | link_enc, false); */ | |
1329 | } | |
1330 | } | |
1331 | ||
1332 | void dce110_link_encoder_dp_set_lane_settings( | |
1333 | struct link_encoder *enc, | |
1334 | const struct link_training_settings *link_settings) | |
1335 | { | |
1336 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1337 | union dpcd_training_lane_set training_lane_set = { { 0 } }; | |
1338 | int32_t lane = 0; | |
1339 | struct bp_transmitter_control cntl = { 0 }; | |
1340 | ||
1341 | if (!link_settings) { | |
1342 | BREAK_TO_DEBUGGER(); | |
1343 | return; | |
1344 | } | |
1345 | ||
1346 | cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS; | |
1347 | cntl.transmitter = enc110->base.transmitter; | |
1348 | cntl.connector_obj_id = enc110->base.connector; | |
1349 | cntl.lanes_number = link_settings->link_settings.lane_count; | |
1350 | cntl.hpd_sel = enc110->base.hpd_source; | |
1351 | cntl.pixel_clock = link_settings->link_settings.link_rate * | |
1352 | LINK_RATE_REF_FREQ_IN_KHZ; | |
1353 | ||
bf5cda33 | 1354 | for (lane = 0; lane < link_settings->link_settings.lane_count; lane++) { |
4562236b HW |
1355 | /* translate lane settings */ |
1356 | ||
1357 | training_lane_set.bits.VOLTAGE_SWING_SET = | |
1358 | link_settings->lane_settings[lane].VOLTAGE_SWING; | |
1359 | training_lane_set.bits.PRE_EMPHASIS_SET = | |
1360 | link_settings->lane_settings[lane].PRE_EMPHASIS; | |
1361 | ||
1362 | /* post cursor 2 setting only applies to HBR2 link rate */ | |
1363 | if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) { | |
1364 | /* this is passed to VBIOS | |
1365 | * to program post cursor 2 level */ | |
1366 | ||
1367 | training_lane_set.bits.POST_CURSOR2_SET = | |
1368 | link_settings->lane_settings[lane].POST_CURSOR2; | |
1369 | } | |
1370 | ||
1371 | cntl.lane_select = lane; | |
1372 | cntl.lane_settings = training_lane_set.raw; | |
1373 | ||
1374 | /* call VBIOS table to set voltage swing and pre-emphasis */ | |
1375 | link_transmitter_control(enc110, &cntl); | |
1376 | } | |
1377 | } | |
1378 | ||
1379 | /* set DP PHY test and training patterns */ | |
1380 | void dce110_link_encoder_dp_set_phy_pattern( | |
1381 | struct link_encoder *enc, | |
1382 | const struct encoder_set_dp_phy_pattern_param *param) | |
1383 | { | |
1384 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1385 | ||
1386 | switch (param->dp_phy_pattern) { | |
1387 | case DP_TEST_PATTERN_TRAINING_PATTERN1: | |
1388 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 0); | |
1389 | break; | |
1390 | case DP_TEST_PATTERN_TRAINING_PATTERN2: | |
1391 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 1); | |
1392 | break; | |
1393 | case DP_TEST_PATTERN_TRAINING_PATTERN3: | |
1394 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 2); | |
1395 | break; | |
d5de97a2 HW |
1396 | case DP_TEST_PATTERN_TRAINING_PATTERN4: |
1397 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 3); | |
1398 | break; | |
4562236b HW |
1399 | case DP_TEST_PATTERN_D102: |
1400 | set_dp_phy_pattern_d102(enc110); | |
1401 | break; | |
1402 | case DP_TEST_PATTERN_SYMBOL_ERROR: | |
1403 | set_dp_phy_pattern_symbol_error(enc110); | |
1404 | break; | |
1405 | case DP_TEST_PATTERN_PRBS7: | |
1406 | set_dp_phy_pattern_prbs7(enc110); | |
1407 | break; | |
1408 | case DP_TEST_PATTERN_80BIT_CUSTOM: | |
1409 | set_dp_phy_pattern_80bit_custom( | |
1410 | enc110, param->custom_pattern); | |
1411 | break; | |
0e19401f TC |
1412 | case DP_TEST_PATTERN_CP2520_1: |
1413 | set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 1); | |
1414 | break; | |
1415 | case DP_TEST_PATTERN_CP2520_2: | |
1416 | set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 2); | |
4562236b | 1417 | break; |
fcbb5ad3 TC |
1418 | case DP_TEST_PATTERN_CP2520_3: |
1419 | set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 3); | |
1420 | break; | |
4562236b HW |
1421 | case DP_TEST_PATTERN_VIDEO_MODE: { |
1422 | set_dp_phy_pattern_passthrough_mode( | |
1423 | enc110, param->dp_panel_mode); | |
1424 | break; | |
1425 | } | |
1426 | ||
1427 | default: | |
1428 | /* invalid phy pattern */ | |
1429 | ASSERT_CRITICAL(false); | |
1430 | break; | |
1431 | } | |
1432 | } | |
1433 | ||
1434 | static void fill_stream_allocation_row_info( | |
1435 | const struct link_mst_stream_allocation *stream_allocation, | |
1436 | uint32_t *src, | |
1437 | uint32_t *slots) | |
1438 | { | |
1439 | const struct stream_encoder *stream_enc = stream_allocation->stream_enc; | |
1440 | ||
1441 | if (stream_enc) { | |
1442 | *src = stream_enc->id; | |
1443 | *slots = stream_allocation->slot_count; | |
1444 | } else { | |
1445 | *src = 0; | |
1446 | *slots = 0; | |
1447 | } | |
1448 | } | |
1449 | ||
1450 | /* programs DP MST VC payload allocation */ | |
1451 | void dce110_link_encoder_update_mst_stream_allocation_table( | |
1452 | struct link_encoder *enc, | |
1453 | const struct link_mst_stream_allocation_table *table) | |
1454 | { | |
1455 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1456 | uint32_t value0 = 0; | |
1457 | uint32_t value1 = 0; | |
1458 | uint32_t value2 = 0; | |
1459 | uint32_t slots = 0; | |
1460 | uint32_t src = 0; | |
1461 | uint32_t retries = 0; | |
1462 | ||
1463 | /* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/ | |
1464 | ||
1465 | /* --- Set MSE Stream Attribute - | |
1466 | * Setup VC Payload Table on Tx Side, | |
1467 | * Issue allocation change trigger | |
1468 | * to commit payload on both tx and rx side */ | |
1469 | ||
1470 | /* we should clean-up table each time */ | |
1471 | ||
1472 | if (table->stream_count >= 1) { | |
1473 | fill_stream_allocation_row_info( | |
1474 | &table->stream_allocations[0], | |
1475 | &src, | |
1476 | &slots); | |
1477 | } else { | |
1478 | src = 0; | |
1479 | slots = 0; | |
1480 | } | |
1481 | ||
1482 | REG_UPDATE_2(DP_MSE_SAT0, | |
1483 | DP_MSE_SAT_SRC0, src, | |
1484 | DP_MSE_SAT_SLOT_COUNT0, slots); | |
1485 | ||
1486 | if (table->stream_count >= 2) { | |
1487 | fill_stream_allocation_row_info( | |
1488 | &table->stream_allocations[1], | |
1489 | &src, | |
1490 | &slots); | |
1491 | } else { | |
1492 | src = 0; | |
1493 | slots = 0; | |
1494 | } | |
1495 | ||
1496 | REG_UPDATE_2(DP_MSE_SAT0, | |
1497 | DP_MSE_SAT_SRC1, src, | |
1498 | DP_MSE_SAT_SLOT_COUNT1, slots); | |
1499 | ||
1500 | if (table->stream_count >= 3) { | |
1501 | fill_stream_allocation_row_info( | |
1502 | &table->stream_allocations[2], | |
1503 | &src, | |
1504 | &slots); | |
1505 | } else { | |
1506 | src = 0; | |
1507 | slots = 0; | |
1508 | } | |
1509 | ||
1510 | REG_UPDATE_2(DP_MSE_SAT1, | |
1511 | DP_MSE_SAT_SRC2, src, | |
1512 | DP_MSE_SAT_SLOT_COUNT2, slots); | |
1513 | ||
1514 | if (table->stream_count >= 4) { | |
1515 | fill_stream_allocation_row_info( | |
1516 | &table->stream_allocations[3], | |
1517 | &src, | |
1518 | &slots); | |
1519 | } else { | |
1520 | src = 0; | |
1521 | slots = 0; | |
1522 | } | |
1523 | ||
1524 | REG_UPDATE_2(DP_MSE_SAT1, | |
1525 | DP_MSE_SAT_SRC3, src, | |
1526 | DP_MSE_SAT_SLOT_COUNT3, slots); | |
1527 | ||
1528 | /* --- wait for transaction finish */ | |
1529 | ||
1530 | /* send allocation change trigger (ACT) ? | |
1531 | * this step first sends the ACT, | |
1532 | * then double buffers the SAT into the hardware | |
1533 | * making the new allocation active on the DP MST mode link */ | |
1534 | ||
1535 | ||
1536 | /* DP_MSE_SAT_UPDATE: | |
1537 | * 0 - No Action | |
1538 | * 1 - Update SAT with trigger | |
1539 | * 2 - Update SAT without trigger */ | |
1540 | ||
1541 | REG_UPDATE(DP_MSE_SAT_UPDATE, | |
1542 | DP_MSE_SAT_UPDATE, 1); | |
1543 | ||
1544 | /* wait for update to complete | |
1545 | * (i.e. DP_MSE_SAT_UPDATE field is reset to 0) | |
1546 | * then wait for the transmission | |
1547 | * of at least 16 MTP headers on immediate local link. | |
1548 | * i.e. DP_MSE_16_MTP_KEEPOUT field (read only) is reset to 0 | |
1549 | * a value of 1 indicates that DP MST mode | |
1550 | * is in the 16 MTP keepout region after a VC has been added. | |
1551 | * MST stream bandwidth (VC rate) can be configured | |
1552 | * after this bit is cleared */ | |
1553 | ||
1554 | do { | |
1555 | udelay(10); | |
1556 | ||
1557 | value0 = REG_READ(DP_MSE_SAT_UPDATE); | |
1558 | ||
1559 | REG_GET(DP_MSE_SAT_UPDATE, | |
1560 | DP_MSE_SAT_UPDATE, &value1); | |
1561 | ||
1562 | REG_GET(DP_MSE_SAT_UPDATE, | |
1563 | DP_MSE_16_MTP_KEEPOUT, &value2); | |
1564 | ||
1565 | /* bit field DP_MSE_SAT_UPDATE is set to 1 already */ | |
1566 | if (!value1 && !value2) | |
1567 | break; | |
1568 | ++retries; | |
1569 | } while (retries < DP_MST_UPDATE_MAX_RETRY); | |
1570 | } | |
1571 | ||
4562236b HW |
1572 | void dce110_link_encoder_connect_dig_be_to_fe( |
1573 | struct link_encoder *enc, | |
1574 | enum engine_id engine, | |
1575 | bool connect) | |
1576 | { | |
1577 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1578 | uint32_t field; | |
1579 | ||
1580 | if (engine != ENGINE_ID_UNKNOWN) { | |
1581 | ||
1582 | REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &field); | |
1583 | ||
1584 | if (connect) | |
1585 | field |= get_frontend_source(engine); | |
1586 | else | |
1587 | field &= ~get_frontend_source(engine); | |
1588 | ||
1589 | REG_UPDATE(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, field); | |
1590 | } | |
1591 | } | |
1592 | ||
1593 | void dce110_link_encoder_enable_hpd(struct link_encoder *enc) | |
1594 | { | |
1595 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1596 | struct dc_context *ctx = enc110->base.ctx; | |
1597 | uint32_t addr = HPD_REG(DC_HPD_CONTROL); | |
1598 | uint32_t hpd_enable = 0; | |
1599 | uint32_t value = dm_read_reg(ctx, addr); | |
1600 | ||
1601 | get_reg_field_value(hpd_enable, DC_HPD_CONTROL, DC_HPD_EN); | |
1602 | ||
1603 | if (hpd_enable == 0) | |
1604 | set_reg_field_value(value, 1, DC_HPD_CONTROL, DC_HPD_EN); | |
1605 | } | |
1606 | ||
1607 | void dce110_link_encoder_disable_hpd(struct link_encoder *enc) | |
1608 | { | |
1609 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); | |
1610 | struct dc_context *ctx = enc110->base.ctx; | |
1611 | uint32_t addr = HPD_REG(DC_HPD_CONTROL); | |
1612 | uint32_t value = dm_read_reg(ctx, addr); | |
1613 | ||
1614 | set_reg_field_value(value, 0, DC_HPD_CONTROL, DC_HPD_EN); | |
1615 | } |