1/*
2 * Copyright 2023 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 owns the creation/destruction of link structure.
28 */
29#include "link_factory.h"
30#include "link_detection.h"
31#include "link_resource.h"
32#include "link_validation.h"
33#include "link_dpms.h"
34#include "accessories/link_dp_cts.h"
35#include "accessories/link_dp_trace.h"
36#include "protocols/link_ddc.h"
37#include "protocols/link_dp_capability.h"
38#include "protocols/link_dp_dpia_bw.h"
39#include "protocols/link_dp_dpia.h"
40#include "protocols/link_dp_irq_handler.h"
41#include "protocols/link_dp_phy.h"
42#include "protocols/link_dp_training.h"
43#include "protocols/link_edp_panel_control.h"
44#include "protocols/link_hpd.h"
45#include "gpio_service_interface.h"
46#include "atomfirmware.h"
47
48#define DC_LOGGER \
49 dc_ctx->logger
50#define DC_LOGGER_INIT(logger)
51
52#define LINK_INFO(...) \
53 DC_LOG_HW_HOTPLUG( \
54 __VA_ARGS__)
55
56/* link factory owns the creation/destruction of link structures. */
57static void construct_link_service_factory(struct link_service *link_srv)
58{
59
60 link_srv->create_link = link_create;
61 link_srv->destroy_link = link_destroy;
62}
63
64/* link_detection manages link detection states and receiver states by using
65 * various link protocols. It also provides helper functions to interpret
66 * certain capabilities or status based on the states it manages or retrieve
67 * them directly from connected receivers.
68 */
69static void construct_link_service_detection(struct link_service *link_srv)
70{
71 link_srv->detect_link = link_detect;
72 link_srv->detect_connection_type = link_detect_connection_type;
73 link_srv->add_remote_sink = link_add_remote_sink;
74 link_srv->remove_remote_sink = link_remove_remote_sink;
75 link_srv->get_hpd_state = link_get_hpd_state;
76 link_srv->get_hpd_gpio = link_get_hpd_gpio;
77 link_srv->enable_hpd = link_enable_hpd;
78 link_srv->disable_hpd = link_disable_hpd;
79 link_srv->enable_hpd_filter = link_enable_hpd_filter;
80 link_srv->reset_cur_dp_mst_topology = link_reset_cur_dp_mst_topology;
81 link_srv->get_status = link_get_status;
82 link_srv->is_hdcp1x_supported = link_is_hdcp14;
83 link_srv->is_hdcp2x_supported = link_is_hdcp22;
84 link_srv->clear_dprx_states = link_clear_dprx_states;
85}
86
87/* link resource implements accessors to link resource. */
88static void construct_link_service_resource(struct link_service *link_srv)
89{
90 link_srv->get_cur_res_map = link_get_cur_res_map;
91 link_srv->restore_res_map = link_restore_res_map;
92 link_srv->get_cur_link_res = link_get_cur_link_res;
93}
94
95/* link validation owns timing validation against various link limitations. (ex.
96 * link bandwidth, receiver capability or our hardware capability) It also
97 * provides helper functions exposing bandwidth formulas used in validation.
98 */
99static void construct_link_service_validation(struct link_service *link_srv)
100{
101 link_srv->validate_mode_timing = link_validate_mode_timing;
102 link_srv->dp_link_bandwidth_kbps = dp_link_bandwidth_kbps;
103 link_srv->validate_dpia_bandwidth = link_validate_dpia_bandwidth;
104}
105
106/* link dpms owns the programming sequence of stream's dpms state associated
107 * with the link and link's enable/disable sequences as result of the stream's
108 * dpms state change.
109 */
110static void construct_link_service_dpms(struct link_service *link_srv)
111{
112 link_srv->set_dpms_on = link_set_dpms_on;
113 link_srv->set_dpms_off = link_set_dpms_off;
114 link_srv->resume = link_resume;
115 link_srv->blank_all_dp_displays = link_blank_all_dp_displays;
116 link_srv->blank_all_edp_displays = link_blank_all_edp_displays;
117 link_srv->blank_dp_stream = link_blank_dp_stream;
118 link_srv->increase_mst_payload = link_increase_mst_payload;
119 link_srv->reduce_mst_payload = link_reduce_mst_payload;
120 link_srv->set_dsc_on_stream = link_set_dsc_on_stream;
121 link_srv->set_dsc_enable = link_set_dsc_enable;
122 link_srv->update_dsc_config = link_update_dsc_config;
123}
124
125/* link ddc implements generic display communication protocols such as i2c, aux
126 * and scdc. It should not contain any specific applications of these
127 * protocols such as display capability query, detection, or handshaking such as
128 * link training.
129 */
130static void construct_link_service_ddc(struct link_service *link_srv)
131{
132 link_srv->create_ddc_service = link_create_ddc_service;
133 link_srv->destroy_ddc_service = link_destroy_ddc_service;
134 link_srv->query_ddc_data = link_query_ddc_data;
135 link_srv->aux_transfer_raw = link_aux_transfer_raw;
136 link_srv->configure_fixed_vs_pe_retimer = link_configure_fixed_vs_pe_retimer;
137 link_srv->aux_transfer_with_retries_no_mutex =
138 link_aux_transfer_with_retries_no_mutex;
139 link_srv->is_in_aux_transaction_mode = link_is_in_aux_transaction_mode;
140 link_srv->get_aux_defer_delay = link_get_aux_defer_delay;
141}
142
143/* link dp capability implements dp specific link capability retrieval sequence.
144 * It is responsible for retrieving, parsing, overriding, deciding capability
145 * obtained from dp link. Link capability consists of encoders, DPRXs, cables,
146 * retimers, usb and all other possible backend capabilities.
147 */
148static void construct_link_service_dp_capability(struct link_service *link_srv)
149{
150 link_srv->dp_is_sink_present = dp_is_sink_present;
151 link_srv->dp_is_fec_supported = dp_is_fec_supported;
152 link_srv->dp_is_128b_132b_signal = dp_is_128b_132b_signal;
153 link_srv->dp_get_max_link_enc_cap = dp_get_max_link_enc_cap;
154 link_srv->dp_get_verified_link_cap = dp_get_verified_link_cap;
155 link_srv->dp_get_encoding_format = link_dp_get_encoding_format;
156 link_srv->dp_should_enable_fec = dp_should_enable_fec;
157 link_srv->dp_decide_link_settings = link_decide_link_settings;
158 link_srv->mst_decide_link_encoding_format =
159 mst_decide_link_encoding_format;
160 link_srv->edp_decide_link_settings = edp_decide_link_settings;
161 link_srv->bw_kbps_from_raw_frl_link_rate_data =
162 link_bw_kbps_from_raw_frl_link_rate_data;
163 link_srv->dp_overwrite_extended_receiver_cap =
164 dp_overwrite_extended_receiver_cap;
165 link_srv->dp_decide_lttpr_mode = dp_decide_lttpr_mode;
166}
167
168/* link dp phy/dpia implements basic dp phy/dpia functionality such as
169 * enable/disable output and set lane/drive settings. It is responsible for
170 * maintaining and update software state representing current phy/dpia status
171 * such as current link settings.
172 */
173static void construct_link_service_dp_phy_or_dpia(struct link_service *link_srv)
174{
175 link_srv->dpia_handle_usb4_bandwidth_allocation_for_link =
176 dpia_handle_usb4_bandwidth_allocation_for_link;
177 link_srv->dpia_handle_bw_alloc_response = dpia_handle_bw_alloc_response;
178 link_srv->dp_set_drive_settings = dp_set_drive_settings;
179 link_srv->dpcd_write_rx_power_ctrl = dpcd_write_rx_power_ctrl;
180}
181
182/* link dp irq handler implements DP HPD short pulse handling sequence according
183 * to DP specifications
184 */
185static void construct_link_service_dp_irq_handler(struct link_service *link_srv)
186{
187 link_srv->dp_parse_link_loss_status = dp_parse_link_loss_status;
188 link_srv->dp_should_allow_hpd_rx_irq = dp_should_allow_hpd_rx_irq;
189 link_srv->dp_handle_link_loss = dp_handle_link_loss;
190 link_srv->dp_read_hpd_rx_irq_data = dp_read_hpd_rx_irq_data;
191 link_srv->dp_handle_hpd_rx_irq = dp_handle_hpd_rx_irq;
192}
193
194/* link edp panel control implements retrieval and configuration of eDP panel
195 * features such as PSR and ABM and it also manages specs defined eDP panel
196 * power sequences.
197 */
198static void construct_link_service_edp_panel_control(struct link_service *link_srv)
199{
200 link_srv->edp_panel_backlight_power_on = edp_panel_backlight_power_on;
201 link_srv->edp_get_backlight_level = edp_get_backlight_level;
202 link_srv->edp_get_backlight_level_nits = edp_get_backlight_level_nits;
203 link_srv->edp_set_backlight_level = edp_set_backlight_level;
204 link_srv->edp_set_backlight_level_nits = edp_set_backlight_level_nits;
205 link_srv->edp_get_target_backlight_pwm = edp_get_target_backlight_pwm;
206 link_srv->edp_get_psr_state = edp_get_psr_state;
207 link_srv->edp_set_psr_allow_active = edp_set_psr_allow_active;
208 link_srv->edp_setup_psr = edp_setup_psr;
209 link_srv->edp_set_sink_vtotal_in_psr_active =
210 edp_set_sink_vtotal_in_psr_active;
211 link_srv->edp_get_psr_residency = edp_get_psr_residency;
212
213 link_srv->edp_get_replay_state = edp_get_replay_state;
214 link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active;
215 link_srv->edp_setup_replay = edp_setup_replay;
216 link_srv->edp_send_replay_cmd = edp_send_replay_cmd;
217 link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
218 link_srv->edp_replay_residency = edp_replay_residency;
219 link_srv->edp_set_replay_power_opt_and_coasting_vtotal = edp_set_replay_power_opt_and_coasting_vtotal;
220
221 link_srv->edp_wait_for_t12 = edp_wait_for_t12;
222 link_srv->edp_is_ilr_optimization_required =
223 edp_is_ilr_optimization_required;
224 link_srv->edp_backlight_enable_aux = edp_backlight_enable_aux;
225 link_srv->edp_add_delay_for_T9 = edp_add_delay_for_T9;
226 link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9;
227 link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7;
228 link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable;
229 link_srv->edp_set_panel_power = edp_set_panel_power;
230}
231
232/* link dp cts implements dp compliance test automation protocols and manual
233 * testing interfaces for debugging and certification purpose.
234 */
235static void construct_link_service_dp_cts(struct link_service *link_srv)
236{
237 link_srv->dp_handle_automated_test = dp_handle_automated_test;
238 link_srv->dp_set_test_pattern = dp_set_test_pattern;
239 link_srv->dp_set_preferred_link_settings =
240 dp_set_preferred_link_settings;
241 link_srv->dp_set_preferred_training_settings =
242 dp_set_preferred_training_settings;
243}
244
245/* link dp trace implements tracing interfaces for tracking major dp sequences
246 * including execution status and timestamps
247 */
248static void construct_link_service_dp_trace(struct link_service *link_srv)
249{
250 link_srv->dp_trace_is_initialized = dp_trace_is_initialized;
251 link_srv->dp_trace_set_is_logged_flag = dp_trace_set_is_logged_flag;
252 link_srv->dp_trace_is_logged = dp_trace_is_logged;
253 link_srv->dp_trace_get_lt_end_timestamp = dp_trace_get_lt_end_timestamp;
254 link_srv->dp_trace_get_lt_counts = dp_trace_get_lt_counts;
255 link_srv->dp_trace_get_link_loss_count = dp_trace_get_link_loss_count;
256 link_srv->dp_trace_set_edp_power_timestamp =
257 dp_trace_set_edp_power_timestamp;
258 link_srv->dp_trace_get_edp_poweron_timestamp =
259 dp_trace_get_edp_poweron_timestamp;
260 link_srv->dp_trace_get_edp_poweroff_timestamp =
261 dp_trace_get_edp_poweroff_timestamp;
262 link_srv->dp_trace_source_sequence = dp_trace_source_sequence;
263}
264
265static void construct_link_service(struct link_service *link_srv)
266{
267 /* All link service functions should fall under some sub categories.
268 * If a new function doesn't perfectly fall under an existing sub
269 * category, it must be that you are either adding a whole new aspect of
270 * responsibility to link service or something doesn't belong to link
271 * service. In that case please contact the arch owner to arrange a
272 * design review meeting.
273 */
274 construct_link_service_factory(link_srv);
275 construct_link_service_detection(link_srv);
276 construct_link_service_resource(link_srv);
277 construct_link_service_validation(link_srv);
278 construct_link_service_dpms(link_srv);
279 construct_link_service_ddc(link_srv);
280 construct_link_service_dp_capability(link_srv);
281 construct_link_service_dp_phy_or_dpia(link_srv);
282 construct_link_service_dp_irq_handler(link_srv);
283 construct_link_service_edp_panel_control(link_srv);
284 construct_link_service_dp_cts(link_srv);
285 construct_link_service_dp_trace(link_srv);
286}
287
288struct link_service *link_create_link_service(void)
289{
290 struct link_service *link_srv = kzalloc(size: sizeof(*link_srv), GFP_KERNEL);
291
292 if (link_srv == NULL)
293 goto fail;
294
295 construct_link_service(link_srv);
296
297 return link_srv;
298fail:
299 return NULL;
300}
301
302void link_destroy_link_service(struct link_service **link_srv)
303{
304 kfree(objp: *link_srv);
305 *link_srv = NULL;
306}
307
308static enum transmitter translate_encoder_to_transmitter(
309 struct graphics_object_id encoder)
310{
311 switch (encoder.id) {
312 case ENCODER_ID_INTERNAL_UNIPHY:
313 switch (encoder.enum_id) {
314 case ENUM_ID_1:
315 return TRANSMITTER_UNIPHY_A;
316 case ENUM_ID_2:
317 return TRANSMITTER_UNIPHY_B;
318 default:
319 return TRANSMITTER_UNKNOWN;
320 }
321 break;
322 case ENCODER_ID_INTERNAL_UNIPHY1:
323 switch (encoder.enum_id) {
324 case ENUM_ID_1:
325 return TRANSMITTER_UNIPHY_C;
326 case ENUM_ID_2:
327 return TRANSMITTER_UNIPHY_D;
328 default:
329 return TRANSMITTER_UNKNOWN;
330 }
331 break;
332 case ENCODER_ID_INTERNAL_UNIPHY2:
333 switch (encoder.enum_id) {
334 case ENUM_ID_1:
335 return TRANSMITTER_UNIPHY_E;
336 case ENUM_ID_2:
337 return TRANSMITTER_UNIPHY_F;
338 default:
339 return TRANSMITTER_UNKNOWN;
340 }
341 break;
342 case ENCODER_ID_INTERNAL_UNIPHY3:
343 switch (encoder.enum_id) {
344 case ENUM_ID_1:
345 return TRANSMITTER_UNIPHY_G;
346 default:
347 return TRANSMITTER_UNKNOWN;
348 }
349 break;
350 case ENCODER_ID_EXTERNAL_NUTMEG:
351 switch (encoder.enum_id) {
352 case ENUM_ID_1:
353 return TRANSMITTER_NUTMEG_CRT;
354 default:
355 return TRANSMITTER_UNKNOWN;
356 }
357 break;
358 case ENCODER_ID_EXTERNAL_TRAVIS:
359 switch (encoder.enum_id) {
360 case ENUM_ID_1:
361 return TRANSMITTER_TRAVIS_CRT;
362 case ENUM_ID_2:
363 return TRANSMITTER_TRAVIS_LCD;
364 default:
365 return TRANSMITTER_UNKNOWN;
366 }
367 break;
368 default:
369 return TRANSMITTER_UNKNOWN;
370 }
371}
372
373static void link_destruct(struct dc_link *link)
374{
375 int i;
376
377 if (link->hpd_gpio) {
378 dal_gpio_destroy_irq(ptr: &link->hpd_gpio);
379 link->hpd_gpio = NULL;
380 }
381
382 if (link->ddc)
383 link_destroy_ddc_service(ddc: &link->ddc);
384
385 if (link->panel_cntl)
386 link->panel_cntl->funcs->destroy(&link->panel_cntl);
387
388 if (link->link_enc) {
389 /* Update link encoder resource tracking variables. These are used for
390 * the dynamic assignment of link encoders to streams. Virtual links
391 * are not assigned encoder resources on creation.
392 */
393 if (link->link_id.id != CONNECTOR_ID_VIRTUAL) {
394 link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = NULL;
395 link->dc->res_pool->dig_link_enc_count--;
396 }
397 link->link_enc->funcs->destroy(&link->link_enc);
398 }
399
400 if (link->local_sink)
401 dc_sink_release(sink: link->local_sink);
402
403 for (i = 0; i < link->sink_count; ++i)
404 dc_sink_release(sink: link->remote_sinks[i]);
405}
406
407static enum channel_id get_ddc_line(struct dc_link *link)
408{
409 struct ddc *ddc;
410 enum channel_id channel;
411
412 channel = CHANNEL_ID_UNKNOWN;
413
414 ddc = get_ddc_pin(ddc_service: link->ddc);
415
416 if (ddc) {
417 switch (dal_ddc_get_line(ddc)) {
418 case GPIO_DDC_LINE_DDC1:
419 channel = CHANNEL_ID_DDC1;
420 break;
421 case GPIO_DDC_LINE_DDC2:
422 channel = CHANNEL_ID_DDC2;
423 break;
424 case GPIO_DDC_LINE_DDC3:
425 channel = CHANNEL_ID_DDC3;
426 break;
427 case GPIO_DDC_LINE_DDC4:
428 channel = CHANNEL_ID_DDC4;
429 break;
430 case GPIO_DDC_LINE_DDC5:
431 channel = CHANNEL_ID_DDC5;
432 break;
433 case GPIO_DDC_LINE_DDC6:
434 channel = CHANNEL_ID_DDC6;
435 break;
436 case GPIO_DDC_LINE_DDC_VGA:
437 channel = CHANNEL_ID_DDC_VGA;
438 break;
439 case GPIO_DDC_LINE_I2C_PAD:
440 channel = CHANNEL_ID_I2C_PAD;
441 break;
442 default:
443 BREAK_TO_DEBUGGER();
444 break;
445 }
446 }
447
448 return channel;
449}
450
451static bool construct_phy(struct dc_link *link,
452 const struct link_init_data *init_params)
453{
454 uint8_t i;
455 struct ddc_service_init_data ddc_service_init_data = { 0 };
456 struct dc_context *dc_ctx = init_params->ctx;
457 struct encoder_init_data enc_init_data = { 0 };
458 struct panel_cntl_init_data panel_cntl_init_data = { 0 };
459 struct integrated_info info = { 0 };
460 struct dc_bios *bios = init_params->dc->ctx->dc_bios;
461 const struct dc_vbios_funcs *bp_funcs = bios->funcs;
462 struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 };
463
464 DC_LOGGER_INIT(dc_ctx->logger);
465
466 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
467 link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
468 link->link_status.dpcd_caps = &link->dpcd_caps;
469
470 link->dc = init_params->dc;
471 link->ctx = dc_ctx;
472 link->link_index = init_params->link_index;
473
474 memset(&link->preferred_training_settings, 0,
475 sizeof(struct dc_link_training_overrides));
476 memset(&link->preferred_link_setting, 0,
477 sizeof(struct dc_link_settings));
478
479 link->link_id =
480 bios->funcs->get_connector_id(bios, init_params->connector_index);
481
482 link->ep_type = DISPLAY_ENDPOINT_PHY;
483
484 DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);
485
486 if (bios->funcs->get_disp_connector_caps_info) {
487 bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);
488 link->is_internal_display = disp_connect_caps_info.INTERNAL_DISPLAY;
489 DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);
490 }
491
492 if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
493 dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n",
494 __func__, init_params->connector_index,
495 link->link_id.type, OBJECT_TYPE_CONNECTOR);
496 goto create_fail;
497 }
498
499 if (link->dc->res_pool->funcs->link_init)
500 link->dc->res_pool->funcs->link_init(link);
501
502 link->hpd_gpio = link_get_hpd_gpio(dcb: link->ctx->dc_bios, link_id: link->link_id,
503 gpio_service: link->ctx->gpio_service);
504
505 if (link->hpd_gpio) {
506 dal_gpio_open(gpio: link->hpd_gpio, mode: GPIO_MODE_INTERRUPT);
507 dal_gpio_unlock_pin(gpio: link->hpd_gpio);
508 link->irq_source_hpd = dal_irq_get_source(irq: link->hpd_gpio);
509
510 DC_LOG_DC("BIOS object table - hpd_gpio id: %d", link->hpd_gpio->id);
511 DC_LOG_DC("BIOS object table - hpd_gpio en: %d", link->hpd_gpio->en);
512 }
513
514 switch (link->link_id.id) {
515 case CONNECTOR_ID_HDMI_TYPE_A:
516 link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
517
518 break;
519 case CONNECTOR_ID_SINGLE_LINK_DVID:
520 case CONNECTOR_ID_SINGLE_LINK_DVII:
521 link->connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
522 break;
523 case CONNECTOR_ID_DUAL_LINK_DVID:
524 case CONNECTOR_ID_DUAL_LINK_DVII:
525 link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
526 break;
527 case CONNECTOR_ID_DISPLAY_PORT:
528 case CONNECTOR_ID_USBC:
529 link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
530
531 if (link->hpd_gpio)
532 link->irq_source_hpd_rx =
533 dal_irq_get_rx_source(irq: link->hpd_gpio);
534
535 break;
536 case CONNECTOR_ID_EDP:
537 link->connector_signal = SIGNAL_TYPE_EDP;
538
539 if (link->hpd_gpio) {
540 if (!link->dc->config.allow_edp_hotplug_detection)
541 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
542
543 switch (link->dc->config.allow_edp_hotplug_detection) {
544 case HPD_EN_FOR_ALL_EDP:
545 link->irq_source_hpd_rx =
546 dal_irq_get_rx_source(irq: link->hpd_gpio);
547 break;
548 case HPD_EN_FOR_PRIMARY_EDP_ONLY:
549 if (link->link_index == 0)
550 link->irq_source_hpd_rx =
551 dal_irq_get_rx_source(irq: link->hpd_gpio);
552 else
553 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
554 break;
555 case HPD_EN_FOR_SECONDARY_EDP_ONLY:
556 if (link->link_index == 1)
557 link->irq_source_hpd_rx =
558 dal_irq_get_rx_source(irq: link->hpd_gpio);
559 else
560 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
561 break;
562 default:
563 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
564 break;
565 }
566 }
567
568 break;
569 case CONNECTOR_ID_LVDS:
570 link->connector_signal = SIGNAL_TYPE_LVDS;
571 break;
572 default:
573 DC_LOG_WARNING("Unsupported Connector type:%d!\n",
574 link->link_id.id);
575 goto create_fail;
576 }
577
578 LINK_INFO("Connector[%d] description: signal: %s\n",
579 init_params->connector_index,
580 signal_type_to_string(link->connector_signal));
581
582 ddc_service_init_data.ctx = link->ctx;
583 ddc_service_init_data.id = link->link_id;
584 ddc_service_init_data.link = link;
585 link->ddc = link_create_ddc_service(ddc_init_data: &ddc_service_init_data);
586
587 if (!link->ddc) {
588 DC_ERROR("Failed to create ddc_service!\n");
589 goto ddc_create_fail;
590 }
591
592 if (!link->ddc->ddc_pin) {
593 DC_ERROR("Failed to get I2C info for connector!\n");
594 goto ddc_create_fail;
595 }
596
597 link->ddc_hw_inst =
598 dal_ddc_get_line(ddc: get_ddc_pin(ddc_service: link->ddc));
599
600 enc_init_data.ctx = dc_ctx;
601 bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0,
602 &enc_init_data.encoder);
603 enc_init_data.connector = link->link_id;
604 enc_init_data.channel = get_ddc_line(link);
605 enc_init_data.hpd_source = get_hpd_line(link);
606
607 link->hpd_src = enc_init_data.hpd_source;
608
609 enc_init_data.transmitter =
610 translate_encoder_to_transmitter(encoder: enc_init_data.encoder);
611 link->link_enc =
612 link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);
613
614 DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
615 DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
616
617 if (!link->link_enc) {
618 DC_ERROR("Failed to create link encoder!\n");
619 goto link_enc_create_fail;
620 }
621
622 /* Update link encoder tracking variables. These are used for the dynamic
623 * assignment of link encoders to streams.
624 */
625 link->eng_id = link->link_enc->preferred_engine;
626 link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = link->link_enc;
627 link->dc->res_pool->dig_link_enc_count++;
628
629 link->link_enc_hw_inst = link->link_enc->transmitter;
630
631 if (link->dc->res_pool->funcs->panel_cntl_create &&
632 (link->link_id.id == CONNECTOR_ID_EDP ||
633 link->link_id.id == CONNECTOR_ID_LVDS)) {
634 panel_cntl_init_data.ctx = dc_ctx;
635 panel_cntl_init_data.inst = panel_cntl_init_data.ctx->dc_edp_id_count;
636 panel_cntl_init_data.eng_id = link->eng_id;
637 link->panel_cntl =
638 link->dc->res_pool->funcs->panel_cntl_create(
639 &panel_cntl_init_data);
640 panel_cntl_init_data.ctx->dc_edp_id_count++;
641
642 if (link->panel_cntl == NULL) {
643 DC_ERROR("Failed to create link panel_cntl!\n");
644 goto panel_cntl_create_fail;
645 }
646 }
647 for (i = 0; i < 4; i++) {
648 if (bp_funcs->get_device_tag(dc_ctx->dc_bios,
649 link->link_id, i,
650 &link->device_tag) != BP_RESULT_OK) {
651 DC_ERROR("Failed to find device tag!\n");
652 goto device_tag_fail;
653 }
654
655 /* Look for device tag that matches connector signal,
656 * CRT for rgb, LCD for other supported signal tyes
657 */
658 if (!bp_funcs->is_device_id_supported(dc_ctx->dc_bios,
659 link->device_tag.dev_id))
660 continue;
661 if (link->device_tag.dev_id.device_type == DEVICE_TYPE_CRT &&
662 link->connector_signal != SIGNAL_TYPE_RGB)
663 continue;
664 if (link->device_tag.dev_id.device_type == DEVICE_TYPE_LCD &&
665 link->connector_signal == SIGNAL_TYPE_RGB)
666 continue;
667
668 DC_LOG_DC("BIOS object table - device_tag.acpi_device: %d", link->device_tag.acpi_device);
669 DC_LOG_DC("BIOS object table - device_tag.dev_id.device_type: %d", link->device_tag.dev_id.device_type);
670 DC_LOG_DC("BIOS object table - device_tag.dev_id.enum_id: %d", link->device_tag.dev_id.enum_id);
671 break;
672 }
673
674 if (bios->integrated_info)
675 info = *bios->integrated_info;
676
677 /* Look for channel mapping corresponding to connector and device tag */
678 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; i++) {
679 struct external_display_path *path =
680 &info.ext_disp_conn_info.path[i];
681
682 if (path->device_connector_id.enum_id == link->link_id.enum_id &&
683 path->device_connector_id.id == link->link_id.id &&
684 path->device_connector_id.type == link->link_id.type) {
685 if (link->device_tag.acpi_device != 0 &&
686 path->device_acpi_enum == link->device_tag.acpi_device) {
687 link->ddi_channel_mapping = path->channel_mapping;
688 link->chip_caps = path->caps;
689 DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
690 DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
691 } else if (path->device_tag ==
692 link->device_tag.dev_id.raw_device_tag) {
693 link->ddi_channel_mapping = path->channel_mapping;
694 link->chip_caps = path->caps;
695 DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
696 DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
697 }
698
699 if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) {
700 link->bios_forced_drive_settings.VOLTAGE_SWING =
701 (info.ext_disp_conn_info.fixdpvoltageswing & 0x3);
702 link->bios_forced_drive_settings.PRE_EMPHASIS =
703 ((info.ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3);
704 }
705
706 break;
707 }
708 }
709
710 if (bios->funcs->get_atom_dc_golden_table)
711 bios->funcs->get_atom_dc_golden_table(bios);
712
713 /*
714 * TODO check if GPIO programmed correctly
715 *
716 * If GPIO isn't programmed correctly HPD might not rise or drain
717 * fast enough, leading to bounces.
718 */
719 program_hpd_filter(link);
720
721 link->psr_settings.psr_vtotal_control_support = false;
722 link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
723
724 DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
725 return true;
726device_tag_fail:
727 link->link_enc->funcs->destroy(&link->link_enc);
728link_enc_create_fail:
729 if (link->panel_cntl != NULL)
730 link->panel_cntl->funcs->destroy(&link->panel_cntl);
731panel_cntl_create_fail:
732 link_destroy_ddc_service(ddc: &link->ddc);
733ddc_create_fail:
734create_fail:
735
736 if (link->hpd_gpio) {
737 dal_gpio_destroy_irq(ptr: &link->hpd_gpio);
738 link->hpd_gpio = NULL;
739 }
740
741 DC_LOG_DC("BIOS object table - %s failed.\n", __func__);
742 return false;
743}
744
745static bool construct_dpia(struct dc_link *link,
746 const struct link_init_data *init_params)
747{
748 struct ddc_service_init_data ddc_service_init_data = { 0 };
749 struct dc_context *dc_ctx = init_params->ctx;
750
751 DC_LOGGER_INIT(dc_ctx->logger);
752
753 /* Initialized irq source for hpd and hpd rx */
754 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
755 link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
756 link->link_status.dpcd_caps = &link->dpcd_caps;
757
758 link->dc = init_params->dc;
759 link->ctx = dc_ctx;
760 link->link_index = init_params->link_index;
761
762 memset(&link->preferred_training_settings, 0,
763 sizeof(struct dc_link_training_overrides));
764 memset(&link->preferred_link_setting, 0,
765 sizeof(struct dc_link_settings));
766
767 /* Dummy Init for linkid */
768 link->link_id.type = OBJECT_TYPE_CONNECTOR;
769 link->link_id.id = CONNECTOR_ID_DISPLAY_PORT;
770 link->link_id.enum_id = ENUM_ID_1 + init_params->connector_index;
771 link->is_internal_display = false;
772 link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
773 LINK_INFO("Connector[%d] description:signal %d\n",
774 init_params->connector_index,
775 link->connector_signal);
776
777 link->ep_type = DISPLAY_ENDPOINT_USB4_DPIA;
778 link->is_dig_mapping_flexible = true;
779
780 /* TODO: Initialize link : funcs->link_init */
781
782 ddc_service_init_data.ctx = link->ctx;
783 ddc_service_init_data.id = link->link_id;
784 ddc_service_init_data.link = link;
785 /* Set indicator for dpia link so that ddc wont be created */
786 ddc_service_init_data.is_dpia_link = true;
787
788 link->ddc = link_create_ddc_service(ddc_init_data: &ddc_service_init_data);
789 if (!link->ddc) {
790 DC_ERROR("Failed to create ddc_service!\n");
791 goto ddc_create_fail;
792 }
793
794 /* Set dpia port index : 0 to number of dpia ports */
795 link->ddc_hw_inst = init_params->connector_index;
796
797 // Assign Dpia preferred eng_id
798 if (link->dc->res_pool->funcs->get_preferred_eng_id_dpia)
799 link->dpia_preferred_eng_id = link->dc->res_pool->funcs->get_preferred_eng_id_dpia(link->ddc_hw_inst);
800
801 /* TODO: Create link encoder */
802
803 link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
804
805 /* Some docks seem to NAK I2C writes to segment pointer with mot=0. */
806 link->wa_flags.dp_mot_reset_segment = true;
807
808 return true;
809
810ddc_create_fail:
811 return false;
812}
813
814static bool link_construct(struct dc_link *link,
815 const struct link_init_data *init_params)
816{
817 /* Handle dpia case */
818 if (init_params->is_dpia_link == true)
819 return construct_dpia(link, init_params);
820 else
821 return construct_phy(link, init_params);
822}
823
824struct dc_link *link_create(const struct link_init_data *init_params)
825{
826 struct dc_link *link =
827 kzalloc(size: sizeof(*link), GFP_KERNEL);
828
829 if (NULL == link)
830 goto alloc_fail;
831
832 if (false == link_construct(link, init_params))
833 goto construct_fail;
834
835 return link;
836
837construct_fail:
838 kfree(objp: link);
839
840alloc_fail:
841 return NULL;
842}
843
844void link_destroy(struct dc_link **link)
845{
846 link_destruct(link: *link);
847 kfree(objp: *link);
848 *link = NULL;
849}
850

source code of linux/drivers/gpu/drm/amd/display/dc/link/link_factory.c