1 | /* |
2 | * Copyright 2022 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 | /* FILE POLICY AND INTENDED USAGE: |
27 | * This file manages link detection states and receiver states by using various |
28 | * link protocols. It also provides helper functions to interpret certain |
29 | * capabilities or status based on the states it manages or retrieve them |
30 | * directly from connected receivers. |
31 | */ |
32 | |
33 | #include "link_dpms.h" |
34 | #include "link_detection.h" |
35 | #include "link_hwss.h" |
36 | #include "protocols/link_edp_panel_control.h" |
37 | #include "protocols/link_ddc.h" |
38 | #include "protocols/link_hpd.h" |
39 | #include "protocols/link_dpcd.h" |
40 | #include "protocols/link_dp_capability.h" |
41 | #include "protocols/link_dp_dpia.h" |
42 | #include "protocols/link_dp_phy.h" |
43 | #include "protocols/link_dp_training.h" |
44 | #include "protocols/link_dp_dpia_bw.h" |
45 | #include "accessories/link_dp_trace.h" |
46 | |
47 | #include "link_enc_cfg.h" |
48 | #include "dm_helpers.h" |
49 | #include "clk_mgr.h" |
50 | |
51 | #define DC_LOGGER \ |
52 | link->ctx->logger |
53 | #define DC_LOGGER_INIT(logger) |
54 | |
55 | #define LINK_INFO(...) \ |
56 | DC_LOG_HW_HOTPLUG( \ |
57 | __VA_ARGS__) |
58 | /* |
59 | * Some receivers fail to train on first try and are good |
60 | * on subsequent tries. 2 retries should be plenty. If we |
61 | * don't have a successful training then we don't expect to |
62 | * ever get one. |
63 | */ |
64 | #define LINK_TRAINING_MAX_VERIFY_RETRY 2 |
65 | |
66 | static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u" ; |
67 | |
68 | static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR" ; |
69 | |
70 | static enum ddc_transaction_type get_ddc_transaction_type(enum signal_type sink_signal) |
71 | { |
72 | enum ddc_transaction_type transaction_type = DDC_TRANSACTION_TYPE_NONE; |
73 | |
74 | switch (sink_signal) { |
75 | case SIGNAL_TYPE_DVI_SINGLE_LINK: |
76 | case SIGNAL_TYPE_DVI_DUAL_LINK: |
77 | case SIGNAL_TYPE_HDMI_TYPE_A: |
78 | case SIGNAL_TYPE_LVDS: |
79 | case SIGNAL_TYPE_RGB: |
80 | transaction_type = DDC_TRANSACTION_TYPE_I2C; |
81 | break; |
82 | |
83 | case SIGNAL_TYPE_DISPLAY_PORT: |
84 | case SIGNAL_TYPE_EDP: |
85 | transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX; |
86 | break; |
87 | |
88 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
89 | /* MST does not use I2COverAux, but there is the |
90 | * SPECIAL use case for "immediate dwnstrm device |
91 | * access" (EPR#370830). |
92 | */ |
93 | transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX; |
94 | break; |
95 | |
96 | default: |
97 | break; |
98 | } |
99 | |
100 | return transaction_type; |
101 | } |
102 | |
103 | static enum signal_type get_basic_signal_type(struct graphics_object_id encoder, |
104 | struct graphics_object_id downstream) |
105 | { |
106 | if (downstream.type == OBJECT_TYPE_CONNECTOR) { |
107 | switch (downstream.id) { |
108 | case CONNECTOR_ID_SINGLE_LINK_DVII: |
109 | switch (encoder.id) { |
110 | case ENCODER_ID_INTERNAL_DAC1: |
111 | case ENCODER_ID_INTERNAL_KLDSCP_DAC1: |
112 | case ENCODER_ID_INTERNAL_DAC2: |
113 | case ENCODER_ID_INTERNAL_KLDSCP_DAC2: |
114 | return SIGNAL_TYPE_RGB; |
115 | default: |
116 | return SIGNAL_TYPE_DVI_SINGLE_LINK; |
117 | } |
118 | break; |
119 | case CONNECTOR_ID_DUAL_LINK_DVII: |
120 | { |
121 | switch (encoder.id) { |
122 | case ENCODER_ID_INTERNAL_DAC1: |
123 | case ENCODER_ID_INTERNAL_KLDSCP_DAC1: |
124 | case ENCODER_ID_INTERNAL_DAC2: |
125 | case ENCODER_ID_INTERNAL_KLDSCP_DAC2: |
126 | return SIGNAL_TYPE_RGB; |
127 | default: |
128 | return SIGNAL_TYPE_DVI_DUAL_LINK; |
129 | } |
130 | } |
131 | break; |
132 | case CONNECTOR_ID_SINGLE_LINK_DVID: |
133 | return SIGNAL_TYPE_DVI_SINGLE_LINK; |
134 | case CONNECTOR_ID_DUAL_LINK_DVID: |
135 | return SIGNAL_TYPE_DVI_DUAL_LINK; |
136 | case CONNECTOR_ID_VGA: |
137 | return SIGNAL_TYPE_RGB; |
138 | case CONNECTOR_ID_HDMI_TYPE_A: |
139 | return SIGNAL_TYPE_HDMI_TYPE_A; |
140 | case CONNECTOR_ID_LVDS: |
141 | return SIGNAL_TYPE_LVDS; |
142 | case CONNECTOR_ID_DISPLAY_PORT: |
143 | case CONNECTOR_ID_USBC: |
144 | return SIGNAL_TYPE_DISPLAY_PORT; |
145 | case CONNECTOR_ID_EDP: |
146 | return SIGNAL_TYPE_EDP; |
147 | default: |
148 | return SIGNAL_TYPE_NONE; |
149 | } |
150 | } else if (downstream.type == OBJECT_TYPE_ENCODER) { |
151 | switch (downstream.id) { |
152 | case ENCODER_ID_EXTERNAL_NUTMEG: |
153 | case ENCODER_ID_EXTERNAL_TRAVIS: |
154 | return SIGNAL_TYPE_DISPLAY_PORT; |
155 | default: |
156 | return SIGNAL_TYPE_NONE; |
157 | } |
158 | } |
159 | |
160 | return SIGNAL_TYPE_NONE; |
161 | } |
162 | |
163 | /* |
164 | * @brief |
165 | * Detect output sink type |
166 | */ |
167 | static enum signal_type link_detect_sink_signal_type(struct dc_link *link, |
168 | enum dc_detect_reason reason) |
169 | { |
170 | enum signal_type result; |
171 | struct graphics_object_id enc_id; |
172 | |
173 | if (link->is_dig_mapping_flexible) |
174 | enc_id = (struct graphics_object_id){.id = ENCODER_ID_UNKNOWN}; |
175 | else |
176 | enc_id = link->link_enc->id; |
177 | result = get_basic_signal_type(encoder: enc_id, downstream: link->link_id); |
178 | |
179 | /* Use basic signal type for link without physical connector. */ |
180 | if (link->ep_type != DISPLAY_ENDPOINT_PHY) |
181 | return result; |
182 | |
183 | /* Internal digital encoder will detect only dongles |
184 | * that require digital signal |
185 | */ |
186 | |
187 | /* Detection mechanism is different |
188 | * for different native connectors. |
189 | * LVDS connector supports only LVDS signal; |
190 | * PCIE is a bus slot, the actual connector needs to be detected first; |
191 | * eDP connector supports only eDP signal; |
192 | * HDMI should check straps for audio |
193 | */ |
194 | |
195 | /* PCIE detects the actual connector on add-on board */ |
196 | if (link->link_id.id == CONNECTOR_ID_PCIE) { |
197 | /* ZAZTODO implement PCIE add-on card detection */ |
198 | } |
199 | |
200 | switch (link->link_id.id) { |
201 | case CONNECTOR_ID_HDMI_TYPE_A: { |
202 | /* check audio support: |
203 | * if native HDMI is not supported, switch to DVI |
204 | */ |
205 | struct audio_support *aud_support = |
206 | &link->dc->res_pool->audio_support; |
207 | |
208 | if (!aud_support->hdmi_audio_native) |
209 | if (link->link_id.id == CONNECTOR_ID_HDMI_TYPE_A) |
210 | result = SIGNAL_TYPE_DVI_SINGLE_LINK; |
211 | } |
212 | break; |
213 | case CONNECTOR_ID_DISPLAY_PORT: |
214 | case CONNECTOR_ID_USBC: { |
215 | /* DP HPD short pulse. Passive DP dongle will not |
216 | * have short pulse |
217 | */ |
218 | if (reason != DETECT_REASON_HPDRX) { |
219 | /* Check whether DP signal detected: if not - |
220 | * we assume signal is DVI; it could be corrected |
221 | * to HDMI after dongle detection |
222 | */ |
223 | if (!dm_helpers_is_dp_sink_present(link)) |
224 | result = SIGNAL_TYPE_DVI_SINGLE_LINK; |
225 | } |
226 | } |
227 | break; |
228 | default: |
229 | break; |
230 | } |
231 | |
232 | return result; |
233 | } |
234 | |
235 | static enum signal_type decide_signal_from_strap_and_dongle_type(enum display_dongle_type dongle_type, |
236 | struct audio_support *audio_support) |
237 | { |
238 | enum signal_type signal = SIGNAL_TYPE_NONE; |
239 | |
240 | switch (dongle_type) { |
241 | case DISPLAY_DONGLE_DP_HDMI_DONGLE: |
242 | if (audio_support->hdmi_audio_on_dongle) |
243 | signal = SIGNAL_TYPE_HDMI_TYPE_A; |
244 | else |
245 | signal = SIGNAL_TYPE_DVI_SINGLE_LINK; |
246 | break; |
247 | case DISPLAY_DONGLE_DP_DVI_DONGLE: |
248 | signal = SIGNAL_TYPE_DVI_SINGLE_LINK; |
249 | break; |
250 | case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE: |
251 | if (audio_support->hdmi_audio_native) |
252 | signal = SIGNAL_TYPE_HDMI_TYPE_A; |
253 | else |
254 | signal = SIGNAL_TYPE_DVI_SINGLE_LINK; |
255 | break; |
256 | default: |
257 | signal = SIGNAL_TYPE_NONE; |
258 | break; |
259 | } |
260 | |
261 | return signal; |
262 | } |
263 | |
264 | static void read_scdc_caps(struct ddc_service *ddc_service, |
265 | struct dc_sink *sink) |
266 | { |
267 | uint8_t slave_address = HDMI_SCDC_ADDRESS; |
268 | uint8_t offset = HDMI_SCDC_MANUFACTURER_OUI; |
269 | |
270 | link_query_ddc_data(ddc: ddc_service, address: slave_address, write_buf: &offset, |
271 | write_size: sizeof(offset), read_buf: sink->scdc_caps.manufacturer_OUI.byte, |
272 | read_size: sizeof(sink->scdc_caps.manufacturer_OUI.byte)); |
273 | |
274 | offset = HDMI_SCDC_DEVICE_ID; |
275 | |
276 | link_query_ddc_data(ddc: ddc_service, address: slave_address, write_buf: &offset, |
277 | write_size: sizeof(offset), read_buf: &(sink->scdc_caps.device_id.byte), |
278 | read_size: sizeof(sink->scdc_caps.device_id.byte)); |
279 | } |
280 | |
281 | static bool i2c_read( |
282 | struct ddc_service *ddc, |
283 | uint32_t address, |
284 | uint8_t *buffer, |
285 | uint32_t len) |
286 | { |
287 | uint8_t offs_data = 0; |
288 | struct i2c_payload payloads[2] = { |
289 | { |
290 | .write = true, |
291 | .address = address, |
292 | .length = 1, |
293 | .data = &offs_data }, |
294 | { |
295 | .write = false, |
296 | .address = address, |
297 | .length = len, |
298 | .data = buffer } }; |
299 | |
300 | struct i2c_command command = { |
301 | .payloads = payloads, |
302 | .number_of_payloads = 2, |
303 | .engine = DDC_I2C_COMMAND_ENGINE, |
304 | .speed = ddc->ctx->dc->caps.i2c_speed_in_khz }; |
305 | |
306 | return dm_helpers_submit_i2c( |
307 | ctx: ddc->ctx, |
308 | link: ddc->link, |
309 | cmd: &command); |
310 | } |
311 | |
312 | enum { |
313 | DP_SINK_CAP_SIZE = |
314 | DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1 |
315 | }; |
316 | |
317 | static void query_dp_dual_mode_adaptor( |
318 | struct ddc_service *ddc, |
319 | struct display_sink_capability *sink_cap) |
320 | { |
321 | uint8_t i; |
322 | bool is_valid_hdmi_signature; |
323 | enum display_dongle_type *dongle = &sink_cap->dongle_type; |
324 | uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE]; |
325 | bool is_type2_dongle = false; |
326 | int retry_count = 2; |
327 | struct dp_hdmi_dongle_signature_data *dongle_signature; |
328 | struct dc_link *link = ddc->link; |
329 | |
330 | /* Assume we have no valid DP passive dongle connected */ |
331 | *dongle = DISPLAY_DONGLE_NONE; |
332 | sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; |
333 | |
334 | /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ |
335 | if (!i2c_read( |
336 | ddc, |
337 | DP_HDMI_DONGLE_ADDRESS, |
338 | buffer: type2_dongle_buf, |
339 | len: sizeof(type2_dongle_buf))) { |
340 | /* Passive HDMI dongles can sometimes fail here without retrying*/ |
341 | while (retry_count > 0) { |
342 | if (i2c_read(ddc, |
343 | DP_HDMI_DONGLE_ADDRESS, |
344 | buffer: type2_dongle_buf, |
345 | len: sizeof(type2_dongle_buf))) |
346 | break; |
347 | retry_count--; |
348 | } |
349 | if (retry_count == 0) { |
350 | *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; |
351 | sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; |
352 | |
353 | CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), |
354 | "DP-DVI passive dongle %dMhz: " , |
355 | DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); |
356 | return; |
357 | } |
358 | } |
359 | |
360 | /* Check if Type 2 dongle.*/ |
361 | if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID) |
362 | is_type2_dongle = true; |
363 | |
364 | dongle_signature = |
365 | (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf; |
366 | |
367 | is_valid_hdmi_signature = true; |
368 | |
369 | /* Check EOT */ |
370 | if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) { |
371 | is_valid_hdmi_signature = false; |
372 | } |
373 | |
374 | /* Check signature */ |
375 | for (i = 0; i < sizeof(dongle_signature->id); ++i) { |
376 | /* If its not the right signature, |
377 | * skip mismatch in subversion byte.*/ |
378 | if (dongle_signature->id[i] != |
379 | dp_hdmi_dongle_signature_str[i] && i != 3) { |
380 | |
381 | if (is_type2_dongle) { |
382 | is_valid_hdmi_signature = false; |
383 | break; |
384 | } |
385 | |
386 | } |
387 | } |
388 | |
389 | if (is_type2_dongle) { |
390 | uint32_t max_tmds_clk = |
391 | type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK]; |
392 | |
393 | max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2; |
394 | |
395 | if (0 == max_tmds_clk || |
396 | max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK || |
397 | max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) { |
398 | *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; |
399 | |
400 | CONN_DATA_DETECT(ddc->link, type2_dongle_buf, |
401 | sizeof(type2_dongle_buf), |
402 | "DP-DVI passive dongle %dMhz: " , |
403 | DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); |
404 | } else { |
405 | if (is_valid_hdmi_signature == true) { |
406 | *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; |
407 | |
408 | CONN_DATA_DETECT(ddc->link, type2_dongle_buf, |
409 | sizeof(type2_dongle_buf), |
410 | "Type 2 DP-HDMI passive dongle %dMhz: " , |
411 | max_tmds_clk); |
412 | } else { |
413 | *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; |
414 | |
415 | CONN_DATA_DETECT(ddc->link, type2_dongle_buf, |
416 | sizeof(type2_dongle_buf), |
417 | "Type 2 DP-HDMI passive dongle (no signature) %dMhz: " , |
418 | max_tmds_clk); |
419 | |
420 | } |
421 | |
422 | /* Multiply by 1000 to convert to kHz. */ |
423 | sink_cap->max_hdmi_pixel_clock = |
424 | max_tmds_clk * 1000; |
425 | } |
426 | sink_cap->is_dongle_type_one = false; |
427 | |
428 | } else { |
429 | if (is_valid_hdmi_signature == true) { |
430 | *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE; |
431 | |
432 | CONN_DATA_DETECT(ddc->link, type2_dongle_buf, |
433 | sizeof(type2_dongle_buf), |
434 | "Type 1 DP-HDMI passive dongle %dMhz: " , |
435 | sink_cap->max_hdmi_pixel_clock / 1000); |
436 | } else { |
437 | *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; |
438 | |
439 | CONN_DATA_DETECT(ddc->link, type2_dongle_buf, |
440 | sizeof(type2_dongle_buf), |
441 | "Type 1 DP-HDMI passive dongle (no signature) %dMhz: " , |
442 | sink_cap->max_hdmi_pixel_clock / 1000); |
443 | } |
444 | sink_cap->is_dongle_type_one = true; |
445 | } |
446 | |
447 | return; |
448 | } |
449 | |
450 | static enum signal_type dp_passive_dongle_detection(struct ddc_service *ddc, |
451 | struct display_sink_capability *sink_cap, |
452 | struct audio_support *audio_support) |
453 | { |
454 | query_dp_dual_mode_adaptor(ddc, sink_cap); |
455 | |
456 | return decide_signal_from_strap_and_dongle_type(dongle_type: sink_cap->dongle_type, |
457 | audio_support); |
458 | } |
459 | |
460 | static void link_disconnect_sink(struct dc_link *link) |
461 | { |
462 | if (link->local_sink) { |
463 | dc_sink_release(sink: link->local_sink); |
464 | link->local_sink = NULL; |
465 | } |
466 | |
467 | link->dpcd_sink_count = 0; |
468 | //link->dpcd_caps.dpcd_rev.raw = 0; |
469 | } |
470 | |
471 | static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *link) |
472 | { |
473 | dc_sink_release(sink: link->local_sink); |
474 | link->local_sink = prev_sink; |
475 | } |
476 | |
477 | static void query_hdcp_capability(enum signal_type signal, struct dc_link *link) |
478 | { |
479 | struct hdcp_protection_message msg22; |
480 | struct hdcp_protection_message msg14; |
481 | |
482 | memset(&msg22, 0, sizeof(struct hdcp_protection_message)); |
483 | memset(&msg14, 0, sizeof(struct hdcp_protection_message)); |
484 | memset(link->hdcp_caps.rx_caps.raw, 0, |
485 | sizeof(link->hdcp_caps.rx_caps.raw)); |
486 | |
487 | if ((link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && |
488 | link->ddc->transaction_type == |
489 | DDC_TRANSACTION_TYPE_I2C_OVER_AUX) || |
490 | link->connector_signal == SIGNAL_TYPE_EDP) { |
491 | msg22.data = link->hdcp_caps.rx_caps.raw; |
492 | msg22.length = sizeof(link->hdcp_caps.rx_caps.raw); |
493 | msg22.msg_id = HDCP_MESSAGE_ID_RX_CAPS; |
494 | } else { |
495 | msg22.data = &link->hdcp_caps.rx_caps.fields.version; |
496 | msg22.length = sizeof(link->hdcp_caps.rx_caps.fields.version); |
497 | msg22.msg_id = HDCP_MESSAGE_ID_HDCP2VERSION; |
498 | } |
499 | msg22.version = HDCP_VERSION_22; |
500 | msg22.link = HDCP_LINK_PRIMARY; |
501 | msg22.max_retries = 5; |
502 | dc_process_hdcp_msg(signal, link, message_info: &msg22); |
503 | |
504 | if (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { |
505 | msg14.data = &link->hdcp_caps.bcaps.raw; |
506 | msg14.length = sizeof(link->hdcp_caps.bcaps.raw); |
507 | msg14.msg_id = HDCP_MESSAGE_ID_READ_BCAPS; |
508 | msg14.version = HDCP_VERSION_14; |
509 | msg14.link = HDCP_LINK_PRIMARY; |
510 | msg14.max_retries = 5; |
511 | |
512 | dc_process_hdcp_msg(signal, link, message_info: &msg14); |
513 | } |
514 | |
515 | } |
516 | static void read_current_link_settings_on_detect(struct dc_link *link) |
517 | { |
518 | union lane_count_set lane_count_set = {0}; |
519 | uint8_t link_bw_set; |
520 | uint8_t link_rate_set; |
521 | uint32_t read_dpcd_retry_cnt = 10; |
522 | enum dc_status status = DC_ERROR_UNEXPECTED; |
523 | int i; |
524 | union max_down_spread max_down_spread = {0}; |
525 | |
526 | // Read DPCD 00101h to find out the number of lanes currently set |
527 | for (i = 0; i < read_dpcd_retry_cnt; i++) { |
528 | status = core_link_read_dpcd(link, |
529 | DP_LANE_COUNT_SET, |
530 | data: &lane_count_set.raw, |
531 | size: sizeof(lane_count_set)); |
532 | /* First DPCD read after VDD ON can fail if the particular board |
533 | * does not have HPD pin wired correctly. So if DPCD read fails, |
534 | * which it should never happen, retry a few times. Target worst |
535 | * case scenario of 80 ms. |
536 | */ |
537 | if (status == DC_OK) { |
538 | link->cur_link_settings.lane_count = |
539 | lane_count_set.bits.LANE_COUNT_SET; |
540 | break; |
541 | } |
542 | |
543 | msleep(msecs: 8); |
544 | } |
545 | |
546 | // Read DPCD 00100h to find if standard link rates are set |
547 | core_link_read_dpcd(link, DP_LINK_BW_SET, |
548 | data: &link_bw_set, size: sizeof(link_bw_set)); |
549 | |
550 | if (link_bw_set == 0) { |
551 | if (link->connector_signal == SIGNAL_TYPE_EDP) { |
552 | /* If standard link rates are not being used, |
553 | * Read DPCD 00115h to find the edp link rate set used |
554 | */ |
555 | core_link_read_dpcd(link, DP_LINK_RATE_SET, |
556 | data: &link_rate_set, size: sizeof(link_rate_set)); |
557 | |
558 | // edp_supported_link_rates_count = 0 for DP |
559 | if (link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) { |
560 | link->cur_link_settings.link_rate = |
561 | link->dpcd_caps.edp_supported_link_rates[link_rate_set]; |
562 | link->cur_link_settings.link_rate_set = link_rate_set; |
563 | link->cur_link_settings.use_link_rate_set = true; |
564 | } |
565 | } else { |
566 | // Link Rate not found. Seamless boot may not work. |
567 | ASSERT(false); |
568 | } |
569 | } else { |
570 | link->cur_link_settings.link_rate = link_bw_set; |
571 | link->cur_link_settings.use_link_rate_set = false; |
572 | } |
573 | // Read DPCD 00003h to find the max down spread. |
574 | core_link_read_dpcd(link, DP_MAX_DOWNSPREAD, |
575 | data: &max_down_spread.raw, size: sizeof(max_down_spread)); |
576 | link->cur_link_settings.link_spread = |
577 | max_down_spread.bits.MAX_DOWN_SPREAD ? |
578 | LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED; |
579 | } |
580 | |
581 | static bool detect_dp(struct dc_link *link, |
582 | struct display_sink_capability *sink_caps, |
583 | enum dc_detect_reason reason) |
584 | { |
585 | struct audio_support *audio_support = &link->dc->res_pool->audio_support; |
586 | |
587 | sink_caps->signal = link_detect_sink_signal_type(link, reason); |
588 | sink_caps->transaction_type = |
589 | get_ddc_transaction_type(sink_signal: sink_caps->signal); |
590 | |
591 | if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { |
592 | sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT; |
593 | if (!detect_dp_sink_caps(link)) |
594 | return false; |
595 | |
596 | if (is_dp_branch_device(link)) |
597 | /* DP SST branch */ |
598 | link->type = dc_connection_sst_branch; |
599 | } else { |
600 | if (link->dc->debug.disable_dp_plus_plus_wa && |
601 | link->link_enc->features.flags.bits.IS_UHBR20_CAPABLE) |
602 | return false; |
603 | |
604 | /* DP passive dongles */ |
605 | sink_caps->signal = dp_passive_dongle_detection(ddc: link->ddc, |
606 | sink_cap: sink_caps, |
607 | audio_support); |
608 | link->dpcd_caps.dongle_type = sink_caps->dongle_type; |
609 | link->dpcd_caps.is_dongle_type_one = sink_caps->is_dongle_type_one; |
610 | link->dpcd_caps.dpcd_rev.raw = 0; |
611 | } |
612 | |
613 | return true; |
614 | } |
615 | |
616 | static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid) |
617 | { |
618 | if (old_edid->length != new_edid->length) |
619 | return false; |
620 | |
621 | if (new_edid->length == 0) |
622 | return false; |
623 | |
624 | return (memcmp(p: old_edid->raw_edid, |
625 | q: new_edid->raw_edid, size: new_edid->length) == 0); |
626 | } |
627 | |
628 | static bool wait_for_entering_dp_alt_mode(struct dc_link *link) |
629 | { |
630 | |
631 | /** |
632 | * something is terribly wrong if time out is > 200ms. (5Hz) |
633 | * 500 microseconds * 400 tries us 200 ms |
634 | **/ |
635 | unsigned int sleep_time_in_microseconds = 500; |
636 | unsigned int tries_allowed = 400; |
637 | bool is_in_alt_mode; |
638 | unsigned long long enter_timestamp; |
639 | unsigned long long finish_timestamp; |
640 | unsigned long long time_taken_in_ns; |
641 | int tries_taken; |
642 | |
643 | DC_LOGGER_INIT(link->ctx->logger); |
644 | |
645 | /** |
646 | * this function will only exist if we are on dcn21 (is_in_alt_mode is a |
647 | * function pointer, so checking to see if it is equal to 0 is the same |
648 | * as checking to see if it is null |
649 | **/ |
650 | if (!link->link_enc->funcs->is_in_alt_mode) |
651 | return true; |
652 | |
653 | is_in_alt_mode = link->link_enc->funcs->is_in_alt_mode(link->link_enc); |
654 | DC_LOG_DC("DP Alt mode state on HPD: %d\n" , is_in_alt_mode); |
655 | |
656 | if (is_in_alt_mode) |
657 | return true; |
658 | |
659 | enter_timestamp = dm_get_timestamp(ctx: link->ctx); |
660 | |
661 | for (tries_taken = 0; tries_taken < tries_allowed; tries_taken++) { |
662 | udelay(sleep_time_in_microseconds); |
663 | /* ask the link if alt mode is enabled, if so return ok */ |
664 | if (link->link_enc->funcs->is_in_alt_mode(link->link_enc)) { |
665 | finish_timestamp = dm_get_timestamp(ctx: link->ctx); |
666 | time_taken_in_ns = |
667 | dm_get_elapse_time_in_ns(ctx: link->ctx, |
668 | current_time_stamp: finish_timestamp, |
669 | last_time_stamp: enter_timestamp); |
670 | DC_LOG_WARNING("Alt mode entered finished after %llu ms\n" , |
671 | div_u64(time_taken_in_ns, 1000000)); |
672 | return true; |
673 | } |
674 | } |
675 | finish_timestamp = dm_get_timestamp(ctx: link->ctx); |
676 | time_taken_in_ns = dm_get_elapse_time_in_ns(ctx: link->ctx, current_time_stamp: finish_timestamp, |
677 | last_time_stamp: enter_timestamp); |
678 | DC_LOG_WARNING("Alt mode has timed out after %llu ms\n" , |
679 | div_u64(time_taken_in_ns, 1000000)); |
680 | return false; |
681 | } |
682 | |
683 | static void apply_dpia_mst_dsc_always_on_wa(struct dc_link *link) |
684 | { |
685 | /* Apply work around for tunneled MST on certain USB4 docks. Always use DSC if dock |
686 | * reports DSC support. |
687 | */ |
688 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && |
689 | link->type == dc_connection_mst_branch && |
690 | link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 && |
691 | link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_20 && |
692 | link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && |
693 | !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around) |
694 | link->wa_flags.dpia_mst_dsc_always_on = true; |
695 | } |
696 | |
697 | static void revert_dpia_mst_dsc_always_on_wa(struct dc_link *link) |
698 | { |
699 | /* Disable work around which keeps DSC on for tunneled MST on certain USB4 docks. */ |
700 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) |
701 | link->wa_flags.dpia_mst_dsc_always_on = false; |
702 | } |
703 | |
704 | static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason reason) |
705 | { |
706 | DC_LOGGER_INIT(link->ctx->logger); |
707 | |
708 | LINK_INFO("link=%d, mst branch is now Connected\n" , |
709 | link->link_index); |
710 | |
711 | link->type = dc_connection_mst_branch; |
712 | apply_dpia_mst_dsc_always_on_wa(link); |
713 | |
714 | dm_helpers_dp_update_branch_info(ctx: link->ctx, link); |
715 | if (dm_helpers_dp_mst_start_top_mgr(ctx: link->ctx, |
716 | link, boot: (reason == DETECT_REASON_BOOT || reason == DETECT_REASON_RESUMEFROMS3S4))) { |
717 | link_disconnect_sink(link); |
718 | } else { |
719 | link->type = dc_connection_sst_branch; |
720 | } |
721 | |
722 | return link->type == dc_connection_mst_branch; |
723 | } |
724 | |
725 | bool link_reset_cur_dp_mst_topology(struct dc_link *link) |
726 | { |
727 | DC_LOGGER_INIT(link->ctx->logger); |
728 | |
729 | LINK_INFO("link=%d, mst branch is now Disconnected\n" , |
730 | link->link_index); |
731 | |
732 | revert_dpia_mst_dsc_always_on_wa(link); |
733 | return dm_helpers_dp_mst_stop_top_mgr(ctx: link->ctx, link); |
734 | } |
735 | |
736 | static bool should_prepare_phy_clocks_for_link_verification(const struct dc *dc, |
737 | enum dc_detect_reason reason) |
738 | { |
739 | int i; |
740 | bool can_apply_seamless_boot = false; |
741 | |
742 | for (i = 0; i < dc->current_state->stream_count; i++) { |
743 | if (dc->current_state->streams[i]->apply_seamless_boot_optimization) { |
744 | can_apply_seamless_boot = true; |
745 | break; |
746 | } |
747 | } |
748 | |
749 | return !can_apply_seamless_boot && reason != DETECT_REASON_BOOT; |
750 | } |
751 | |
752 | static void prepare_phy_clocks_for_destructive_link_verification(const struct dc *dc) |
753 | { |
754 | dc_z10_restore(dc); |
755 | clk_mgr_exit_optimized_pwr_state(dc, clk_mgr: dc->clk_mgr); |
756 | } |
757 | |
758 | static void restore_phy_clocks_for_destructive_link_verification(const struct dc *dc) |
759 | { |
760 | clk_mgr_optimize_pwr_state(dc, clk_mgr: dc->clk_mgr); |
761 | } |
762 | |
763 | static void verify_link_capability_destructive(struct dc_link *link, |
764 | struct dc_sink *sink, |
765 | enum dc_detect_reason reason) |
766 | { |
767 | bool should_prepare_phy_clocks = |
768 | should_prepare_phy_clocks_for_link_verification(dc: link->dc, reason); |
769 | |
770 | if (should_prepare_phy_clocks) |
771 | prepare_phy_clocks_for_destructive_link_verification(dc: link->dc); |
772 | |
773 | if (dc_is_dp_signal(signal: link->local_sink->sink_signal)) { |
774 | struct dc_link_settings known_limit_link_setting = |
775 | dp_get_max_link_cap(link); |
776 | link_set_all_streams_dpms_off_for_link(link); |
777 | dp_verify_link_cap_with_retries( |
778 | link, known_limit_link_setting: &known_limit_link_setting, |
779 | LINK_TRAINING_MAX_VERIFY_RETRY); |
780 | } else { |
781 | ASSERT(0); |
782 | } |
783 | |
784 | if (should_prepare_phy_clocks) |
785 | restore_phy_clocks_for_destructive_link_verification(dc: link->dc); |
786 | } |
787 | |
788 | static void verify_link_capability_non_destructive(struct dc_link *link) |
789 | { |
790 | if (dc_is_dp_signal(signal: link->local_sink->sink_signal)) { |
791 | if (dc_is_embedded_signal(signal: link->local_sink->sink_signal) || |
792 | link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) |
793 | /* TODO - should we check link encoder's max link caps here? |
794 | * How do we know which link encoder to check from? |
795 | */ |
796 | link->verified_link_cap = link->reported_link_cap; |
797 | else |
798 | link->verified_link_cap = dp_get_max_link_cap(link); |
799 | } |
800 | } |
801 | |
802 | static bool should_verify_link_capability_destructively(struct dc_link *link, |
803 | enum dc_detect_reason reason) |
804 | { |
805 | bool destrictive = false; |
806 | struct dc_link_settings max_link_cap; |
807 | bool is_link_enc_unavailable = link->link_enc && |
808 | link->dc->res_pool->funcs->link_encs_assign && |
809 | !link_enc_cfg_is_link_enc_avail( |
810 | dc: link->ctx->dc, |
811 | eng_id: link->link_enc->preferred_engine, |
812 | link); |
813 | |
814 | if (dc_is_dp_signal(signal: link->local_sink->sink_signal)) { |
815 | max_link_cap = dp_get_max_link_cap(link); |
816 | destrictive = true; |
817 | |
818 | if (link->dc->debug.skip_detection_link_training || |
819 | dc_is_embedded_signal(signal: link->local_sink->sink_signal) || |
820 | link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { |
821 | destrictive = false; |
822 | } else if (link_dp_get_encoding_format(link_settings: &max_link_cap) == |
823 | DP_8b_10b_ENCODING) { |
824 | if (link->dpcd_caps.is_mst_capable || |
825 | is_link_enc_unavailable) { |
826 | destrictive = false; |
827 | } |
828 | } |
829 | } |
830 | |
831 | return destrictive; |
832 | } |
833 | |
834 | static void verify_link_capability(struct dc_link *link, struct dc_sink *sink, |
835 | enum dc_detect_reason reason) |
836 | { |
837 | if (should_verify_link_capability_destructively(link, reason)) |
838 | verify_link_capability_destructive(link, sink, reason); |
839 | else |
840 | verify_link_capability_non_destructive(link); |
841 | } |
842 | |
843 | /* |
844 | * detect_link_and_local_sink() - Detect if a sink is attached to a given link |
845 | * |
846 | * link->local_sink is created or destroyed as needed. |
847 | * |
848 | * This does not create remote sinks. |
849 | */ |
850 | static bool detect_link_and_local_sink(struct dc_link *link, |
851 | enum dc_detect_reason reason) |
852 | { |
853 | struct dc_sink_init_data sink_init_data = { 0 }; |
854 | struct display_sink_capability sink_caps = { 0 }; |
855 | uint32_t i; |
856 | bool converter_disable_audio = false; |
857 | struct audio_support *aud_support = &link->dc->res_pool->audio_support; |
858 | bool same_edid = false; |
859 | enum dc_edid_status edid_status; |
860 | struct dc_context *dc_ctx = link->ctx; |
861 | struct dc *dc = dc_ctx->dc; |
862 | struct dc_sink *sink = NULL; |
863 | struct dc_sink *prev_sink = NULL; |
864 | struct dpcd_caps prev_dpcd_caps; |
865 | enum dc_connection_type new_connection_type = dc_connection_none; |
866 | enum dc_connection_type pre_connection_type = link->type; |
867 | const uint32_t post_oui_delay = 30; // 30ms |
868 | |
869 | DC_LOGGER_INIT(link->ctx->logger); |
870 | |
871 | if (dc_is_virtual_signal(signal: link->connector_signal)) |
872 | return false; |
873 | |
874 | if (((link->connector_signal == SIGNAL_TYPE_LVDS || |
875 | link->connector_signal == SIGNAL_TYPE_EDP) && |
876 | (!link->dc->config.allow_edp_hotplug_detection)) && |
877 | link->local_sink) { |
878 | // need to re-write OUI and brightness in resume case |
879 | if (link->connector_signal == SIGNAL_TYPE_EDP && |
880 | (link->dpcd_sink_ext_caps.bits.oled == 1)) { |
881 | dpcd_set_source_specific_data(link); |
882 | msleep(msecs: post_oui_delay); |
883 | set_default_brightness_aux(link); |
884 | } |
885 | |
886 | return true; |
887 | } |
888 | |
889 | if (!link_detect_connection_type(link, type: &new_connection_type)) { |
890 | BREAK_TO_DEBUGGER(); |
891 | return false; |
892 | } |
893 | |
894 | prev_sink = link->local_sink; |
895 | if (prev_sink) { |
896 | dc_sink_retain(sink: prev_sink); |
897 | memcpy(&prev_dpcd_caps, &link->dpcd_caps, sizeof(struct dpcd_caps)); |
898 | } |
899 | |
900 | link_disconnect_sink(link); |
901 | if (new_connection_type != dc_connection_none) { |
902 | link->type = new_connection_type; |
903 | link->link_state_valid = false; |
904 | |
905 | /* From Disconnected-to-Connected. */ |
906 | switch (link->connector_signal) { |
907 | case SIGNAL_TYPE_HDMI_TYPE_A: { |
908 | sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C; |
909 | if (aud_support->hdmi_audio_native) |
910 | sink_caps.signal = SIGNAL_TYPE_HDMI_TYPE_A; |
911 | else |
912 | sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; |
913 | break; |
914 | } |
915 | |
916 | case SIGNAL_TYPE_DVI_SINGLE_LINK: { |
917 | sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C; |
918 | sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; |
919 | break; |
920 | } |
921 | |
922 | case SIGNAL_TYPE_DVI_DUAL_LINK: { |
923 | sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C; |
924 | sink_caps.signal = SIGNAL_TYPE_DVI_DUAL_LINK; |
925 | break; |
926 | } |
927 | |
928 | case SIGNAL_TYPE_LVDS: { |
929 | sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C; |
930 | sink_caps.signal = SIGNAL_TYPE_LVDS; |
931 | break; |
932 | } |
933 | |
934 | case SIGNAL_TYPE_EDP: { |
935 | detect_edp_sink_caps(link); |
936 | read_current_link_settings_on_detect(link); |
937 | |
938 | /* Disable power sequence on MIPI panel + converter |
939 | */ |
940 | if (dc->config.enable_mipi_converter_optimization && |
941 | dc_ctx->dce_version == DCN_VERSION_3_01 && |
942 | link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_0022B9 && |
943 | memcmp(p: &link->dpcd_caps.branch_dev_name, q: DP_SINK_BRANCH_DEV_NAME_7580, |
944 | size: sizeof(link->dpcd_caps.branch_dev_name)) == 0) { |
945 | dc->config.edp_no_power_sequencing = true; |
946 | |
947 | if (!link->dpcd_caps.set_power_state_capable_edp) |
948 | link->wa_flags.dp_keep_receiver_powered = true; |
949 | } |
950 | |
951 | sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX; |
952 | sink_caps.signal = SIGNAL_TYPE_EDP; |
953 | break; |
954 | } |
955 | |
956 | case SIGNAL_TYPE_DISPLAY_PORT: { |
957 | |
958 | /* wa HPD high coming too early*/ |
959 | if (link->ep_type == DISPLAY_ENDPOINT_PHY && |
960 | link->link_enc->features.flags.bits.DP_IS_USB_C == 1) { |
961 | |
962 | /* if alt mode times out, return false */ |
963 | if (!wait_for_entering_dp_alt_mode(link)) |
964 | return false; |
965 | } |
966 | |
967 | if (!detect_dp(link, sink_caps: &sink_caps, reason)) { |
968 | link->type = pre_connection_type; |
969 | |
970 | if (prev_sink) |
971 | dc_sink_release(sink: prev_sink); |
972 | return false; |
973 | } |
974 | |
975 | /* Active SST downstream branch device unplug*/ |
976 | if (link->type == dc_connection_sst_branch && |
977 | link->dpcd_caps.sink_count.bits.SINK_COUNT == 0) { |
978 | if (prev_sink) |
979 | /* Downstream unplug */ |
980 | dc_sink_release(sink: prev_sink); |
981 | return true; |
982 | } |
983 | |
984 | /* disable audio for non DP to HDMI active sst converter */ |
985 | if (link->type == dc_connection_sst_branch && |
986 | is_dp_active_dongle(link) && |
987 | (link->dpcd_caps.dongle_type != |
988 | DISPLAY_DONGLE_DP_HDMI_CONVERTER)) |
989 | converter_disable_audio = true; |
990 | |
991 | /* limited link rate to HBR3 for DPIA until we implement USB4 V2 */ |
992 | if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && |
993 | link->reported_link_cap.link_rate > LINK_RATE_HIGH3) |
994 | link->reported_link_cap.link_rate = LINK_RATE_HIGH3; |
995 | |
996 | /* |
997 | * If this is DP over USB4 link then we need to: |
998 | * - Enable BW ALLOC support on DPtx if applicable |
999 | */ |
1000 | if (dc->config.usb4_bw_alloc_support) { |
1001 | if (link_dp_dpia_set_dptx_usb4_bw_alloc_support(link)) { |
1002 | /* update with non reduced link cap if bw allocation mode is supported */ |
1003 | if (link->dpia_bw_alloc_config.nrd_max_link_rate && |
1004 | link->dpia_bw_alloc_config.nrd_max_lane_count) { |
1005 | link->reported_link_cap.link_rate = |
1006 | link->dpia_bw_alloc_config.nrd_max_link_rate; |
1007 | link->reported_link_cap.lane_count = |
1008 | link->dpia_bw_alloc_config.nrd_max_lane_count; |
1009 | } |
1010 | } |
1011 | } |
1012 | break; |
1013 | } |
1014 | |
1015 | default: |
1016 | DC_ERROR("Invalid connector type! signal:%d\n" , |
1017 | link->connector_signal); |
1018 | if (prev_sink) |
1019 | dc_sink_release(sink: prev_sink); |
1020 | return false; |
1021 | } /* switch() */ |
1022 | |
1023 | if (link->dpcd_caps.sink_count.bits.SINK_COUNT) |
1024 | link->dpcd_sink_count = |
1025 | link->dpcd_caps.sink_count.bits.SINK_COUNT; |
1026 | else |
1027 | link->dpcd_sink_count = 1; |
1028 | |
1029 | set_ddc_transaction_type(ddc: link->ddc, |
1030 | type: sink_caps.transaction_type); |
1031 | |
1032 | link->aux_mode = |
1033 | link_is_in_aux_transaction_mode(ddc: link->ddc); |
1034 | |
1035 | sink_init_data.link = link; |
1036 | sink_init_data.sink_signal = sink_caps.signal; |
1037 | |
1038 | sink = dc_sink_create(init_params: &sink_init_data); |
1039 | if (!sink) { |
1040 | DC_ERROR("Failed to create sink!\n" ); |
1041 | if (prev_sink) |
1042 | dc_sink_release(sink: prev_sink); |
1043 | return false; |
1044 | } |
1045 | |
1046 | sink->link->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock; |
1047 | sink->converter_disable_audio = converter_disable_audio; |
1048 | |
1049 | /* dc_sink_create returns a new reference */ |
1050 | link->local_sink = sink; |
1051 | |
1052 | edid_status = dm_helpers_read_local_edid(ctx: link->ctx, |
1053 | link, sink); |
1054 | |
1055 | switch (edid_status) { |
1056 | case EDID_BAD_CHECKSUM: |
1057 | DC_LOG_ERROR("EDID checksum invalid.\n" ); |
1058 | break; |
1059 | case EDID_PARTIAL_VALID: |
1060 | DC_LOG_ERROR("Partial EDID valid, abandon invalid blocks.\n" ); |
1061 | break; |
1062 | case EDID_NO_RESPONSE: |
1063 | DC_LOG_ERROR("No EDID read.\n" ); |
1064 | /* |
1065 | * Abort detection for non-DP connectors if we have |
1066 | * no EDID |
1067 | * |
1068 | * DP needs to report as connected if HDP is high |
1069 | * even if we have no EDID in order to go to |
1070 | * fail-safe mode |
1071 | */ |
1072 | if (dc_is_hdmi_signal(signal: link->connector_signal) || |
1073 | dc_is_dvi_signal(signal: link->connector_signal)) { |
1074 | if (prev_sink) |
1075 | dc_sink_release(sink: prev_sink); |
1076 | |
1077 | return false; |
1078 | } |
1079 | |
1080 | if (link->type == dc_connection_sst_branch && |
1081 | link->dpcd_caps.dongle_type == |
1082 | DISPLAY_DONGLE_DP_VGA_CONVERTER && |
1083 | reason == DETECT_REASON_HPDRX) { |
1084 | /* Abort detection for DP-VGA adapters when EDID |
1085 | * can't be read and detection reason is VGA-side |
1086 | * hotplug |
1087 | */ |
1088 | if (prev_sink) |
1089 | dc_sink_release(sink: prev_sink); |
1090 | link_disconnect_sink(link); |
1091 | |
1092 | return true; |
1093 | } |
1094 | |
1095 | break; |
1096 | default: |
1097 | break; |
1098 | } |
1099 | |
1100 | // Check if edid is the same |
1101 | if ((prev_sink) && |
1102 | (edid_status == EDID_THE_SAME || edid_status == EDID_OK)) |
1103 | same_edid = is_same_edid(old_edid: &prev_sink->dc_edid, |
1104 | new_edid: &sink->dc_edid); |
1105 | |
1106 | if (sink->edid_caps.panel_patch.skip_scdc_overwrite) |
1107 | link->ctx->dc->debug.hdmi20_disable = true; |
1108 | |
1109 | if (sink->edid_caps.panel_patch.remove_sink_ext_caps) |
1110 | link->dpcd_sink_ext_caps.raw = 0; |
1111 | |
1112 | if (dc_is_hdmi_signal(signal: link->connector_signal)) |
1113 | read_scdc_caps(ddc_service: link->ddc, sink: link->local_sink); |
1114 | |
1115 | if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && |
1116 | sink_caps.transaction_type == |
1117 | DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { |
1118 | /* |
1119 | * TODO debug why certain monitors don't like |
1120 | * two link trainings |
1121 | */ |
1122 | query_hdcp_capability(signal: sink->sink_signal, link); |
1123 | } else { |
1124 | // If edid is the same, then discard new sink and revert back to original sink |
1125 | if (same_edid) { |
1126 | link_disconnect_remap(prev_sink, link); |
1127 | sink = prev_sink; |
1128 | prev_sink = NULL; |
1129 | } |
1130 | query_hdcp_capability(signal: sink->sink_signal, link); |
1131 | } |
1132 | |
1133 | /* HDMI-DVI Dongle */ |
1134 | if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && |
1135 | !sink->edid_caps.edid_hdmi) |
1136 | sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; |
1137 | |
1138 | if (link->local_sink && dc_is_dp_signal(signal: sink_caps.signal)) |
1139 | dp_trace_init(link); |
1140 | |
1141 | /* Connectivity log: detection */ |
1142 | for (i = 0; i < sink->dc_edid.length / DC_EDID_BLOCK_SIZE; i++) { |
1143 | CONN_DATA_DETECT(link, |
1144 | &sink->dc_edid.raw_edid[i * DC_EDID_BLOCK_SIZE], |
1145 | DC_EDID_BLOCK_SIZE, |
1146 | "%s: [Block %d] " , sink->edid_caps.display_name, i); |
1147 | } |
1148 | |
1149 | DC_LOG_DETECTION_EDID_PARSER("%s: " |
1150 | "manufacturer_id = %X, " |
1151 | "product_id = %X, " |
1152 | "serial_number = %X, " |
1153 | "manufacture_week = %d, " |
1154 | "manufacture_year = %d, " |
1155 | "display_name = %s, " |
1156 | "speaker_flag = %d, " |
1157 | "audio_mode_count = %d\n" , |
1158 | __func__, |
1159 | sink->edid_caps.manufacturer_id, |
1160 | sink->edid_caps.product_id, |
1161 | sink->edid_caps.serial_number, |
1162 | sink->edid_caps.manufacture_week, |
1163 | sink->edid_caps.manufacture_year, |
1164 | sink->edid_caps.display_name, |
1165 | sink->edid_caps.speaker_flags, |
1166 | sink->edid_caps.audio_mode_count); |
1167 | |
1168 | for (i = 0; i < sink->edid_caps.audio_mode_count; i++) { |
1169 | DC_LOG_DETECTION_EDID_PARSER("%s: mode number = %d, " |
1170 | "format_code = %d, " |
1171 | "channel_count = %d, " |
1172 | "sample_rate = %d, " |
1173 | "sample_size = %d\n" , |
1174 | __func__, |
1175 | i, |
1176 | sink->edid_caps.audio_modes[i].format_code, |
1177 | sink->edid_caps.audio_modes[i].channel_count, |
1178 | sink->edid_caps.audio_modes[i].sample_rate, |
1179 | sink->edid_caps.audio_modes[i].sample_size); |
1180 | } |
1181 | |
1182 | if (link->connector_signal == SIGNAL_TYPE_EDP) { |
1183 | // Init dc_panel_config by HW config |
1184 | if (dc_ctx->dc->res_pool->funcs->get_panel_config_defaults) |
1185 | dc_ctx->dc->res_pool->funcs->get_panel_config_defaults(&link->panel_config); |
1186 | // Pickup base DM settings |
1187 | dm_helpers_init_panel_settings(ctx: dc_ctx, config: &link->panel_config, sink); |
1188 | // Override dc_panel_config if system has specific settings |
1189 | dm_helpers_override_panel_settings(ctx: dc_ctx, config: &link->panel_config); |
1190 | |
1191 | //sink only can use supported link rate table, we are foreced to enable it |
1192 | if (link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN) |
1193 | link->panel_config.ilr.optimize_edp_link_rate = true; |
1194 | if (edp_is_ilr_optimization_enabled(link)) |
1195 | link->reported_link_cap.link_rate = get_max_link_rate_from_ilr_table(link); |
1196 | } |
1197 | |
1198 | } else { |
1199 | /* From Connected-to-Disconnected. */ |
1200 | link->type = dc_connection_none; |
1201 | sink_caps.signal = SIGNAL_TYPE_NONE; |
1202 | memset(&link->hdcp_caps, 0, sizeof(struct hdcp_caps)); |
1203 | /* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk |
1204 | * is not cleared. If we emulate a DP signal on this connection, it thinks |
1205 | * the dongle is still there and limits the number of modes we can emulate. |
1206 | * Clear dongle_max_pix_clk on disconnect to fix this |
1207 | */ |
1208 | link->dongle_max_pix_clk = 0; |
1209 | |
1210 | dc_link_clear_dprx_states(link); |
1211 | dp_trace_reset(link); |
1212 | } |
1213 | |
1214 | LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n" , |
1215 | link->link_index, sink, |
1216 | (sink_caps.signal == |
1217 | SIGNAL_TYPE_NONE ? "Disconnected" : "Connected" ), |
1218 | prev_sink, same_edid); |
1219 | |
1220 | if (prev_sink) |
1221 | dc_sink_release(sink: prev_sink); |
1222 | |
1223 | return true; |
1224 | } |
1225 | |
1226 | /* |
1227 | * link_detect_connection_type() - Determine if there is a sink connected |
1228 | * |
1229 | * @type: Returned connection type |
1230 | * Does not detect downstream devices, such as MST sinks |
1231 | * or display connected through active dongles |
1232 | */ |
1233 | bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type *type) |
1234 | { |
1235 | uint32_t is_hpd_high = 0; |
1236 | |
1237 | if (link->connector_signal == SIGNAL_TYPE_LVDS) { |
1238 | *type = dc_connection_single; |
1239 | return true; |
1240 | } |
1241 | |
1242 | if (link->connector_signal == SIGNAL_TYPE_EDP) { |
1243 | /*in case it is not on*/ |
1244 | if (!link->dc->config.edp_no_power_sequencing) |
1245 | link->dc->hwss.edp_power_control(link, true); |
1246 | link->dc->hwss.edp_wait_for_hpd_ready(link, true); |
1247 | } |
1248 | |
1249 | /* Link may not have physical HPD pin. */ |
1250 | if (link->ep_type != DISPLAY_ENDPOINT_PHY) { |
1251 | if (link->is_hpd_pending || !dpia_query_hpd_status(link)) |
1252 | *type = dc_connection_none; |
1253 | else |
1254 | *type = dc_connection_single; |
1255 | |
1256 | return true; |
1257 | } |
1258 | |
1259 | |
1260 | if (!query_hpd_status(link, is_hpd_high: &is_hpd_high)) |
1261 | goto hpd_gpio_failure; |
1262 | |
1263 | if (is_hpd_high) { |
1264 | *type = dc_connection_single; |
1265 | /* TODO: need to do the actual detection */ |
1266 | } else { |
1267 | *type = dc_connection_none; |
1268 | if (link->connector_signal == SIGNAL_TYPE_EDP) { |
1269 | /* eDP is not connected, power down it */ |
1270 | if (!link->dc->config.edp_no_power_sequencing) |
1271 | link->dc->hwss.edp_power_control(link, false); |
1272 | } |
1273 | } |
1274 | |
1275 | return true; |
1276 | |
1277 | hpd_gpio_failure: |
1278 | return false; |
1279 | } |
1280 | |
1281 | bool link_detect(struct dc_link *link, enum dc_detect_reason reason) |
1282 | { |
1283 | bool is_local_sink_detect_success; |
1284 | bool is_delegated_to_mst_top_mgr = false; |
1285 | enum dc_connection_type pre_link_type = link->type; |
1286 | |
1287 | DC_LOGGER_INIT(link->ctx->logger); |
1288 | |
1289 | is_local_sink_detect_success = detect_link_and_local_sink(link, reason); |
1290 | |
1291 | if (is_local_sink_detect_success && link->local_sink) |
1292 | verify_link_capability(link, sink: link->local_sink, reason); |
1293 | |
1294 | DC_LOG_DC("%s: link_index=%d is_local_sink_detect_success=%d pre_link_type=%d link_type=%d\n" , __func__, |
1295 | link->link_index, is_local_sink_detect_success, pre_link_type, link->type); |
1296 | |
1297 | if (is_local_sink_detect_success && link->local_sink && |
1298 | dc_is_dp_signal(signal: link->local_sink->sink_signal) && |
1299 | link->dpcd_caps.is_mst_capable) |
1300 | is_delegated_to_mst_top_mgr = discover_dp_mst_topology(link, reason); |
1301 | |
1302 | if (is_local_sink_detect_success && |
1303 | pre_link_type == dc_connection_mst_branch && |
1304 | link->type != dc_connection_mst_branch) |
1305 | is_delegated_to_mst_top_mgr = link_reset_cur_dp_mst_topology(link); |
1306 | |
1307 | return is_local_sink_detect_success && !is_delegated_to_mst_top_mgr; |
1308 | } |
1309 | |
1310 | void link_clear_dprx_states(struct dc_link *link) |
1311 | { |
1312 | memset(&link->dprx_states, 0, sizeof(link->dprx_states)); |
1313 | } |
1314 | |
1315 | bool link_is_hdcp14(struct dc_link *link, enum signal_type signal) |
1316 | { |
1317 | bool ret = false; |
1318 | |
1319 | switch (signal) { |
1320 | case SIGNAL_TYPE_DISPLAY_PORT: |
1321 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
1322 | ret = link->hdcp_caps.bcaps.bits.HDCP_CAPABLE; |
1323 | break; |
1324 | case SIGNAL_TYPE_DVI_SINGLE_LINK: |
1325 | case SIGNAL_TYPE_DVI_DUAL_LINK: |
1326 | case SIGNAL_TYPE_HDMI_TYPE_A: |
1327 | /* HDMI doesn't tell us its HDCP(1.4) capability, so assume to always be capable, |
1328 | * we can poll for bksv but some displays have an issue with this. Since its so rare |
1329 | * for a display to not be 1.4 capable, this assumtion is ok |
1330 | */ |
1331 | ret = true; |
1332 | break; |
1333 | default: |
1334 | break; |
1335 | } |
1336 | return ret; |
1337 | } |
1338 | |
1339 | bool link_is_hdcp22(struct dc_link *link, enum signal_type signal) |
1340 | { |
1341 | bool ret = false; |
1342 | |
1343 | switch (signal) { |
1344 | case SIGNAL_TYPE_DISPLAY_PORT: |
1345 | case SIGNAL_TYPE_DISPLAY_PORT_MST: |
1346 | ret = (link->hdcp_caps.bcaps.bits.HDCP_CAPABLE && |
1347 | link->hdcp_caps.rx_caps.fields.byte0.hdcp_capable && |
1348 | (link->hdcp_caps.rx_caps.fields.version == 0x2)) ? 1 : 0; |
1349 | break; |
1350 | case SIGNAL_TYPE_DVI_SINGLE_LINK: |
1351 | case SIGNAL_TYPE_DVI_DUAL_LINK: |
1352 | case SIGNAL_TYPE_HDMI_TYPE_A: |
1353 | ret = (link->hdcp_caps.rx_caps.fields.version == 0x4) ? 1:0; |
1354 | break; |
1355 | default: |
1356 | break; |
1357 | } |
1358 | |
1359 | return ret; |
1360 | } |
1361 | |
1362 | const struct dc_link_status *link_get_status(const struct dc_link *link) |
1363 | { |
1364 | return &link->link_status; |
1365 | } |
1366 | |
1367 | |
1368 | static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) |
1369 | { |
1370 | if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { |
1371 | BREAK_TO_DEBUGGER(); |
1372 | return false; |
1373 | } |
1374 | |
1375 | dc_sink_retain(sink); |
1376 | |
1377 | dc_link->remote_sinks[dc_link->sink_count] = sink; |
1378 | dc_link->sink_count++; |
1379 | |
1380 | return true; |
1381 | } |
1382 | |
1383 | struct dc_sink *link_add_remote_sink( |
1384 | struct dc_link *link, |
1385 | const uint8_t *edid, |
1386 | int len, |
1387 | struct dc_sink_init_data *init_data) |
1388 | { |
1389 | struct dc_sink *dc_sink; |
1390 | enum dc_edid_status edid_status; |
1391 | |
1392 | if (len > DC_MAX_EDID_BUFFER_SIZE) { |
1393 | dm_error("Max EDID buffer size breached!\n" ); |
1394 | return NULL; |
1395 | } |
1396 | |
1397 | if (!init_data) { |
1398 | BREAK_TO_DEBUGGER(); |
1399 | return NULL; |
1400 | } |
1401 | |
1402 | if (!init_data->link) { |
1403 | BREAK_TO_DEBUGGER(); |
1404 | return NULL; |
1405 | } |
1406 | |
1407 | dc_sink = dc_sink_create(init_params: init_data); |
1408 | |
1409 | if (!dc_sink) |
1410 | return NULL; |
1411 | |
1412 | memmove(dc_sink->dc_edid.raw_edid, edid, len); |
1413 | dc_sink->dc_edid.length = len; |
1414 | |
1415 | if (!link_add_remote_sink_helper( |
1416 | dc_link: link, |
1417 | sink: dc_sink)) |
1418 | goto fail_add_sink; |
1419 | |
1420 | edid_status = dm_helpers_parse_edid_caps( |
1421 | link, |
1422 | edid: &dc_sink->dc_edid, |
1423 | edid_caps: &dc_sink->edid_caps); |
1424 | |
1425 | /* |
1426 | * Treat device as no EDID device if EDID |
1427 | * parsing fails |
1428 | */ |
1429 | if (edid_status != EDID_OK && edid_status != EDID_PARTIAL_VALID) { |
1430 | dc_sink->dc_edid.length = 0; |
1431 | dm_error("Bad EDID, status%d!\n" , edid_status); |
1432 | } |
1433 | |
1434 | return dc_sink; |
1435 | |
1436 | fail_add_sink: |
1437 | dc_sink_release(sink: dc_sink); |
1438 | return NULL; |
1439 | } |
1440 | |
1441 | void link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) |
1442 | { |
1443 | int i; |
1444 | |
1445 | if (!link->sink_count) { |
1446 | BREAK_TO_DEBUGGER(); |
1447 | return; |
1448 | } |
1449 | |
1450 | for (i = 0; i < link->sink_count; i++) { |
1451 | if (link->remote_sinks[i] == sink) { |
1452 | dc_sink_release(sink); |
1453 | link->remote_sinks[i] = NULL; |
1454 | |
1455 | /* shrink array to remove empty place */ |
1456 | while (i < link->sink_count - 1) { |
1457 | link->remote_sinks[i] = link->remote_sinks[i+1]; |
1458 | i++; |
1459 | } |
1460 | link->remote_sinks[i] = NULL; |
1461 | link->sink_count--; |
1462 | return; |
1463 | } |
1464 | } |
1465 | } |
1466 | |