File: | dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c |
Warning: | line 307, column 2 Value stored to 'value' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
41 | #ifndef DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE__SHIFT0xa |
42 | #define DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE__SHIFT0xa 0xa |
43 | #endif |
44 | |
45 | #ifndef DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE_MASK0x00000400L |
46 | #define DMU_MEM_PWR_CNTL__DMCU_IRAM_MEM_PWR_STATE_MASK0x00000400L 0x00000400L |
47 | #endif |
48 | |
49 | #ifndef HPD0_DC_HPD_CONTROL__DC_HPD_EN_MASK0x10000000L |
50 | #define HPD0_DC_HPD_CONTROL__DC_HPD_EN_MASK0x10000000L 0x10000000L |
51 | #endif |
52 | |
53 | #ifndef HPD0_DC_HPD_CONTROL__DC_HPD_EN__SHIFT0x1c |
54 | #define HPD0_DC_HPD_CONTROL__DC_HPD_EN__SHIFT0x1c 0x1c |
55 | #endif |
56 | |
57 | #define CTXenc110->base.ctx \ |
58 | enc110->base.ctx |
59 | #define DC_LOGGERenc110->base.ctx->logger \ |
60 | enc110->base.ctx->logger |
61 | |
62 | #define REG(reg)(enc110->link_regs->reg)\ |
63 | (enc110->link_regs->reg) |
64 | |
65 | #define AUX_REG(reg)(enc110->aux_regs->reg)\ |
66 | (enc110->aux_regs->reg) |
67 | |
68 | #define HPD_REG(reg)(enc110->hpd_regs->reg)\ |
69 | (enc110->hpd_regs->reg) |
70 | |
71 | #define DEFAULT_AUX_MAX_DATA_SIZE16 16 |
72 | #define AUX_MAX_DEFER_WRITE_RETRY20 20 |
73 | /* |
74 | * @brief |
75 | * Trigger Source Select |
76 | * ASIC-dependent, actual values for register programming |
77 | */ |
78 | #define DCE110_DIG_FE_SOURCE_SELECT_INVALID0x0 0x0 |
79 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGA0x1 0x1 |
80 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGB0x2 0x2 |
81 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGC0x4 0x4 |
82 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGD0x08 0x08 |
83 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGE0x10 0x10 |
84 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGF0x20 0x20 |
85 | #define DCE110_DIG_FE_SOURCE_SELECT_DIGG0x40 0x40 |
86 | |
87 | enum { |
88 | DP_MST_UPDATE_MAX_RETRY = 50 |
89 | }; |
90 | |
91 | #define DIG_REG(reg)(reg + enc110->offsets.dig)\ |
92 | (reg + enc110->offsets.dig) |
93 | |
94 | #define DP_REG(reg)(reg + enc110->offsets.dp)\ |
95 | (reg + enc110->offsets.dp) |
96 | |
97 | static const struct link_encoder_funcs dce110_lnk_enc_funcs = { |
98 | .validate_output_with_stream = |
99 | dce110_link_encoder_validate_output_with_stream, |
100 | .hw_init = dce110_link_encoder_hw_init, |
101 | .setup = dce110_link_encoder_setup, |
102 | .enable_tmds_output = dce110_link_encoder_enable_tmds_output, |
103 | .enable_dp_output = dce110_link_encoder_enable_dp_output, |
104 | .enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output, |
105 | .enable_lvds_output = dce110_link_encoder_enable_lvds_output, |
106 | .disable_output = dce110_link_encoder_disable_output, |
107 | .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, |
108 | .dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern, |
109 | .update_mst_stream_allocation_table = |
110 | dce110_link_encoder_update_mst_stream_allocation_table, |
111 | .psr_program_dp_dphy_fast_training = |
112 | dce110_psr_program_dp_dphy_fast_training, |
113 | .psr_program_secondary_packet = dce110_psr_program_secondary_packet, |
114 | .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe, |
115 | .enable_hpd = dce110_link_encoder_enable_hpd, |
116 | .disable_hpd = dce110_link_encoder_disable_hpd, |
117 | .is_dig_enabled = dce110_is_dig_enabled, |
118 | .destroy = dce110_link_encoder_destroy, |
119 | .get_max_link_cap = dce110_link_encoder_get_max_link_cap, |
120 | .get_dig_frontend = dce110_get_dig_frontend, |
121 | }; |
122 | |
123 | static enum bp_result link_transmitter_control( |
124 | struct dce110_link_encoder *enc110, |
125 | struct bp_transmitter_control *cntl) |
126 | { |
127 | enum bp_result result; |
128 | struct dc_bios *bp = enc110->base.ctx->dc_bios; |
129 | |
130 | result = bp->funcs->transmitter_control(bp, cntl); |
131 | |
132 | return result; |
133 | } |
134 | |
135 | static void enable_phy_bypass_mode( |
136 | struct dce110_link_encoder *enc110, |
137 | bool_Bool enable) |
138 | { |
139 | /* This register resides in DP back end block; |
140 | * transmitter is used for the offset */ |
141 | |
142 | REG_UPDATE(DP_DPHY_CNTL, DPHY_BYPASS, enable)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_CNTL), 1, 0x10, 0x10000, enable); |
143 | |
144 | } |
145 | |
146 | static void disable_prbs_symbols( |
147 | struct dce110_link_encoder *enc110, |
148 | bool_Bool disable) |
149 | { |
150 | /* This register resides in DP back end block; |
151 | * transmitter is used for the offset */ |
152 | |
153 | REG_UPDATE_4(DP_DPHY_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_CNTL), 4, 0x0, 0x1, disable, 0x1, 0x2, disable, 0x2 , 0x4, disable, 0x3, 0x8, disable) |
154 | DPHY_ATEST_SEL_LANE0, disable,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_CNTL), 4, 0x0, 0x1, disable, 0x1, 0x2, disable, 0x2 , 0x4, disable, 0x3, 0x8, disable) |
155 | DPHY_ATEST_SEL_LANE1, disable,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_CNTL), 4, 0x0, 0x1, disable, 0x1, 0x2, disable, 0x2 , 0x4, disable, 0x3, 0x8, disable) |
156 | DPHY_ATEST_SEL_LANE2, disable,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_CNTL), 4, 0x0, 0x1, disable, 0x1, 0x2, disable, 0x2 , 0x4, disable, 0x3, 0x8, disable) |
157 | DPHY_ATEST_SEL_LANE3, disable)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_CNTL), 4, 0x0, 0x1, disable, 0x1, 0x2, disable, 0x2 , 0x4, disable, 0x3, 0x8, disable); |
158 | } |
159 | |
160 | static void disable_prbs_mode( |
161 | struct dce110_link_encoder *enc110) |
162 | { |
163 | REG_UPDATE(DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 1, 0x0, 0x1, 0); |
164 | } |
165 | |
166 | static void program_pattern_symbols( |
167 | struct dce110_link_encoder *enc110, |
168 | uint16_t pattern_symbols[8]) |
169 | { |
170 | /* This register resides in DP back end block; |
171 | * transmitter is used for the offset */ |
172 | |
173 | REG_SET_3(DP_DPHY_SYM0, 0,generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM0), 0, 3, 0x0, 0x3ff, pattern_symbols[0], 0xa , 0xffc00, pattern_symbols[1], 0x14, 0x3ff00000, pattern_symbols [2]) |
174 | DPHY_SYM1, pattern_symbols[0],generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM0), 0, 3, 0x0, 0x3ff, pattern_symbols[0], 0xa , 0xffc00, pattern_symbols[1], 0x14, 0x3ff00000, pattern_symbols [2]) |
175 | DPHY_SYM2, pattern_symbols[1],generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM0), 0, 3, 0x0, 0x3ff, pattern_symbols[0], 0xa , 0xffc00, pattern_symbols[1], 0x14, 0x3ff00000, pattern_symbols [2]) |
176 | DPHY_SYM3, pattern_symbols[2])generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM0), 0, 3, 0x0, 0x3ff, pattern_symbols[0], 0xa , 0xffc00, pattern_symbols[1], 0x14, 0x3ff00000, pattern_symbols [2]); |
177 | |
178 | /* This register resides in DP back end block; |
179 | * transmitter is used for the offset */ |
180 | |
181 | REG_SET_3(DP_DPHY_SYM1, 0,generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM1), 0, 3, 0x0, 0x3ff, pattern_symbols[3], 0xa , 0xffc00, pattern_symbols[4], 0x14, 0x3ff00000, pattern_symbols [5]) |
182 | DPHY_SYM4, pattern_symbols[3],generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM1), 0, 3, 0x0, 0x3ff, pattern_symbols[3], 0xa , 0xffc00, pattern_symbols[4], 0x14, 0x3ff00000, pattern_symbols [5]) |
183 | DPHY_SYM5, pattern_symbols[4],generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM1), 0, 3, 0x0, 0x3ff, pattern_symbols[3], 0xa , 0xffc00, pattern_symbols[4], 0x14, 0x3ff00000, pattern_symbols [5]) |
184 | DPHY_SYM6, pattern_symbols[5])generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM1), 0, 3, 0x0, 0x3ff, pattern_symbols[3], 0xa , 0xffc00, pattern_symbols[4], 0x14, 0x3ff00000, pattern_symbols [5]); |
185 | |
186 | /* This register resides in DP back end block; |
187 | * transmitter is used for the offset */ |
188 | |
189 | REG_SET_2(DP_DPHY_SYM2, 0,generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM2), 0, 2, 0x0, 0x3ff, pattern_symbols[6], 0xa , 0xffc00, pattern_symbols[7]) |
190 | DPHY_SYM7, pattern_symbols[6],generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM2), 0, 2, 0x0, 0x3ff, pattern_symbols[6], 0xa , 0xffc00, pattern_symbols[7]) |
191 | DPHY_SYM8, pattern_symbols[7])generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SYM2), 0, 2, 0x0, 0x3ff, pattern_symbols[6], 0xa , 0xffc00, pattern_symbols[7]); |
192 | } |
193 | |
194 | static void set_dp_phy_pattern_d102( |
195 | struct dce110_link_encoder *enc110) |
196 | { |
197 | /* Disable PHY Bypass mode to setup the test pattern */ |
198 | enable_phy_bypass_mode(enc110, false0); |
199 | |
200 | /* For 10-bit PRBS or debug symbols |
201 | * please use the following sequence: */ |
202 | |
203 | /* Enable debug symbols on the lanes */ |
204 | |
205 | disable_prbs_symbols(enc110, true1); |
206 | |
207 | /* Disable PRBS mode */ |
208 | disable_prbs_mode(enc110); |
209 | |
210 | /* Program debug symbols to be output */ |
211 | { |
212 | uint16_t pattern_symbols[8] = { |
213 | 0x2AA, 0x2AA, 0x2AA, 0x2AA, |
214 | 0x2AA, 0x2AA, 0x2AA, 0x2AA |
215 | }; |
216 | |
217 | program_pattern_symbols(enc110, pattern_symbols); |
218 | } |
219 | |
220 | /* Enable phy bypass mode to enable the test pattern */ |
221 | |
222 | enable_phy_bypass_mode(enc110, true1); |
223 | } |
224 | |
225 | static void set_link_training_complete( |
226 | struct dce110_link_encoder *enc110, |
227 | bool_Bool complete) |
228 | { |
229 | /* This register resides in DP back end block; |
230 | * transmitter is used for the offset */ |
231 | |
232 | REG_UPDATE(DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE, complete)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_CNTL), 1, 0x4, 0x10, complete); |
233 | |
234 | } |
235 | |
236 | unsigned int dce110_get_dig_frontend(struct link_encoder *enc) |
237 | { |
238 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
239 | u32 value; |
240 | enum engine_id result; |
241 | |
242 | REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value)generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DIG_BE_CNTL), 0x8, 0x7f00, &value); |
243 | |
244 | switch (value) { |
245 | case DCE110_DIG_FE_SOURCE_SELECT_DIGA0x1: |
246 | result = ENGINE_ID_DIGA; |
247 | break; |
248 | case DCE110_DIG_FE_SOURCE_SELECT_DIGB0x2: |
249 | result = ENGINE_ID_DIGB; |
250 | break; |
251 | case DCE110_DIG_FE_SOURCE_SELECT_DIGC0x4: |
252 | result = ENGINE_ID_DIGC; |
253 | break; |
254 | case DCE110_DIG_FE_SOURCE_SELECT_DIGD0x08: |
255 | result = ENGINE_ID_DIGD; |
256 | break; |
257 | case DCE110_DIG_FE_SOURCE_SELECT_DIGE0x10: |
258 | result = ENGINE_ID_DIGE; |
259 | break; |
260 | case DCE110_DIG_FE_SOURCE_SELECT_DIGF0x20: |
261 | result = ENGINE_ID_DIGF; |
262 | break; |
263 | case DCE110_DIG_FE_SOURCE_SELECT_DIGG0x40: |
264 | result = ENGINE_ID_DIGG; |
265 | break; |
266 | default: |
267 | // invalid source select DIG |
268 | result = ENGINE_ID_UNKNOWN; |
269 | } |
270 | |
271 | return result; |
272 | } |
273 | |
274 | void dce110_link_encoder_set_dp_phy_pattern_training_pattern( |
275 | struct link_encoder *enc, |
276 | uint32_t index) |
277 | { |
278 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
279 | /* Write Training Pattern */ |
280 | |
281 | REG_WRITE(DP_DPHY_TRAINING_PATTERN_SEL, index)dm_write_reg_func(enc110->base.ctx, (enc110->link_regs-> DP_DPHY_TRAINING_PATTERN_SEL), index, __func__); |
282 | |
283 | /* Set HW Register Training Complete to false */ |
284 | |
285 | set_link_training_complete(enc110, false0); |
286 | |
287 | /* Disable PHY Bypass mode to output Training Pattern */ |
288 | |
289 | enable_phy_bypass_mode(enc110, false0); |
290 | |
291 | /* Disable PRBS mode */ |
292 | disable_prbs_mode(enc110); |
293 | } |
294 | |
295 | static void setup_panel_mode( |
296 | struct dce110_link_encoder *enc110, |
297 | enum dp_panel_mode panel_mode) |
298 | { |
299 | uint32_t value; |
300 | struct dc_context *ctx = enc110->base.ctx; |
301 | |
302 | /* if psp set panel mode, dal should be program it */ |
303 | if (ctx->dc->caps.psp_setup_panel_mode) |
304 | return; |
305 | |
306 | ASSERT(REG(DP_DPHY_INTERNAL_CTRL))do { if (({ static int __warned; int __ret = !!(!((enc110-> link_regs->DP_DPHY_INTERNAL_CTRL))); if (__ret && ! __warned) { printf("WARNING %s failed at %s:%d\n", "!((enc110->link_regs->DP_DPHY_INTERNAL_CTRL))" , "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 306); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
307 | value = REG_READ(DP_DPHY_INTERNAL_CTRL)dm_read_reg_func(enc110->base.ctx, (enc110->link_regs-> DP_DPHY_INTERNAL_CTRL), __func__); |
Value stored to 'value' is never read | |
308 | |
309 | switch (panel_mode) { |
310 | case DP_PANEL_MODE_EDP: |
311 | value = 0x1; |
312 | break; |
313 | case DP_PANEL_MODE_SPECIAL: |
314 | value = 0x11; |
315 | break; |
316 | default: |
317 | value = 0x0; |
318 | break; |
319 | } |
320 | |
321 | REG_WRITE(DP_DPHY_INTERNAL_CTRL, value)dm_write_reg_func(enc110->base.ctx, (enc110->link_regs-> DP_DPHY_INTERNAL_CTRL), value, __func__); |
322 | } |
323 | |
324 | static void set_dp_phy_pattern_symbol_error( |
325 | struct dce110_link_encoder *enc110) |
326 | { |
327 | /* Disable PHY Bypass mode to setup the test pattern */ |
328 | enable_phy_bypass_mode(enc110, false0); |
329 | |
330 | /* program correct panel mode*/ |
331 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); |
332 | |
333 | /* A PRBS23 pattern is used for most DP electrical measurements. */ |
334 | |
335 | /* Enable PRBS symbols on the lanes */ |
336 | disable_prbs_symbols(enc110, false0); |
337 | |
338 | /* For PRBS23 Set bit DPHY_PRBS_SEL=1 and Set bit DPHY_PRBS_EN=1 */ |
339 | REG_UPDATE_2(DP_DPHY_PRBS_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 2, 0x4, 0x30, 1, 0x0, 0x1, 1) |
340 | DPHY_PRBS_SEL, 1,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 2, 0x4, 0x30, 1, 0x0, 0x1, 1) |
341 | DPHY_PRBS_EN, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 2, 0x4, 0x30, 1, 0x0, 0x1, 1); |
342 | |
343 | /* Enable phy bypass mode to enable the test pattern */ |
344 | enable_phy_bypass_mode(enc110, true1); |
345 | } |
346 | |
347 | static void set_dp_phy_pattern_prbs7( |
348 | struct dce110_link_encoder *enc110) |
349 | { |
350 | /* Disable PHY Bypass mode to setup the test pattern */ |
351 | enable_phy_bypass_mode(enc110, false0); |
352 | |
353 | /* A PRBS7 pattern is used for most DP electrical measurements. */ |
354 | |
355 | /* Enable PRBS symbols on the lanes */ |
356 | disable_prbs_symbols(enc110, false0); |
357 | |
358 | /* For PRBS7 Set bit DPHY_PRBS_SEL=0 and Set bit DPHY_PRBS_EN=1 */ |
359 | REG_UPDATE_2(DP_DPHY_PRBS_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 2, 0x4, 0x30, 0, 0x0, 0x1, 1) |
360 | DPHY_PRBS_SEL, 0,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 2, 0x4, 0x30, 0, 0x0, 0x1, 1) |
361 | DPHY_PRBS_EN, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_PRBS_CNTL), 2, 0x4, 0x30, 0, 0x0, 0x1, 1); |
362 | |
363 | /* Enable phy bypass mode to enable the test pattern */ |
364 | enable_phy_bypass_mode(enc110, true1); |
365 | } |
366 | |
367 | static void set_dp_phy_pattern_80bit_custom( |
368 | struct dce110_link_encoder *enc110, |
369 | const uint8_t *pattern) |
370 | { |
371 | /* Disable PHY Bypass mode to setup the test pattern */ |
372 | enable_phy_bypass_mode(enc110, false0); |
373 | |
374 | /* Enable debug symbols on the lanes */ |
375 | |
376 | disable_prbs_symbols(enc110, true1); |
377 | |
378 | /* Enable PHY bypass mode to enable the test pattern */ |
379 | /* TODO is it really needed ? */ |
380 | |
381 | enable_phy_bypass_mode(enc110, true1); |
382 | |
383 | /* Program 80 bit custom pattern */ |
384 | { |
385 | uint16_t pattern_symbols[8]; |
386 | |
387 | pattern_symbols[0] = |
388 | ((pattern[1] & 0x03) << 8) | pattern[0]; |
389 | pattern_symbols[1] = |
390 | ((pattern[2] & 0x0f) << 6) | ((pattern[1] >> 2) & 0x3f); |
391 | pattern_symbols[2] = |
392 | ((pattern[3] & 0x3f) << 4) | ((pattern[2] >> 4) & 0x0f); |
393 | pattern_symbols[3] = |
394 | (pattern[4] << 2) | ((pattern[3] >> 6) & 0x03); |
395 | pattern_symbols[4] = |
396 | ((pattern[6] & 0x03) << 8) | pattern[5]; |
397 | pattern_symbols[5] = |
398 | ((pattern[7] & 0x0f) << 6) | ((pattern[6] >> 2) & 0x3f); |
399 | pattern_symbols[6] = |
400 | ((pattern[8] & 0x3f) << 4) | ((pattern[7] >> 4) & 0x0f); |
401 | pattern_symbols[7] = |
402 | (pattern[9] << 2) | ((pattern[8] >> 6) & 0x03); |
403 | |
404 | program_pattern_symbols(enc110, pattern_symbols); |
405 | } |
406 | |
407 | /* Enable phy bypass mode to enable the test pattern */ |
408 | |
409 | enable_phy_bypass_mode(enc110, true1); |
410 | } |
411 | |
412 | static void set_dp_phy_pattern_hbr2_compliance_cp2520_2( |
413 | struct dce110_link_encoder *enc110, |
414 | unsigned int cp2520_pattern) |
415 | { |
416 | |
417 | /* previously there is a register DP_HBR2_EYE_PATTERN |
418 | * that is enabled to get the pattern. |
419 | * But it does not work with the latest spec change, |
420 | * so we are programming the following registers manually. |
421 | * |
422 | * The following settings have been confirmed |
423 | * by Nick Chorney and Sandra Liu */ |
424 | |
425 | /* Disable PHY Bypass mode to setup the test pattern */ |
426 | |
427 | enable_phy_bypass_mode(enc110, false0); |
428 | |
429 | /* Setup DIG encoder in DP SST mode */ |
430 | enc110->base.funcs->setup(&enc110->base, SIGNAL_TYPE_DISPLAY_PORT); |
431 | |
432 | /* ensure normal panel mode. */ |
433 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); |
434 | |
435 | /* no vbid after BS (SR) |
436 | * DP_LINK_FRAMING_CNTL changed history Sandra Liu |
437 | * 11000260 / 11000104 / 110000FC */ |
438 | REG_UPDATE_3(DP_LINK_FRAMING_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1) |
439 | DP_IDLE_BS_INTERVAL, 0xFC,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1) |
440 | DP_VBID_DISABLE, 1,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1) |
441 | DP_VID_ENHANCED_FRAME_MODE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1); |
442 | |
443 | /* swap every BS with SR */ |
444 | REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_BS_COUNT, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SCRAM_CNTL), 1, 0x8, 0x3ff00, 0); |
445 | |
446 | /* select cp2520 patterns */ |
447 | if (REG(DP_DPHY_HBR2_PATTERN_CONTROL)(enc110->link_regs->DP_DPHY_HBR2_PATTERN_CONTROL)) |
448 | REG_UPDATE(DP_DPHY_HBR2_PATTERN_CONTROL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_HBR2_PATTERN_CONTROL), 1, 0x0, 0x7, cp2520_pattern ) |
449 | DP_DPHY_HBR2_PATTERN_CONTROL, cp2520_pattern)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_HBR2_PATTERN_CONTROL), 1, 0x0, 0x7, cp2520_pattern ); |
450 | else |
451 | /* pre-DCE11 can only generate CP2520 pattern 2 */ |
452 | ASSERT(cp2520_pattern == 2)do { if (({ static int __warned; int __ret = !!(!(cp2520_pattern == 2)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(cp2520_pattern == 2)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 452); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
453 | |
454 | /* set link training complete */ |
455 | set_link_training_complete(enc110, true1); |
456 | |
457 | /* disable video stream */ |
458 | REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_VID_STREAM_CNTL), 1, 0x0, 0x1, 0); |
459 | |
460 | /* Disable PHY Bypass mode to setup the test pattern */ |
461 | enable_phy_bypass_mode(enc110, false0); |
462 | } |
463 | |
464 | #if defined(CONFIG_DRM_AMD_DC_SI) |
465 | static void dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2( |
466 | struct dce110_link_encoder *enc110, |
467 | unsigned int cp2520_pattern) |
468 | { |
469 | |
470 | /* previously there is a register DP_HBR2_EYE_PATTERN |
471 | * that is enabled to get the pattern. |
472 | * But it does not work with the latest spec change, |
473 | * so we are programming the following registers manually. |
474 | * |
475 | * The following settings have been confirmed |
476 | * by Nick Chorney and Sandra Liu */ |
477 | |
478 | /* Disable PHY Bypass mode to setup the test pattern */ |
479 | |
480 | enable_phy_bypass_mode(enc110, false0); |
481 | |
482 | /* Setup DIG encoder in DP SST mode */ |
483 | enc110->base.funcs->setup(&enc110->base, SIGNAL_TYPE_DISPLAY_PORT); |
484 | |
485 | /* ensure normal panel mode. */ |
486 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); |
487 | |
488 | /* no vbid after BS (SR) |
489 | * DP_LINK_FRAMING_CNTL changed history Sandra Liu |
490 | * 11000260 / 11000104 / 110000FC */ |
491 | REG_UPDATE_3(DP_LINK_FRAMING_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1) |
492 | DP_IDLE_BS_INTERVAL, 0xFC,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1) |
493 | DP_VBID_DISABLE, 1,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1) |
494 | DP_VID_ENHANCED_FRAME_MODE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0xFC, 0x18, 0x1000000 , 1, 0x1c, 0x10000000, 1); |
495 | |
496 | /* DCE6 has no DP_DPHY_SCRAM_CNTL register, skip swap BS with SR */ |
497 | |
498 | /* select cp2520 patterns */ |
499 | if (REG(DP_DPHY_HBR2_PATTERN_CONTROL)(enc110->link_regs->DP_DPHY_HBR2_PATTERN_CONTROL)) |
500 | REG_UPDATE(DP_DPHY_HBR2_PATTERN_CONTROL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_HBR2_PATTERN_CONTROL), 1, 0x0, 0x7, cp2520_pattern ) |
501 | DP_DPHY_HBR2_PATTERN_CONTROL, cp2520_pattern)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_HBR2_PATTERN_CONTROL), 1, 0x0, 0x7, cp2520_pattern ); |
502 | else |
503 | /* pre-DCE11 can only generate CP2520 pattern 2 */ |
504 | ASSERT(cp2520_pattern == 2)do { if (({ static int __warned; int __ret = !!(!(cp2520_pattern == 2)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(cp2520_pattern == 2)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 504); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
505 | |
506 | /* set link training complete */ |
507 | set_link_training_complete(enc110, true1); |
508 | |
509 | /* disable video stream */ |
510 | REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_VID_STREAM_CNTL), 1, 0x0, 0x1, 0); |
511 | |
512 | /* Disable PHY Bypass mode to setup the test pattern */ |
513 | enable_phy_bypass_mode(enc110, false0); |
514 | } |
515 | #endif |
516 | |
517 | static void set_dp_phy_pattern_passthrough_mode( |
518 | struct dce110_link_encoder *enc110, |
519 | enum dp_panel_mode panel_mode) |
520 | { |
521 | /* program correct panel mode */ |
522 | setup_panel_mode(enc110, panel_mode); |
523 | |
524 | /* restore LINK_FRAMING_CNTL and DPHY_SCRAMBLER_BS_COUNT |
525 | * in case we were doing HBR2 compliance pattern before |
526 | */ |
527 | REG_UPDATE_3(DP_LINK_FRAMING_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1) |
528 | DP_IDLE_BS_INTERVAL, 0x2000,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1) |
529 | DP_VBID_DISABLE, 0,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1) |
530 | DP_VID_ENHANCED_FRAME_MODE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1); |
531 | |
532 | REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_BS_COUNT, 0x1FF)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SCRAM_CNTL), 1, 0x8, 0x3ff00, 0x1FF); |
533 | |
534 | /* set link training complete */ |
535 | set_link_training_complete(enc110, true1); |
536 | |
537 | /* Disable PHY Bypass mode to setup the test pattern */ |
538 | enable_phy_bypass_mode(enc110, false0); |
539 | |
540 | /* Disable PRBS mode */ |
541 | disable_prbs_mode(enc110); |
542 | } |
543 | |
544 | #if defined(CONFIG_DRM_AMD_DC_SI) |
545 | static void dce60_set_dp_phy_pattern_passthrough_mode( |
546 | struct dce110_link_encoder *enc110, |
547 | enum dp_panel_mode panel_mode) |
548 | { |
549 | /* program correct panel mode */ |
550 | setup_panel_mode(enc110, panel_mode); |
551 | |
552 | /* restore LINK_FRAMING_CNTL |
553 | * in case we were doing HBR2 compliance pattern before |
554 | */ |
555 | REG_UPDATE_3(DP_LINK_FRAMING_CNTL,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1) |
556 | DP_IDLE_BS_INTERVAL, 0x2000,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1) |
557 | DP_VBID_DISABLE, 0,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1) |
558 | DP_VID_ENHANCED_FRAME_MODE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_FRAMING_CNTL), 3, 0x0, 0x3ffff, 0x2000, 0x18, 0x1000000 , 0, 0x1c, 0x10000000, 1); |
559 | |
560 | /* DCE6 has no DP_DPHY_SCRAM_CNTL register, skip DPHY_SCRAMBLER_BS_COUNT restore */ |
561 | |
562 | /* set link training complete */ |
563 | set_link_training_complete(enc110, true1); |
564 | |
565 | /* Disable PHY Bypass mode to setup the test pattern */ |
566 | enable_phy_bypass_mode(enc110, false0); |
567 | |
568 | /* Disable PRBS mode */ |
569 | disable_prbs_mode(enc110); |
570 | } |
571 | #endif |
572 | |
573 | /* return value is bit-vector */ |
574 | static uint8_t get_frontend_source( |
575 | enum engine_id engine) |
576 | { |
577 | switch (engine) { |
578 | case ENGINE_ID_DIGA: |
579 | return DCE110_DIG_FE_SOURCE_SELECT_DIGA0x1; |
580 | case ENGINE_ID_DIGB: |
581 | return DCE110_DIG_FE_SOURCE_SELECT_DIGB0x2; |
582 | case ENGINE_ID_DIGC: |
583 | return DCE110_DIG_FE_SOURCE_SELECT_DIGC0x4; |
584 | case ENGINE_ID_DIGD: |
585 | return DCE110_DIG_FE_SOURCE_SELECT_DIGD0x08; |
586 | case ENGINE_ID_DIGE: |
587 | return DCE110_DIG_FE_SOURCE_SELECT_DIGE0x10; |
588 | case ENGINE_ID_DIGF: |
589 | return DCE110_DIG_FE_SOURCE_SELECT_DIGF0x20; |
590 | case ENGINE_ID_DIGG: |
591 | return DCE110_DIG_FE_SOURCE_SELECT_DIGG0x40; |
592 | default: |
593 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 593); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
594 | return DCE110_DIG_FE_SOURCE_SELECT_INVALID0x0; |
595 | } |
596 | } |
597 | |
598 | static void configure_encoder( |
599 | struct dce110_link_encoder *enc110, |
600 | const struct dc_link_settings *link_settings) |
601 | { |
602 | /* set number of lanes */ |
603 | |
604 | REG_SET(DP_CONFIG, 0,generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_CONFIG), 0, 1, 0x0, 0x3, link_settings->lane_count - LANE_COUNT_ONE) |
605 | DP_UDI_LANES, link_settings->lane_count - LANE_COUNT_ONE)generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_CONFIG), 0, 1, 0x0, 0x3, link_settings->lane_count - LANE_COUNT_ONE); |
606 | |
607 | /* setup scrambler */ |
608 | REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_ADVANCE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_SCRAM_CNTL), 1, 0x4, 0x10, 1); |
609 | } |
610 | |
611 | #if defined(CONFIG_DRM_AMD_DC_SI) |
612 | static void dce60_configure_encoder( |
613 | struct dce110_link_encoder *enc110, |
614 | const struct dc_link_settings *link_settings) |
615 | { |
616 | /* set number of lanes */ |
617 | |
618 | REG_SET(DP_CONFIG, 0,generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_CONFIG), 0, 1, 0x0, 0x3, link_settings->lane_count - LANE_COUNT_ONE) |
619 | DP_UDI_LANES, link_settings->lane_count - LANE_COUNT_ONE)generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_CONFIG), 0, 1, 0x0, 0x3, link_settings->lane_count - LANE_COUNT_ONE); |
620 | |
621 | /* DCE6 has no DP_DPHY_SCRAM_CNTL register, skip setup scrambler */ |
622 | } |
623 | #endif |
624 | |
625 | static void aux_initialize( |
626 | struct dce110_link_encoder *enc110) |
627 | { |
628 | struct dc_context *ctx = enc110->base.ctx; |
629 | enum hpd_source_id hpd_source = enc110->base.hpd_source; |
630 | uint32_t addr = AUX_REG(AUX_CONTROL)(enc110->aux_regs->AUX_CONTROL); |
631 | uint32_t value = dm_read_reg(ctx, addr)dm_read_reg_func(ctx, addr, __func__); |
632 | |
633 | set_reg_field_value(value, hpd_source, AUX_CONTROL, AUX_HPD_SEL)(value) = set_reg_field_value_ex( (value), (hpd_source), 0x700000 , 0x14); |
634 | set_reg_field_value(value, 0, AUX_CONTROL, AUX_LS_READ_EN)(value) = set_reg_field_value_ex( (value), (0), 0x100, 0x8); |
635 | dm_write_reg(ctx, addr, value)dm_write_reg_func(ctx, addr, value, __func__); |
636 | |
637 | addr = AUX_REG(AUX_DPHY_RX_CONTROL0)(enc110->aux_regs->AUX_DPHY_RX_CONTROL0); |
638 | value = dm_read_reg(ctx, addr)dm_read_reg_func(ctx, addr, __func__); |
639 | |
640 | /* 1/4 window (the maximum allowed) */ |
641 | set_reg_field_value(value, 1,(value) = set_reg_field_value_ex( (value), (1), 0x700, 0x8) |
642 | AUX_DPHY_RX_CONTROL0, AUX_RX_RECEIVE_WINDOW)(value) = set_reg_field_value_ex( (value), (1), 0x700, 0x8); |
643 | dm_write_reg(ctx, addr, value)dm_write_reg_func(ctx, addr, value, __func__); |
644 | |
645 | } |
646 | |
647 | void dce110_psr_program_dp_dphy_fast_training(struct link_encoder *enc, |
648 | bool_Bool exit_link_training_required) |
649 | { |
650 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
651 | |
652 | if (exit_link_training_required) |
653 | REG_UPDATE(DP_DPHY_FAST_TRAINING,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_FAST_TRAINING), 1, 0x0, 0x1, 1) |
654 | DPHY_RX_FAST_TRAINING_CAPABLE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_FAST_TRAINING), 1, 0x0, 0x1, 1); |
655 | else { |
656 | REG_UPDATE(DP_DPHY_FAST_TRAINING,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_FAST_TRAINING), 1, 0x0, 0x1, 0) |
657 | DPHY_RX_FAST_TRAINING_CAPABLE, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_FAST_TRAINING), 1, 0x0, 0x1, 0); |
658 | /*In DCE 11, we are able to pre-program a Force SR register |
659 | * to be able to trigger SR symbol after 5 idle patterns |
660 | * transmitted. Upon PSR Exit, DMCU can trigger |
661 | * DPHY_LOAD_BS_COUNT_START = 1. Upon writing 1 to |
662 | * DPHY_LOAD_BS_COUNT_START and the internal counter |
663 | * reaches DPHY_LOAD_BS_COUNT, the next BS symbol will be |
664 | * replaced by SR symbol once. |
665 | */ |
666 | |
667 | REG_UPDATE(DP_DPHY_BS_SR_SWAP_CNTL, DPHY_LOAD_BS_COUNT, 0x5)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_BS_SR_SWAP_CNTL), 1, 0x0, 0x3ff, 0x5); |
668 | } |
669 | } |
670 | |
671 | void dce110_psr_program_secondary_packet(struct link_encoder *enc, |
672 | unsigned int sdp_transmit_line_num_deadline) |
673 | { |
674 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
675 | |
676 | REG_UPDATE_2(DP_SEC_CNTL1,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_SEC_CNTL1), 2, 0x10, 0xffff0000, sdp_transmit_line_num_deadline , 0x4, 0x10, 1) |
677 | DP_SEC_GSP0_LINE_NUM, sdp_transmit_line_num_deadline,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_SEC_CNTL1), 2, 0x10, 0xffff0000, sdp_transmit_line_num_deadline , 0x4, 0x10, 1) |
678 | DP_SEC_GSP0_PRIORITY, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_SEC_CNTL1), 2, 0x10, 0xffff0000, sdp_transmit_line_num_deadline , 0x4, 0x10, 1); |
679 | } |
680 | |
681 | bool_Bool dce110_is_dig_enabled(struct link_encoder *enc) |
682 | { |
683 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
684 | uint32_t value; |
685 | |
686 | REG_GET(DIG_BE_EN_CNTL, DIG_ENABLE, &value)generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DIG_BE_EN_CNTL), 0x0, 0x1, &value); |
687 | return value; |
688 | } |
689 | |
690 | static void link_encoder_disable(struct dce110_link_encoder *enc110) |
691 | { |
692 | /* reset training pattern */ |
693 | REG_SET(DP_DPHY_TRAINING_PATTERN_SEL, 0,generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_TRAINING_PATTERN_SEL), 0, 1, 0x0, 0x3, 0) |
694 | DPHY_TRAINING_PATTERN_SEL, 0)generic_reg_set_ex(enc110->base.ctx, (enc110->link_regs ->DP_DPHY_TRAINING_PATTERN_SEL), 0, 1, 0x0, 0x3, 0); |
695 | |
696 | /* reset training complete */ |
697 | REG_UPDATE(DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_LINK_CNTL), 1, 0x4, 0x10, 0); |
698 | |
699 | /* reset panel mode */ |
700 | setup_panel_mode(enc110, DP_PANEL_MODE_DEFAULT); |
701 | } |
702 | |
703 | static void hpd_initialize( |
704 | struct dce110_link_encoder *enc110) |
705 | { |
706 | /* Associate HPD with DIG_BE */ |
707 | enum hpd_source_id hpd_source = enc110->base.hpd_source; |
708 | |
709 | REG_UPDATE(DIG_BE_CNTL, DIG_HPD_SELECT, hpd_source)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x1c, 0x70000000, hpd_source); |
710 | } |
711 | |
712 | bool_Bool dce110_link_encoder_validate_dvi_output( |
713 | const struct dce110_link_encoder *enc110, |
714 | enum amd_signal_type connector_signal, |
715 | enum amd_signal_type signal, |
716 | const struct dc_crtc_timing *crtc_timing) |
717 | { |
718 | uint32_t max_pixel_clock = TMDS_MAX_PIXEL_CLOCK165000; |
719 | |
720 | if (signal == SIGNAL_TYPE_DVI_DUAL_LINK) |
721 | max_pixel_clock *= 2; |
722 | |
723 | /* This handles the case of HDMI downgrade to DVI we don't want to |
724 | * we don't want to cap the pixel clock if the DDI is not DVI. |
725 | */ |
726 | if (connector_signal != SIGNAL_TYPE_DVI_DUAL_LINK && |
727 | connector_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) |
728 | max_pixel_clock = enc110->base.features.max_hdmi_pixel_clock; |
729 | |
730 | /* DVI only support RGB pixel encoding */ |
731 | if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB) |
732 | return false0; |
733 | |
734 | /*connect DVI via adpater's HDMI connector*/ |
735 | if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK || |
736 | connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) && |
737 | signal != SIGNAL_TYPE_HDMI_TYPE_A && |
738 | crtc_timing->pix_clk_100hz > (TMDS_MAX_PIXEL_CLOCK165000 * 10)) |
739 | return false0; |
740 | if (crtc_timing->pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK25000 * 10)) |
741 | return false0; |
742 | |
743 | if (crtc_timing->pix_clk_100hz > (max_pixel_clock * 10)) |
744 | return false0; |
745 | |
746 | /* DVI supports 6/8bpp single-link and 10/16bpp dual-link */ |
747 | switch (crtc_timing->display_color_depth) { |
748 | case COLOR_DEPTH_666: |
749 | case COLOR_DEPTH_888: |
750 | break; |
751 | case COLOR_DEPTH_101010: |
752 | case COLOR_DEPTH_161616: |
753 | if (signal != SIGNAL_TYPE_DVI_DUAL_LINK) |
754 | return false0; |
755 | break; |
756 | default: |
757 | return false0; |
758 | } |
759 | |
760 | return true1; |
761 | } |
762 | |
763 | static bool_Bool dce110_link_encoder_validate_hdmi_output( |
764 | const struct dce110_link_encoder *enc110, |
765 | const struct dc_crtc_timing *crtc_timing, |
766 | int adjusted_pix_clk_khz) |
767 | { |
768 | enum dc_color_depth max_deep_color = |
769 | enc110->base.features.max_hdmi_deep_color; |
770 | |
771 | if (max_deep_color < crtc_timing->display_color_depth) |
772 | return false0; |
773 | |
774 | if (crtc_timing->display_color_depth < COLOR_DEPTH_888) |
775 | return false0; |
776 | if (adjusted_pix_clk_khz < TMDS_MIN_PIXEL_CLOCK25000) |
777 | return false0; |
778 | |
779 | if ((adjusted_pix_clk_khz == 0) || |
780 | (adjusted_pix_clk_khz > enc110->base.features.max_hdmi_pixel_clock)) |
781 | return false0; |
782 | |
783 | /* DCE11 HW does not support 420 */ |
784 | if (!enc110->base.features.hdmi_ycbcr420_supported && |
785 | crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) |
786 | return false0; |
787 | |
788 | if ((!enc110->base.features.flags.bits.HDMI_6GB_EN || |
789 | enc110->base.ctx->dc->debug.hdmi20_disable) && |
790 | adjusted_pix_clk_khz >= 300000) |
791 | return false0; |
792 | if (enc110->base.ctx->dc->debug.hdmi20_disable && |
793 | crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) |
794 | return false0; |
795 | return true1; |
796 | } |
797 | |
798 | bool_Bool dce110_link_encoder_validate_dp_output( |
799 | const struct dce110_link_encoder *enc110, |
800 | const struct dc_crtc_timing *crtc_timing) |
801 | { |
802 | if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) |
803 | return false0; |
804 | |
805 | return true1; |
806 | } |
807 | |
808 | void dce110_link_encoder_construct( |
809 | struct dce110_link_encoder *enc110, |
810 | const struct encoder_init_data *init_data, |
811 | const struct encoder_feature_support *enc_features, |
812 | const struct dce110_link_enc_registers *link_regs, |
813 | const struct dce110_link_enc_aux_registers *aux_regs, |
814 | const struct dce110_link_enc_hpd_registers *hpd_regs) |
815 | { |
816 | struct bp_encoder_cap_info bp_cap_info = {0}; |
817 | const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; |
818 | enum bp_result result = BP_RESULT_OK; |
819 | |
820 | enc110->base.funcs = &dce110_lnk_enc_funcs; |
821 | enc110->base.ctx = init_data->ctx; |
822 | enc110->base.id = init_data->encoder; |
823 | |
824 | enc110->base.hpd_source = init_data->hpd_source; |
825 | enc110->base.connector = init_data->connector; |
826 | |
827 | enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; |
828 | |
829 | enc110->base.features = *enc_features; |
830 | |
831 | enc110->base.transmitter = init_data->transmitter; |
832 | |
833 | /* set the flag to indicate whether driver poll the I2C data pin |
834 | * while doing the DP sink detect |
835 | */ |
836 | |
837 | /* if (dal_adapter_service_is_feature_supported(as, |
838 | FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) |
839 | enc110->base.features.flags.bits. |
840 | DP_SINK_DETECT_POLL_DATA_PIN = true;*/ |
841 | |
842 | enc110->base.output_signals = |
843 | SIGNAL_TYPE_DVI_SINGLE_LINK | |
844 | SIGNAL_TYPE_DVI_DUAL_LINK | |
845 | SIGNAL_TYPE_LVDS | |
846 | SIGNAL_TYPE_DISPLAY_PORT | |
847 | SIGNAL_TYPE_DISPLAY_PORT_MST | |
848 | SIGNAL_TYPE_EDP | |
849 | SIGNAL_TYPE_HDMI_TYPE_A; |
850 | |
851 | /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. |
852 | * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. |
853 | * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer |
854 | * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. |
855 | * Prefer DIG assignment is decided by board design. |
856 | * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design |
857 | * and VBIOS will filter out 7 UNIPHY for DCE 8.0. |
858 | * By this, adding DIGG should not hurt DCE 8.0. |
859 | * This will let DCE 8.1 share DCE 8.0 as much as possible |
860 | */ |
861 | |
862 | enc110->link_regs = link_regs; |
863 | enc110->aux_regs = aux_regs; |
864 | enc110->hpd_regs = hpd_regs; |
865 | |
866 | switch (enc110->base.transmitter) { |
867 | case TRANSMITTER_UNIPHY_A: |
868 | enc110->base.preferred_engine = ENGINE_ID_DIGA; |
869 | break; |
870 | case TRANSMITTER_UNIPHY_B: |
871 | enc110->base.preferred_engine = ENGINE_ID_DIGB; |
872 | break; |
873 | case TRANSMITTER_UNIPHY_C: |
874 | enc110->base.preferred_engine = ENGINE_ID_DIGC; |
875 | break; |
876 | case TRANSMITTER_UNIPHY_D: |
877 | enc110->base.preferred_engine = ENGINE_ID_DIGD; |
878 | break; |
879 | case TRANSMITTER_UNIPHY_E: |
880 | enc110->base.preferred_engine = ENGINE_ID_DIGE; |
881 | break; |
882 | case TRANSMITTER_UNIPHY_F: |
883 | enc110->base.preferred_engine = ENGINE_ID_DIGF; |
884 | break; |
885 | case TRANSMITTER_UNIPHY_G: |
886 | enc110->base.preferred_engine = ENGINE_ID_DIGG; |
887 | break; |
888 | default: |
889 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 889); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
890 | enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; |
891 | } |
892 | |
893 | /* default to one to mirror Windows behavior */ |
894 | enc110->base.features.flags.bits.HDMI_6GB_EN = 1; |
895 | |
896 | result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, |
897 | enc110->base.id, &bp_cap_info); |
898 | |
899 | /* Override features with DCE-specific values */ |
900 | if (BP_RESULT_OK == result) { |
901 | enc110->base.features.flags.bits.IS_HBR2_CAPABLE = |
902 | bp_cap_info.DP_HBR2_EN; |
903 | enc110->base.features.flags.bits.IS_HBR3_CAPABLE = |
904 | bp_cap_info.DP_HBR3_EN; |
905 | enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; |
906 | } else { |
907 | DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",printk("\0014" "[" "drm" "] " "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n" , __func__, result) |
908 | __func__,printk("\0014" "[" "drm" "] " "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n" , __func__, result) |
909 | result)printk("\0014" "[" "drm" "] " "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n" , __func__, result); |
910 | } |
911 | if (enc110->base.ctx->dc->debug.hdmi20_disable) { |
912 | enc110->base.features.flags.bits.HDMI_6GB_EN = 0; |
913 | } |
914 | } |
915 | |
916 | bool_Bool dce110_link_encoder_validate_output_with_stream( |
917 | struct link_encoder *enc, |
918 | const struct dc_stream_state *stream) |
919 | { |
920 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
921 | bool_Bool is_valid; |
922 | |
923 | switch (stream->signal) { |
924 | case SIGNAL_TYPE_DVI_SINGLE_LINK: |
925 | case SIGNAL_TYPE_DVI_DUAL_LINK: |
926 | is_valid = dce110_link_encoder_validate_dvi_output( |
927 | enc110, |
928 | stream->link->connector_signal, |
929 | stream->signal, |
930 | &stream->timing); |
931 | break; |
932 | case SIGNAL_TYPE_HDMI_TYPE_A: |
933 | is_valid = dce110_link_encoder_validate_hdmi_output( |
934 | enc110, |
935 | &stream->timing, |
936 | stream->phy_pix_clk); |
937 | break; |
938 | case SIGNAL_TYPE_DISPLAY_PORT: |
939 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
940 | is_valid = dce110_link_encoder_validate_dp_output( |
941 | enc110, &stream->timing); |
942 | break; |
943 | case SIGNAL_TYPE_EDP: |
944 | case SIGNAL_TYPE_LVDS: |
945 | is_valid = |
946 | (stream->timing. |
947 | pixel_encoding == PIXEL_ENCODING_RGB) ? true1 : false0; |
948 | break; |
949 | case SIGNAL_TYPE_VIRTUAL: |
950 | is_valid = true1; |
951 | break; |
952 | default: |
953 | is_valid = false0; |
954 | break; |
955 | } |
956 | |
957 | return is_valid; |
958 | } |
959 | |
960 | void dce110_link_encoder_hw_init( |
961 | struct link_encoder *enc) |
962 | { |
963 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
964 | struct bp_transmitter_control cntl = { 0 }; |
965 | enum bp_result result; |
966 | |
967 | cntl.action = TRANSMITTER_CONTROL_INIT; |
968 | cntl.engine_id = ENGINE_ID_UNKNOWN; |
969 | cntl.transmitter = enc110->base.transmitter; |
970 | cntl.connector_obj_id = enc110->base.connector; |
971 | cntl.lanes_number = LANE_COUNT_FOUR; |
972 | cntl.coherent = false0; |
973 | cntl.hpd_sel = enc110->base.hpd_source; |
974 | |
975 | if (enc110->base.connector.id == CONNECTOR_ID_EDP) |
976 | cntl.signal = SIGNAL_TYPE_EDP; |
977 | |
978 | result = link_transmitter_control(enc110, &cntl); |
979 | |
980 | if (result != BP_RESULT_OK) { |
981 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
982 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
983 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 983); do {} while (0); } while (0); |
984 | return; |
985 | } |
986 | |
987 | if (enc110->base.connector.id == CONNECTOR_ID_LVDS) { |
988 | cntl.action = TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS; |
989 | |
990 | result = link_transmitter_control(enc110, &cntl); |
991 | |
992 | ASSERT(result == BP_RESULT_OK)do { if (({ static int __warned; int __ret = !!(!(result == BP_RESULT_OK )); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(result == BP_RESULT_OK)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 992); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
993 | |
994 | } |
995 | aux_initialize(enc110); |
996 | |
997 | /* reinitialize HPD. |
998 | * hpd_initialize() will pass DIG_FE id to HW context. |
999 | * All other routine within HW context will use fe_engine_offset |
1000 | * as DIG_FE id even caller pass DIG_FE id. |
1001 | * So this routine must be called first. */ |
1002 | hpd_initialize(enc110); |
1003 | } |
1004 | |
1005 | void dce110_link_encoder_destroy(struct link_encoder **enc) |
1006 | { |
1007 | kfree(TO_DCE110_LINK_ENC(*enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (*enc); (struct dce110_link_encoder *)( (char *) __mptr - __builtin_offsetof(struct dce110_link_encoder, base) );})); |
1008 | *enc = NULL((void *)0); |
1009 | } |
1010 | |
1011 | void dce110_link_encoder_setup( |
1012 | struct link_encoder *enc, |
1013 | enum amd_signal_type signal) |
1014 | { |
1015 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1016 | |
1017 | switch (signal) { |
1018 | case SIGNAL_TYPE_EDP: |
1019 | case SIGNAL_TYPE_DISPLAY_PORT: |
1020 | /* DP SST */ |
1021 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 0)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x10, 0x70000, 0); |
1022 | break; |
1023 | case SIGNAL_TYPE_LVDS: |
1024 | /* LVDS */ |
1025 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x10, 0x70000, 1); |
1026 | break; |
1027 | case SIGNAL_TYPE_DVI_SINGLE_LINK: |
1028 | case SIGNAL_TYPE_DVI_DUAL_LINK: |
1029 | /* TMDS-DVI */ |
1030 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 2)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x10, 0x70000, 2); |
1031 | break; |
1032 | case SIGNAL_TYPE_HDMI_TYPE_A: |
1033 | /* TMDS-HDMI */ |
1034 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 3)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x10, 0x70000, 3); |
1035 | break; |
1036 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
1037 | /* DP MST */ |
1038 | REG_UPDATE(DIG_BE_CNTL, DIG_MODE, 5)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x10, 0x70000, 5); |
1039 | break; |
1040 | default: |
1041 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 1041); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
1042 | /* invalid mode ! */ |
1043 | break; |
1044 | } |
1045 | |
1046 | } |
1047 | |
1048 | /* TODO: still need depth or just pass in adjusted pixel clock? */ |
1049 | void dce110_link_encoder_enable_tmds_output( |
1050 | struct link_encoder *enc, |
1051 | enum clock_source_id clock_source, |
1052 | enum dc_color_depth color_depth, |
1053 | enum amd_signal_type signal, |
1054 | uint32_t pixel_clock) |
1055 | { |
1056 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1057 | struct bp_transmitter_control cntl = { 0 }; |
1058 | enum bp_result result; |
1059 | |
1060 | /* Enable the PHY */ |
1061 | cntl.connector_obj_id = enc110->base.connector; |
1062 | cntl.action = TRANSMITTER_CONTROL_ENABLE; |
1063 | cntl.engine_id = enc->preferred_engine; |
1064 | cntl.transmitter = enc110->base.transmitter; |
1065 | cntl.pll_id = clock_source; |
1066 | cntl.signal = signal; |
1067 | if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK) |
1068 | cntl.lanes_number = 8; |
1069 | else |
1070 | cntl.lanes_number = 4; |
1071 | |
1072 | cntl.hpd_sel = enc110->base.hpd_source; |
1073 | |
1074 | cntl.pixel_clock = pixel_clock; |
1075 | cntl.color_depth = color_depth; |
1076 | |
1077 | result = link_transmitter_control(enc110, &cntl); |
1078 | |
1079 | if (result != BP_RESULT_OK) { |
1080 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1081 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1082 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1082); do {} while (0); } while (0); |
1083 | } |
1084 | } |
1085 | |
1086 | /* TODO: still need depth or just pass in adjusted pixel clock? */ |
1087 | void dce110_link_encoder_enable_lvds_output( |
1088 | struct link_encoder *enc, |
1089 | enum clock_source_id clock_source, |
1090 | uint32_t pixel_clock) |
1091 | { |
1092 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1093 | struct bp_transmitter_control cntl = { 0 }; |
1094 | enum bp_result result; |
1095 | |
1096 | /* Enable the PHY */ |
1097 | cntl.connector_obj_id = enc110->base.connector; |
1098 | cntl.action = TRANSMITTER_CONTROL_ENABLE; |
1099 | cntl.engine_id = enc->preferred_engine; |
1100 | cntl.transmitter = enc110->base.transmitter; |
1101 | cntl.pll_id = clock_source; |
1102 | cntl.signal = SIGNAL_TYPE_LVDS; |
1103 | cntl.lanes_number = 4; |
1104 | |
1105 | cntl.hpd_sel = enc110->base.hpd_source; |
1106 | |
1107 | cntl.pixel_clock = pixel_clock; |
1108 | |
1109 | result = link_transmitter_control(enc110, &cntl); |
1110 | |
1111 | if (result != BP_RESULT_OK) { |
1112 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1113 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1114 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1114); do {} while (0); } while (0); |
1115 | } |
1116 | } |
1117 | |
1118 | /* enables DP PHY output */ |
1119 | void dce110_link_encoder_enable_dp_output( |
1120 | struct link_encoder *enc, |
1121 | const struct dc_link_settings *link_settings, |
1122 | enum clock_source_id clock_source) |
1123 | { |
1124 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1125 | struct bp_transmitter_control cntl = { 0 }; |
1126 | enum bp_result result; |
1127 | |
1128 | /* Enable the PHY */ |
1129 | |
1130 | /* number_of_lanes is used for pixel clock adjust, |
1131 | * but it's not passed to asic_control. |
1132 | * We need to set number of lanes manually. |
1133 | */ |
1134 | configure_encoder(enc110, link_settings); |
1135 | cntl.connector_obj_id = enc110->base.connector; |
1136 | cntl.action = TRANSMITTER_CONTROL_ENABLE; |
1137 | cntl.engine_id = enc->preferred_engine; |
1138 | cntl.transmitter = enc110->base.transmitter; |
1139 | cntl.pll_id = clock_source; |
1140 | cntl.signal = SIGNAL_TYPE_DISPLAY_PORT; |
1141 | cntl.lanes_number = link_settings->lane_count; |
1142 | cntl.hpd_sel = enc110->base.hpd_source; |
1143 | cntl.pixel_clock = link_settings->link_rate |
1144 | * LINK_RATE_REF_FREQ_IN_KHZ; |
1145 | /* TODO: check if undefined works */ |
1146 | cntl.color_depth = COLOR_DEPTH_UNDEFINED; |
1147 | |
1148 | result = link_transmitter_control(enc110, &cntl); |
1149 | |
1150 | if (result != BP_RESULT_OK) { |
1151 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1152 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1153 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1153); do {} while (0); } while (0); |
1154 | } |
1155 | } |
1156 | |
1157 | /* enables DP PHY output in MST mode */ |
1158 | void dce110_link_encoder_enable_dp_mst_output( |
1159 | struct link_encoder *enc, |
1160 | const struct dc_link_settings *link_settings, |
1161 | enum clock_source_id clock_source) |
1162 | { |
1163 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1164 | struct bp_transmitter_control cntl = { 0 }; |
1165 | enum bp_result result; |
1166 | |
1167 | /* Enable the PHY */ |
1168 | |
1169 | /* number_of_lanes is used for pixel clock adjust, |
1170 | * but it's not passed to asic_control. |
1171 | * We need to set number of lanes manually. |
1172 | */ |
1173 | configure_encoder(enc110, link_settings); |
1174 | |
1175 | cntl.action = TRANSMITTER_CONTROL_ENABLE; |
1176 | cntl.engine_id = ENGINE_ID_UNKNOWN; |
1177 | cntl.transmitter = enc110->base.transmitter; |
1178 | cntl.pll_id = clock_source; |
1179 | cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST; |
1180 | cntl.lanes_number = link_settings->lane_count; |
1181 | cntl.hpd_sel = enc110->base.hpd_source; |
1182 | cntl.pixel_clock = link_settings->link_rate |
1183 | * LINK_RATE_REF_FREQ_IN_KHZ; |
1184 | /* TODO: check if undefined works */ |
1185 | cntl.color_depth = COLOR_DEPTH_UNDEFINED; |
1186 | |
1187 | result = link_transmitter_control(enc110, &cntl); |
1188 | |
1189 | if (result != BP_RESULT_OK) { |
1190 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1191 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1192 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1192); do {} while (0); } while (0); |
1193 | } |
1194 | } |
1195 | |
1196 | #if defined(CONFIG_DRM_AMD_DC_SI) |
1197 | /* enables DP PHY output */ |
1198 | static void dce60_link_encoder_enable_dp_output( |
1199 | struct link_encoder *enc, |
1200 | const struct dc_link_settings *link_settings, |
1201 | enum clock_source_id clock_source) |
1202 | { |
1203 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1204 | struct bp_transmitter_control cntl = { 0 }; |
1205 | enum bp_result result; |
1206 | |
1207 | /* Enable the PHY */ |
1208 | |
1209 | /* number_of_lanes is used for pixel clock adjust, |
1210 | * but it's not passed to asic_control. |
1211 | * We need to set number of lanes manually. |
1212 | */ |
1213 | dce60_configure_encoder(enc110, link_settings); |
1214 | cntl.connector_obj_id = enc110->base.connector; |
1215 | cntl.action = TRANSMITTER_CONTROL_ENABLE; |
1216 | cntl.engine_id = enc->preferred_engine; |
1217 | cntl.transmitter = enc110->base.transmitter; |
1218 | cntl.pll_id = clock_source; |
1219 | cntl.signal = SIGNAL_TYPE_DISPLAY_PORT; |
1220 | cntl.lanes_number = link_settings->lane_count; |
1221 | cntl.hpd_sel = enc110->base.hpd_source; |
1222 | cntl.pixel_clock = link_settings->link_rate |
1223 | * LINK_RATE_REF_FREQ_IN_KHZ; |
1224 | /* TODO: check if undefined works */ |
1225 | cntl.color_depth = COLOR_DEPTH_UNDEFINED; |
1226 | |
1227 | result = link_transmitter_control(enc110, &cntl); |
1228 | |
1229 | if (result != BP_RESULT_OK) { |
1230 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1231 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1232 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1232); do {} while (0); } while (0); |
1233 | } |
1234 | } |
1235 | |
1236 | /* enables DP PHY output in MST mode */ |
1237 | static void dce60_link_encoder_enable_dp_mst_output( |
1238 | struct link_encoder *enc, |
1239 | const struct dc_link_settings *link_settings, |
1240 | enum clock_source_id clock_source) |
1241 | { |
1242 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1243 | struct bp_transmitter_control cntl = { 0 }; |
1244 | enum bp_result result; |
1245 | |
1246 | /* Enable the PHY */ |
1247 | |
1248 | /* number_of_lanes is used for pixel clock adjust, |
1249 | * but it's not passed to asic_control. |
1250 | * We need to set number of lanes manually. |
1251 | */ |
1252 | dce60_configure_encoder(enc110, link_settings); |
1253 | |
1254 | cntl.action = TRANSMITTER_CONTROL_ENABLE; |
1255 | cntl.engine_id = ENGINE_ID_UNKNOWN; |
1256 | cntl.transmitter = enc110->base.transmitter; |
1257 | cntl.pll_id = clock_source; |
1258 | cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST; |
1259 | cntl.lanes_number = link_settings->lane_count; |
1260 | cntl.hpd_sel = enc110->base.hpd_source; |
1261 | cntl.pixel_clock = link_settings->link_rate |
1262 | * LINK_RATE_REF_FREQ_IN_KHZ; |
1263 | /* TODO: check if undefined works */ |
1264 | cntl.color_depth = COLOR_DEPTH_UNDEFINED; |
1265 | |
1266 | result = link_transmitter_control(enc110, &cntl); |
1267 | |
1268 | if (result != BP_RESULT_OK) { |
1269 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1270 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1271 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1271); do {} while (0); } while (0); |
1272 | } |
1273 | } |
1274 | #endif |
1275 | |
1276 | /* |
1277 | * @brief |
1278 | * Disable transmitter and its encoder |
1279 | */ |
1280 | void dce110_link_encoder_disable_output( |
1281 | struct link_encoder *enc, |
1282 | enum amd_signal_type signal) |
1283 | { |
1284 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1285 | struct bp_transmitter_control cntl = { 0 }; |
1286 | enum bp_result result; |
1287 | |
1288 | if (!dce110_is_dig_enabled(enc)) { |
1289 | /* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */ |
1290 | return; |
1291 | } |
1292 | /* Power-down RX and disable GPU PHY should be paired. |
1293 | * Disabling PHY without powering down RX may cause |
1294 | * symbol lock loss, on which we will get DP Sink interrupt. */ |
1295 | |
1296 | /* There is a case for the DP active dongles |
1297 | * where we want to disable the PHY but keep RX powered, |
1298 | * for those we need to ignore DP Sink interrupt |
1299 | * by checking lane count that has been set |
1300 | * on the last do_enable_output(). */ |
1301 | |
1302 | /* disable transmitter */ |
1303 | cntl.action = TRANSMITTER_CONTROL_DISABLE; |
1304 | cntl.transmitter = enc110->base.transmitter; |
1305 | cntl.hpd_sel = enc110->base.hpd_source; |
1306 | cntl.signal = signal; |
1307 | cntl.connector_obj_id = enc110->base.connector; |
1308 | |
1309 | result = link_transmitter_control(enc110, &cntl); |
1310 | |
1311 | if (result != BP_RESULT_OK) { |
1312 | DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ) |
1313 | __func__)__drm_err("%s: Failed to execute VBIOS command table!\n", __func__ ); |
1314 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1314); do {} while (0); } while (0); |
1315 | return; |
1316 | } |
1317 | |
1318 | /* disable encoder */ |
1319 | if (dc_is_dp_signal(signal)) |
1320 | link_encoder_disable(enc110); |
1321 | } |
1322 | |
1323 | void dce110_link_encoder_dp_set_lane_settings( |
1324 | struct link_encoder *enc, |
1325 | const struct dc_link_settings *link_settings, |
1326 | const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) |
1327 | { |
1328 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1329 | union dpcd_training_lane_set training_lane_set = { { 0 } }; |
1330 | int32_t lane = 0; |
1331 | struct bp_transmitter_control cntl = { 0 }; |
1332 | |
1333 | if (!link_settings) { |
1334 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1334); do {} while (0); } while (0); |
1335 | return; |
1336 | } |
1337 | |
1338 | cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS; |
1339 | cntl.transmitter = enc110->base.transmitter; |
1340 | cntl.connector_obj_id = enc110->base.connector; |
1341 | cntl.lanes_number = link_settings->lane_count; |
1342 | cntl.hpd_sel = enc110->base.hpd_source; |
1343 | cntl.pixel_clock = link_settings->link_rate * |
1344 | LINK_RATE_REF_FREQ_IN_KHZ; |
1345 | |
1346 | for (lane = 0; lane < link_settings->lane_count; lane++) { |
1347 | /* translate lane settings */ |
1348 | |
1349 | training_lane_set.bits.VOLTAGE_SWING_SET = |
1350 | lane_settings[lane].VOLTAGE_SWING; |
1351 | training_lane_set.bits.PRE_EMPHASIS_SET = |
1352 | lane_settings[lane].PRE_EMPHASIS; |
1353 | |
1354 | /* post cursor 2 setting only applies to HBR2 link rate */ |
1355 | if (link_settings->link_rate == LINK_RATE_HIGH2) { |
1356 | /* this is passed to VBIOS |
1357 | * to program post cursor 2 level */ |
1358 | |
1359 | training_lane_set.bits.POST_CURSOR2_SET = |
1360 | lane_settings[lane].POST_CURSOR2; |
1361 | } |
1362 | |
1363 | cntl.lane_select = lane; |
1364 | cntl.lane_settings = training_lane_set.raw; |
1365 | |
1366 | /* call VBIOS table to set voltage swing and pre-emphasis */ |
1367 | link_transmitter_control(enc110, &cntl); |
1368 | } |
1369 | } |
1370 | |
1371 | /* set DP PHY test and training patterns */ |
1372 | void dce110_link_encoder_dp_set_phy_pattern( |
1373 | struct link_encoder *enc, |
1374 | const struct encoder_set_dp_phy_pattern_param *param) |
1375 | { |
1376 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1377 | |
1378 | switch (param->dp_phy_pattern) { |
1379 | case DP_TEST_PATTERN_TRAINING_PATTERN1: |
1380 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 0); |
1381 | break; |
1382 | case DP_TEST_PATTERN_TRAINING_PATTERN2: |
1383 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 1); |
1384 | break; |
1385 | case DP_TEST_PATTERN_TRAINING_PATTERN3: |
1386 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 2); |
1387 | break; |
1388 | case DP_TEST_PATTERN_TRAINING_PATTERN4: |
1389 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 3); |
1390 | break; |
1391 | case DP_TEST_PATTERN_D102: |
1392 | set_dp_phy_pattern_d102(enc110); |
1393 | break; |
1394 | case DP_TEST_PATTERN_SYMBOL_ERROR: |
1395 | set_dp_phy_pattern_symbol_error(enc110); |
1396 | break; |
1397 | case DP_TEST_PATTERN_PRBS7: |
1398 | set_dp_phy_pattern_prbs7(enc110); |
1399 | break; |
1400 | case DP_TEST_PATTERN_80BIT_CUSTOM: |
1401 | set_dp_phy_pattern_80bit_custom( |
1402 | enc110, param->custom_pattern); |
1403 | break; |
1404 | case DP_TEST_PATTERN_CP2520_1: |
1405 | set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 1); |
1406 | break; |
1407 | case DP_TEST_PATTERN_CP2520_2: |
1408 | set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 2); |
1409 | break; |
1410 | case DP_TEST_PATTERN_CP2520_3: |
1411 | set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 3); |
1412 | break; |
1413 | case DP_TEST_PATTERN_VIDEO_MODE: { |
1414 | set_dp_phy_pattern_passthrough_mode( |
1415 | enc110, param->dp_panel_mode); |
1416 | break; |
1417 | } |
1418 | |
1419 | default: |
1420 | /* invalid phy pattern */ |
1421 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 1421); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
1422 | break; |
1423 | } |
1424 | } |
1425 | |
1426 | #if defined(CONFIG_DRM_AMD_DC_SI) |
1427 | /* set DP PHY test and training patterns */ |
1428 | static void dce60_link_encoder_dp_set_phy_pattern( |
1429 | struct link_encoder *enc, |
1430 | const struct encoder_set_dp_phy_pattern_param *param) |
1431 | { |
1432 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1433 | |
1434 | switch (param->dp_phy_pattern) { |
1435 | case DP_TEST_PATTERN_TRAINING_PATTERN1: |
1436 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 0); |
1437 | break; |
1438 | case DP_TEST_PATTERN_TRAINING_PATTERN2: |
1439 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 1); |
1440 | break; |
1441 | case DP_TEST_PATTERN_TRAINING_PATTERN3: |
1442 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 2); |
1443 | break; |
1444 | case DP_TEST_PATTERN_TRAINING_PATTERN4: |
1445 | dce110_link_encoder_set_dp_phy_pattern_training_pattern(enc, 3); |
1446 | break; |
1447 | case DP_TEST_PATTERN_D102: |
1448 | set_dp_phy_pattern_d102(enc110); |
1449 | break; |
1450 | case DP_TEST_PATTERN_SYMBOL_ERROR: |
1451 | set_dp_phy_pattern_symbol_error(enc110); |
1452 | break; |
1453 | case DP_TEST_PATTERN_PRBS7: |
1454 | set_dp_phy_pattern_prbs7(enc110); |
1455 | break; |
1456 | case DP_TEST_PATTERN_80BIT_CUSTOM: |
1457 | set_dp_phy_pattern_80bit_custom( |
1458 | enc110, param->custom_pattern); |
1459 | break; |
1460 | case DP_TEST_PATTERN_CP2520_1: |
1461 | dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 1); |
1462 | break; |
1463 | case DP_TEST_PATTERN_CP2520_2: |
1464 | dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 2); |
1465 | break; |
1466 | case DP_TEST_PATTERN_CP2520_3: |
1467 | dce60_set_dp_phy_pattern_hbr2_compliance_cp2520_2(enc110, 3); |
1468 | break; |
1469 | case DP_TEST_PATTERN_VIDEO_MODE: { |
1470 | dce60_set_dp_phy_pattern_passthrough_mode( |
1471 | enc110, param->dp_panel_mode); |
1472 | break; |
1473 | } |
1474 | |
1475 | default: |
1476 | /* invalid phy pattern */ |
1477 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 1477); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
1478 | break; |
1479 | } |
1480 | } |
1481 | #endif |
1482 | |
1483 | static void fill_stream_allocation_row_info( |
1484 | const struct link_mst_stream_allocation *stream_allocation, |
1485 | uint32_t *src, |
1486 | uint32_t *slots) |
1487 | { |
1488 | const struct stream_encoder *stream_enc = stream_allocation->stream_enc; |
1489 | |
1490 | if (stream_enc) { |
1491 | *src = stream_enc->id; |
1492 | *slots = stream_allocation->slot_count; |
1493 | } else { |
1494 | *src = 0; |
1495 | *slots = 0; |
1496 | } |
1497 | } |
1498 | |
1499 | /* programs DP MST VC payload allocation */ |
1500 | void dce110_link_encoder_update_mst_stream_allocation_table( |
1501 | struct link_encoder *enc, |
1502 | const struct link_mst_stream_allocation_table *table) |
1503 | { |
1504 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1505 | uint32_t value1 = 0; |
1506 | uint32_t value2 = 0; |
1507 | uint32_t slots = 0; |
1508 | uint32_t src = 0; |
1509 | uint32_t retries = 0; |
1510 | |
1511 | /* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/ |
1512 | |
1513 | /* --- Set MSE Stream Attribute - |
1514 | * Setup VC Payload Table on Tx Side, |
1515 | * Issue allocation change trigger |
1516 | * to commit payload on both tx and rx side */ |
1517 | |
1518 | /* we should clean-up table each time */ |
1519 | |
1520 | if (table->stream_count >= 1) { |
1521 | fill_stream_allocation_row_info( |
1522 | &table->stream_allocations[0], |
1523 | &src, |
1524 | &slots); |
1525 | } else { |
1526 | src = 0; |
1527 | slots = 0; |
1528 | } |
1529 | |
1530 | REG_UPDATE_2(DP_MSE_SAT0,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT0), 2, 0x0, 0x7, src, 0x8, 0x3f00, slots) |
1531 | DP_MSE_SAT_SRC0, src,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT0), 2, 0x0, 0x7, src, 0x8, 0x3f00, slots) |
1532 | DP_MSE_SAT_SLOT_COUNT0, slots)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT0), 2, 0x0, 0x7, src, 0x8, 0x3f00, slots); |
1533 | |
1534 | if (table->stream_count >= 2) { |
1535 | fill_stream_allocation_row_info( |
1536 | &table->stream_allocations[1], |
1537 | &src, |
1538 | &slots); |
1539 | } else { |
1540 | src = 0; |
1541 | slots = 0; |
1542 | } |
1543 | |
1544 | REG_UPDATE_2(DP_MSE_SAT0,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT0), 2, 0x10, 0x70000, src, 0x18, 0x3f000000, slots ) |
1545 | DP_MSE_SAT_SRC1, src,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT0), 2, 0x10, 0x70000, src, 0x18, 0x3f000000, slots ) |
1546 | DP_MSE_SAT_SLOT_COUNT1, slots)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT0), 2, 0x10, 0x70000, src, 0x18, 0x3f000000, slots ); |
1547 | |
1548 | if (table->stream_count >= 3) { |
1549 | fill_stream_allocation_row_info( |
1550 | &table->stream_allocations[2], |
1551 | &src, |
1552 | &slots); |
1553 | } else { |
1554 | src = 0; |
1555 | slots = 0; |
1556 | } |
1557 | |
1558 | REG_UPDATE_2(DP_MSE_SAT1,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT1), 2, 0x0, 0x7, src, 0x8, 0x3f00, slots) |
1559 | DP_MSE_SAT_SRC2, src,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT1), 2, 0x0, 0x7, src, 0x8, 0x3f00, slots) |
1560 | DP_MSE_SAT_SLOT_COUNT2, slots)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT1), 2, 0x0, 0x7, src, 0x8, 0x3f00, slots); |
1561 | |
1562 | if (table->stream_count >= 4) { |
1563 | fill_stream_allocation_row_info( |
1564 | &table->stream_allocations[3], |
1565 | &src, |
1566 | &slots); |
1567 | } else { |
1568 | src = 0; |
1569 | slots = 0; |
1570 | } |
1571 | |
1572 | REG_UPDATE_2(DP_MSE_SAT1,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT1), 2, 0x10, 0x70000, src, 0x18, 0x3f000000, slots ) |
1573 | DP_MSE_SAT_SRC3, src,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT1), 2, 0x10, 0x70000, src, 0x18, 0x3f000000, slots ) |
1574 | DP_MSE_SAT_SLOT_COUNT3, slots)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT1), 2, 0x10, 0x70000, src, 0x18, 0x3f000000, slots ); |
1575 | |
1576 | /* --- wait for transaction finish */ |
1577 | |
1578 | /* send allocation change trigger (ACT) ? |
1579 | * this step first sends the ACT, |
1580 | * then double buffers the SAT into the hardware |
1581 | * making the new allocation active on the DP MST mode link */ |
1582 | |
1583 | |
1584 | /* DP_MSE_SAT_UPDATE: |
1585 | * 0 - No Action |
1586 | * 1 - Update SAT with trigger |
1587 | * 2 - Update SAT without trigger */ |
1588 | |
1589 | REG_UPDATE(DP_MSE_SAT_UPDATE,generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT_UPDATE), 1, 0x0, 0x3, 1) |
1590 | DP_MSE_SAT_UPDATE, 1)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DP_MSE_SAT_UPDATE), 1, 0x0, 0x3, 1); |
1591 | |
1592 | /* wait for update to complete |
1593 | * (i.e. DP_MSE_SAT_UPDATE field is reset to 0) |
1594 | * then wait for the transmission |
1595 | * of at least 16 MTP headers on immediate local link. |
1596 | * i.e. DP_MSE_16_MTP_KEEPOUT field (read only) is reset to 0 |
1597 | * a value of 1 indicates that DP MST mode |
1598 | * is in the 16 MTP keepout region after a VC has been added. |
1599 | * MST stream bandwidth (VC rate) can be configured |
1600 | * after this bit is cleared */ |
1601 | |
1602 | do { |
1603 | udelay(10); |
1604 | |
1605 | REG_READ(DP_MSE_SAT_UPDATE)dm_read_reg_func(enc110->base.ctx, (enc110->link_regs-> DP_MSE_SAT_UPDATE), __func__); |
1606 | |
1607 | REG_GET(DP_MSE_SAT_UPDATE,generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DP_MSE_SAT_UPDATE), 0x0, 0x3, &value1) |
1608 | DP_MSE_SAT_UPDATE, &value1)generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DP_MSE_SAT_UPDATE), 0x0, 0x3, &value1); |
1609 | |
1610 | REG_GET(DP_MSE_SAT_UPDATE,generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DP_MSE_SAT_UPDATE), 0x8, 0x100, &value2) |
1611 | DP_MSE_16_MTP_KEEPOUT, &value2)generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DP_MSE_SAT_UPDATE), 0x8, 0x100, &value2); |
1612 | |
1613 | /* bit field DP_MSE_SAT_UPDATE is set to 1 already */ |
1614 | if (!value1 && !value2) |
1615 | break; |
1616 | ++retries; |
1617 | } while (retries < DP_MST_UPDATE_MAX_RETRY); |
1618 | } |
1619 | |
1620 | void dce110_link_encoder_connect_dig_be_to_fe( |
1621 | struct link_encoder *enc, |
1622 | enum engine_id engine, |
1623 | bool_Bool connect) |
1624 | { |
1625 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1626 | uint32_t field; |
1627 | |
1628 | if (engine != ENGINE_ID_UNKNOWN) { |
1629 | |
1630 | REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &field)generic_reg_get(enc110->base.ctx, (enc110->link_regs-> DIG_BE_CNTL), 0x8, 0x7f00, &field); |
1631 | |
1632 | if (connect) |
1633 | field |= get_frontend_source(engine); |
1634 | else |
1635 | field &= ~get_frontend_source(engine); |
1636 | |
1637 | REG_UPDATE(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, field)generic_reg_update_ex(enc110->base.ctx, (enc110->link_regs ->DIG_BE_CNTL), 1, 0x8, 0x7f00, field); |
1638 | } |
1639 | } |
1640 | |
1641 | void dce110_link_encoder_enable_hpd(struct link_encoder *enc) |
1642 | { |
1643 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1644 | struct dc_context *ctx = enc110->base.ctx; |
1645 | uint32_t addr = HPD_REG(DC_HPD_CONTROL)(enc110->hpd_regs->DC_HPD_CONTROL); |
1646 | uint32_t hpd_enable = 0; |
1647 | uint32_t value = dm_read_reg(ctx, addr)dm_read_reg_func(ctx, addr, __func__); |
1648 | |
1649 | get_reg_field_value(hpd_enable, DC_HPD_CONTROL, DC_HPD_EN)get_reg_field_value_ex( (hpd_enable), 0x10000000, 0x1c); |
1650 | |
1651 | if (hpd_enable == 0) |
1652 | set_reg_field_value(value, 1, DC_HPD_CONTROL, DC_HPD_EN)(value) = set_reg_field_value_ex( (value), (1), 0x10000000, 0x1c ); |
1653 | } |
1654 | |
1655 | void dce110_link_encoder_disable_hpd(struct link_encoder *enc) |
1656 | { |
1657 | struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc)({ const __typeof( ((struct dce110_link_encoder *)0)->base ) *__mptr = (enc); (struct dce110_link_encoder *)( (char *)__mptr - __builtin_offsetof(struct dce110_link_encoder, base) );}); |
1658 | struct dc_context *ctx = enc110->base.ctx; |
1659 | uint32_t addr = HPD_REG(DC_HPD_CONTROL)(enc110->hpd_regs->DC_HPD_CONTROL); |
1660 | uint32_t value = dm_read_reg(ctx, addr)dm_read_reg_func(ctx, addr, __func__); |
1661 | |
1662 | set_reg_field_value(value, 0, DC_HPD_CONTROL, DC_HPD_EN)(value) = set_reg_field_value_ex( (value), (0), 0x10000000, 0x1c ); |
1663 | } |
1664 | |
1665 | void dce110_link_encoder_get_max_link_cap(struct link_encoder *enc, |
1666 | struct dc_link_settings *link_settings) |
1667 | { |
1668 | /* Set Default link settings */ |
1669 | struct dc_link_settings max_link_cap = {LANE_COUNT_FOUR, LINK_RATE_HIGH, |
1670 | LINK_SPREAD_05_DOWNSPREAD_30KHZ, false0, 0}; |
1671 | |
1672 | /* Higher link settings based on feature supported */ |
1673 | if (enc->features.flags.bits.IS_HBR2_CAPABLE) |
1674 | max_link_cap.link_rate = LINK_RATE_HIGH2; |
1675 | |
1676 | if (enc->features.flags.bits.IS_HBR3_CAPABLE) |
1677 | max_link_cap.link_rate = LINK_RATE_HIGH3; |
1678 | |
1679 | *link_settings = max_link_cap; |
1680 | } |
1681 | |
1682 | #if defined(CONFIG_DRM_AMD_DC_SI) |
1683 | static const struct link_encoder_funcs dce60_lnk_enc_funcs = { |
1684 | .validate_output_with_stream = |
1685 | dce110_link_encoder_validate_output_with_stream, |
1686 | .hw_init = dce110_link_encoder_hw_init, |
1687 | .setup = dce110_link_encoder_setup, |
1688 | .enable_tmds_output = dce110_link_encoder_enable_tmds_output, |
1689 | .enable_dp_output = dce60_link_encoder_enable_dp_output, |
1690 | .enable_dp_mst_output = dce60_link_encoder_enable_dp_mst_output, |
1691 | .enable_lvds_output = dce110_link_encoder_enable_lvds_output, |
1692 | .disable_output = dce110_link_encoder_disable_output, |
1693 | .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, |
1694 | .dp_set_phy_pattern = dce60_link_encoder_dp_set_phy_pattern, |
1695 | .update_mst_stream_allocation_table = |
1696 | dce110_link_encoder_update_mst_stream_allocation_table, |
1697 | .psr_program_dp_dphy_fast_training = |
1698 | dce110_psr_program_dp_dphy_fast_training, |
1699 | .psr_program_secondary_packet = dce110_psr_program_secondary_packet, |
1700 | .connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe, |
1701 | .enable_hpd = dce110_link_encoder_enable_hpd, |
1702 | .disable_hpd = dce110_link_encoder_disable_hpd, |
1703 | .is_dig_enabled = dce110_is_dig_enabled, |
1704 | .destroy = dce110_link_encoder_destroy, |
1705 | .get_max_link_cap = dce110_link_encoder_get_max_link_cap, |
1706 | .get_dig_frontend = dce110_get_dig_frontend |
1707 | }; |
1708 | |
1709 | void dce60_link_encoder_construct( |
1710 | struct dce110_link_encoder *enc110, |
1711 | const struct encoder_init_data *init_data, |
1712 | const struct encoder_feature_support *enc_features, |
1713 | const struct dce110_link_enc_registers *link_regs, |
1714 | const struct dce110_link_enc_aux_registers *aux_regs, |
1715 | const struct dce110_link_enc_hpd_registers *hpd_regs) |
1716 | { |
1717 | struct bp_encoder_cap_info bp_cap_info = {0}; |
1718 | const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; |
1719 | enum bp_result result = BP_RESULT_OK; |
1720 | |
1721 | enc110->base.funcs = &dce60_lnk_enc_funcs; |
1722 | enc110->base.ctx = init_data->ctx; |
1723 | enc110->base.id = init_data->encoder; |
1724 | |
1725 | enc110->base.hpd_source = init_data->hpd_source; |
1726 | enc110->base.connector = init_data->connector; |
1727 | |
1728 | enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; |
1729 | |
1730 | enc110->base.features = *enc_features; |
1731 | |
1732 | enc110->base.transmitter = init_data->transmitter; |
1733 | |
1734 | /* set the flag to indicate whether driver poll the I2C data pin |
1735 | * while doing the DP sink detect |
1736 | */ |
1737 | |
1738 | /* if (dal_adapter_service_is_feature_supported(as, |
1739 | FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) |
1740 | enc110->base.features.flags.bits. |
1741 | DP_SINK_DETECT_POLL_DATA_PIN = true;*/ |
1742 | |
1743 | enc110->base.output_signals = |
1744 | SIGNAL_TYPE_DVI_SINGLE_LINK | |
1745 | SIGNAL_TYPE_DVI_DUAL_LINK | |
1746 | SIGNAL_TYPE_LVDS | |
1747 | SIGNAL_TYPE_DISPLAY_PORT | |
1748 | SIGNAL_TYPE_DISPLAY_PORT_MST | |
1749 | SIGNAL_TYPE_EDP | |
1750 | SIGNAL_TYPE_HDMI_TYPE_A; |
1751 | |
1752 | /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. |
1753 | * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. |
1754 | * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer |
1755 | * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. |
1756 | * Prefer DIG assignment is decided by board design. |
1757 | * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design |
1758 | * and VBIOS will filter out 7 UNIPHY for DCE 8.0. |
1759 | * By this, adding DIGG should not hurt DCE 8.0. |
1760 | * This will let DCE 8.1 share DCE 8.0 as much as possible |
1761 | */ |
1762 | |
1763 | enc110->link_regs = link_regs; |
1764 | enc110->aux_regs = aux_regs; |
1765 | enc110->hpd_regs = hpd_regs; |
1766 | |
1767 | switch (enc110->base.transmitter) { |
1768 | case TRANSMITTER_UNIPHY_A: |
1769 | enc110->base.preferred_engine = ENGINE_ID_DIGA; |
1770 | break; |
1771 | case TRANSMITTER_UNIPHY_B: |
1772 | enc110->base.preferred_engine = ENGINE_ID_DIGB; |
1773 | break; |
1774 | case TRANSMITTER_UNIPHY_C: |
1775 | enc110->base.preferred_engine = ENGINE_ID_DIGC; |
1776 | break; |
1777 | case TRANSMITTER_UNIPHY_D: |
1778 | enc110->base.preferred_engine = ENGINE_ID_DIGD; |
1779 | break; |
1780 | case TRANSMITTER_UNIPHY_E: |
1781 | enc110->base.preferred_engine = ENGINE_ID_DIGE; |
1782 | break; |
1783 | case TRANSMITTER_UNIPHY_F: |
1784 | enc110->base.preferred_engine = ENGINE_ID_DIGF; |
1785 | break; |
1786 | case TRANSMITTER_UNIPHY_G: |
1787 | enc110->base.preferred_engine = ENGINE_ID_DIGG; |
1788 | break; |
1789 | default: |
1790 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dce/dce_link_encoder.c" , 1790); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
1791 | enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; |
1792 | } |
1793 | |
1794 | /* default to one to mirror Windows behavior */ |
1795 | enc110->base.features.flags.bits.HDMI_6GB_EN = 1; |
1796 | |
1797 | result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios, |
1798 | enc110->base.id, &bp_cap_info); |
1799 | |
1800 | /* Override features with DCE-specific values */ |
1801 | if (BP_RESULT_OK == result) { |
1802 | enc110->base.features.flags.bits.IS_HBR2_CAPABLE = |
1803 | bp_cap_info.DP_HBR2_EN; |
1804 | enc110->base.features.flags.bits.IS_HBR3_CAPABLE = |
1805 | bp_cap_info.DP_HBR3_EN; |
1806 | enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; |
1807 | } else { |
1808 | DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",printk("\0014" "[" "drm" "] " "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n" , __func__, result) |
1809 | __func__,printk("\0014" "[" "drm" "] " "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n" , __func__, result) |
1810 | result)printk("\0014" "[" "drm" "] " "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n" , __func__, result); |
1811 | } |
1812 | if (enc110->base.ctx->dc->debug.hdmi20_disable) { |
1813 | enc110->base.features.flags.bits.HDMI_6GB_EN = 0; |
1814 | } |
1815 | } |
1816 | #endif |