154618888SWenjing Liu /*
254618888SWenjing Liu  * Copyright 2023 Advanced Micro Devices, Inc.
354618888SWenjing Liu  *
454618888SWenjing Liu  * Permission is hereby granted, free of charge, to any person obtaining a
554618888SWenjing Liu  * copy of this software and associated documentation files (the "Software"),
654618888SWenjing Liu  * to deal in the Software without restriction, including without limitation
754618888SWenjing Liu  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
854618888SWenjing Liu  * and/or sell copies of the Software, and to permit persons to whom the
954618888SWenjing Liu  * Software is furnished to do so, subject to the following conditions:
1054618888SWenjing Liu  *
1154618888SWenjing Liu  * The above copyright notice and this permission notice shall be included in
1254618888SWenjing Liu  * all copies or substantial portions of the Software.
1354618888SWenjing Liu  *
1454618888SWenjing Liu  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1554618888SWenjing Liu  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1654618888SWenjing Liu  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1754618888SWenjing Liu  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1854618888SWenjing Liu  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1954618888SWenjing Liu  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2054618888SWenjing Liu  * OTHER DEALINGS IN THE SOFTWARE.
2154618888SWenjing Liu  *
2254618888SWenjing Liu  * Authors: AMD
2354618888SWenjing Liu  *
2454618888SWenjing Liu  */
2554618888SWenjing Liu 
2654618888SWenjing Liu /* FILE POLICY AND INTENDED USAGE:
2754618888SWenjing Liu  * This file owns the creation/destruction of link structure.
2854618888SWenjing Liu  */
2954618888SWenjing Liu #include "link_factory.h"
3076f5dc40SWenjing Liu #include "link_detection.h"
3198ce7d32SWenjing Liu #include "link_resource.h"
3298ce7d32SWenjing Liu #include "link_validation.h"
3398ce7d32SWenjing Liu #include "link_dpms.h"
3436516001SWenjing Liu #include "accessories/link_dp_cts.h"
3536516001SWenjing Liu #include "accessories/link_dp_trace.h"
3636516001SWenjing Liu #include "accessories/link_fpga.h"
3754618888SWenjing Liu #include "protocols/link_ddc.h"
38202a3816SWenjing Liu #include "protocols/link_dp_capability.h"
39202a3816SWenjing Liu #include "protocols/link_dp_dpia_bw.h"
40202a3816SWenjing Liu #include "protocols/link_dp_dpia.h"
41202a3816SWenjing Liu #include "protocols/link_dp_irq_handler.h"
42202a3816SWenjing Liu #include "protocols/link_dp_phy.h"
43202a3816SWenjing Liu #include "protocols/link_dp_training.h"
4454618888SWenjing Liu #include "protocols/link_edp_panel_control.h"
4554618888SWenjing Liu #include "protocols/link_hpd.h"
4654618888SWenjing Liu #include "gpio_service_interface.h"
4754618888SWenjing Liu #include "atomfirmware.h"
4854618888SWenjing Liu 
4954618888SWenjing Liu #define DC_LOGGER_INIT(logger)
5054618888SWenjing Liu 
5154618888SWenjing Liu #define LINK_INFO(...) \
5254618888SWenjing Liu 	DC_LOG_HW_HOTPLUG(  \
5354618888SWenjing Liu 		__VA_ARGS__)
5454618888SWenjing Liu 
5598ce7d32SWenjing Liu /* link factory owns the creation/destruction of link structures. */
construct_link_service_factory(struct link_service * link_srv)5698ce7d32SWenjing Liu static void construct_link_service_factory(struct link_service *link_srv)
5798ce7d32SWenjing Liu {
58202a3816SWenjing Liu 
5998ce7d32SWenjing Liu 	link_srv->create_link = link_create;
6098ce7d32SWenjing Liu 	link_srv->destroy_link = link_destroy;
6198ce7d32SWenjing Liu }
62202a3816SWenjing Liu 
6398ce7d32SWenjing Liu /* link_detection manages link detection states and receiver states by using
6498ce7d32SWenjing Liu  * various link protocols. It also provides helper functions to interpret
6598ce7d32SWenjing Liu  * certain capabilities or status based on the states it manages or retrieve
6698ce7d32SWenjing Liu  * them directly from connected receivers.
6798ce7d32SWenjing Liu  */
construct_link_service_detection(struct link_service * link_srv)6898ce7d32SWenjing Liu static void construct_link_service_detection(struct link_service *link_srv)
6998ce7d32SWenjing Liu {
7098ce7d32SWenjing Liu 	link_srv->detect_link = link_detect;
7198ce7d32SWenjing Liu 	link_srv->detect_connection_type = link_detect_connection_type;
7298ce7d32SWenjing Liu 	link_srv->add_remote_sink = link_add_remote_sink;
7398ce7d32SWenjing Liu 	link_srv->remove_remote_sink = link_remove_remote_sink;
7498ce7d32SWenjing Liu 	link_srv->get_hpd_state = link_get_hpd_state;
7598ce7d32SWenjing Liu 	link_srv->get_hpd_gpio = link_get_hpd_gpio;
7698ce7d32SWenjing Liu 	link_srv->enable_hpd = link_enable_hpd;
7798ce7d32SWenjing Liu 	link_srv->disable_hpd = link_disable_hpd;
7898ce7d32SWenjing Liu 	link_srv->enable_hpd_filter = link_enable_hpd_filter;
7998ce7d32SWenjing Liu 	link_srv->reset_cur_dp_mst_topology = link_reset_cur_dp_mst_topology;
8098ce7d32SWenjing Liu 	link_srv->get_status = link_get_status;
8198ce7d32SWenjing Liu 	link_srv->is_hdcp1x_supported = link_is_hdcp14;
8298ce7d32SWenjing Liu 	link_srv->is_hdcp2x_supported = link_is_hdcp22;
8398ce7d32SWenjing Liu 	link_srv->clear_dprx_states = link_clear_dprx_states;
8498ce7d32SWenjing Liu }
85202a3816SWenjing Liu 
8698ce7d32SWenjing Liu /* link resource implements accessors to link resource. */
construct_link_service_resource(struct link_service * link_srv)8798ce7d32SWenjing Liu static void construct_link_service_resource(struct link_service *link_srv)
8898ce7d32SWenjing Liu {
8998ce7d32SWenjing Liu 	link_srv->get_cur_res_map = link_get_cur_res_map;
9098ce7d32SWenjing Liu 	link_srv->restore_res_map = link_restore_res_map;
9198ce7d32SWenjing Liu 	link_srv->get_cur_link_res = link_get_cur_link_res;
9298ce7d32SWenjing Liu }
93202a3816SWenjing Liu 
9498ce7d32SWenjing Liu /* link validation owns timing validation against various link limitations. (ex.
9598ce7d32SWenjing Liu  * link bandwidth, receiver capability or our hardware capability) It also
9698ce7d32SWenjing Liu  * provides helper functions exposing bandwidth formulas used in validation.
9798ce7d32SWenjing Liu  */
construct_link_service_validation(struct link_service * link_srv)9898ce7d32SWenjing Liu static void construct_link_service_validation(struct link_service *link_srv)
9998ce7d32SWenjing Liu {
10098ce7d32SWenjing Liu 	link_srv->validate_mode_timing = link_validate_mode_timing;
10198ce7d32SWenjing Liu 	link_srv->dp_link_bandwidth_kbps = dp_link_bandwidth_kbps;
102a8b53760SMustapha Ghaddar 	link_srv->validate_dpia_bandwidth = link_validate_dpia_bandwidth;
10398ce7d32SWenjing Liu }
104202a3816SWenjing Liu 
10598ce7d32SWenjing Liu /* link dpms owns the programming sequence of stream's dpms state associated
10698ce7d32SWenjing Liu  * with the link and link's enable/disable sequences as result of the stream's
10798ce7d32SWenjing Liu  * dpms state change.
10898ce7d32SWenjing Liu  */
construct_link_service_dpms(struct link_service * link_srv)10998ce7d32SWenjing Liu static void construct_link_service_dpms(struct link_service *link_srv)
11098ce7d32SWenjing Liu {
11198ce7d32SWenjing Liu 	link_srv->set_dpms_on = link_set_dpms_on;
11298ce7d32SWenjing Liu 	link_srv->set_dpms_off = link_set_dpms_off;
11398ce7d32SWenjing Liu 	link_srv->resume = link_resume;
11498ce7d32SWenjing Liu 	link_srv->blank_all_dp_displays = link_blank_all_dp_displays;
11598ce7d32SWenjing Liu 	link_srv->blank_all_edp_displays = link_blank_all_edp_displays;
11698ce7d32SWenjing Liu 	link_srv->blank_dp_stream = link_blank_dp_stream;
11798ce7d32SWenjing Liu 	link_srv->increase_mst_payload = link_increase_mst_payload;
11898ce7d32SWenjing Liu 	link_srv->reduce_mst_payload = link_reduce_mst_payload;
11998ce7d32SWenjing Liu 	link_srv->set_dsc_on_stream = link_set_dsc_on_stream;
12098ce7d32SWenjing Liu 	link_srv->set_dsc_enable = link_set_dsc_enable;
12198ce7d32SWenjing Liu 	link_srv->update_dsc_config = link_update_dsc_config;
12298ce7d32SWenjing Liu }
123202a3816SWenjing Liu 
12498ce7d32SWenjing Liu /* link ddc implements generic display communication protocols such as i2c, aux
12598ce7d32SWenjing Liu  * and scdc. It should not contain any specific applications of these
12698ce7d32SWenjing Liu  * protocols such as display capability query, detection, or handshaking such as
12798ce7d32SWenjing Liu  * link training.
12898ce7d32SWenjing Liu  */
construct_link_service_ddc(struct link_service * link_srv)12998ce7d32SWenjing Liu static void construct_link_service_ddc(struct link_service *link_srv)
13098ce7d32SWenjing Liu {
13198ce7d32SWenjing Liu 	link_srv->create_ddc_service = link_create_ddc_service;
13298ce7d32SWenjing Liu 	link_srv->destroy_ddc_service = link_destroy_ddc_service;
13398ce7d32SWenjing Liu 	link_srv->query_ddc_data = link_query_ddc_data;
13498ce7d32SWenjing Liu 	link_srv->aux_transfer_raw = link_aux_transfer_raw;
135ad5594adSMichael Strauss 	link_srv->configure_fixed_vs_pe_retimer = link_configure_fixed_vs_pe_retimer;
13698ce7d32SWenjing Liu 	link_srv->aux_transfer_with_retries_no_mutex =
13798ce7d32SWenjing Liu 			link_aux_transfer_with_retries_no_mutex;
13898ce7d32SWenjing Liu 	link_srv->is_in_aux_transaction_mode = link_is_in_aux_transaction_mode;
13998ce7d32SWenjing Liu 	link_srv->get_aux_defer_delay = link_get_aux_defer_delay;
14098ce7d32SWenjing Liu }
14136516001SWenjing Liu 
14298ce7d32SWenjing Liu /* link dp capability implements dp specific link capability retrieval sequence.
14398ce7d32SWenjing Liu  * It is responsible for retrieving, parsing, overriding, deciding capability
14498ce7d32SWenjing Liu  * obtained from dp link. Link capability consists of encoders, DPRXs, cables,
14598ce7d32SWenjing Liu  * retimers, usb and all other possible backend capabilities.
14698ce7d32SWenjing Liu  */
construct_link_service_dp_capability(struct link_service * link_srv)14798ce7d32SWenjing Liu static void construct_link_service_dp_capability(struct link_service *link_srv)
14898ce7d32SWenjing Liu {
14998ce7d32SWenjing Liu 	link_srv->dp_is_sink_present = dp_is_sink_present;
15098ce7d32SWenjing Liu 	link_srv->dp_is_fec_supported = dp_is_fec_supported;
15198ce7d32SWenjing Liu 	link_srv->dp_is_128b_132b_signal = dp_is_128b_132b_signal;
15298ce7d32SWenjing Liu 	link_srv->dp_get_max_link_enc_cap = dp_get_max_link_enc_cap;
15398ce7d32SWenjing Liu 	link_srv->dp_get_verified_link_cap = dp_get_verified_link_cap;
15498ce7d32SWenjing Liu 	link_srv->dp_get_encoding_format = link_dp_get_encoding_format;
15598ce7d32SWenjing Liu 	link_srv->dp_should_enable_fec = dp_should_enable_fec;
15698ce7d32SWenjing Liu 	link_srv->dp_decide_link_settings = link_decide_link_settings;
15798ce7d32SWenjing Liu 	link_srv->mst_decide_link_encoding_format =
15898ce7d32SWenjing Liu 			mst_decide_link_encoding_format;
15998ce7d32SWenjing Liu 	link_srv->edp_decide_link_settings = edp_decide_link_settings;
16098ce7d32SWenjing Liu 	link_srv->bw_kbps_from_raw_frl_link_rate_data =
16198ce7d32SWenjing Liu 			link_bw_kbps_from_raw_frl_link_rate_data;
16298ce7d32SWenjing Liu 	link_srv->dp_overwrite_extended_receiver_cap =
16398ce7d32SWenjing Liu 			dp_overwrite_extended_receiver_cap;
16498ce7d32SWenjing Liu 	link_srv->dp_decide_lttpr_mode = dp_decide_lttpr_mode;
16598ce7d32SWenjing Liu }
16698ce7d32SWenjing Liu 
16798ce7d32SWenjing Liu /* link dp phy/dpia implements basic dp phy/dpia functionality such as
16898ce7d32SWenjing Liu  * enable/disable output and set lane/drive settings. It is responsible for
16998ce7d32SWenjing Liu  * maintaining and update software state representing current phy/dpia status
17098ce7d32SWenjing Liu  * such as current link settings.
17198ce7d32SWenjing Liu  */
construct_link_service_dp_phy_or_dpia(struct link_service * link_srv)17298ce7d32SWenjing Liu static void construct_link_service_dp_phy_or_dpia(struct link_service *link_srv)
17398ce7d32SWenjing Liu {
17498ce7d32SWenjing Liu 	link_srv->dpia_handle_usb4_bandwidth_allocation_for_link =
17598ce7d32SWenjing Liu 			dpia_handle_usb4_bandwidth_allocation_for_link;
17698ce7d32SWenjing Liu 	link_srv->dpia_handle_bw_alloc_response = dpia_handle_bw_alloc_response;
17798ce7d32SWenjing Liu 	link_srv->dp_set_drive_settings = dp_set_drive_settings;
17898ce7d32SWenjing Liu 	link_srv->dpcd_write_rx_power_ctrl = dpcd_write_rx_power_ctrl;
17998ce7d32SWenjing Liu }
18098ce7d32SWenjing Liu 
18198ce7d32SWenjing Liu /* link dp irq handler implements DP HPD short pulse handling sequence according
18298ce7d32SWenjing Liu  * to DP specifications
18398ce7d32SWenjing Liu  */
construct_link_service_dp_irq_handler(struct link_service * link_srv)18498ce7d32SWenjing Liu static void construct_link_service_dp_irq_handler(struct link_service *link_srv)
18598ce7d32SWenjing Liu {
18698ce7d32SWenjing Liu 	link_srv->dp_parse_link_loss_status = dp_parse_link_loss_status;
18798ce7d32SWenjing Liu 	link_srv->dp_should_allow_hpd_rx_irq = dp_should_allow_hpd_rx_irq;
18898ce7d32SWenjing Liu 	link_srv->dp_handle_link_loss = dp_handle_link_loss;
18998ce7d32SWenjing Liu 	link_srv->dp_read_hpd_rx_irq_data = dp_read_hpd_rx_irq_data;
19098ce7d32SWenjing Liu 	link_srv->dp_handle_hpd_rx_irq = dp_handle_hpd_rx_irq;
19198ce7d32SWenjing Liu }
19298ce7d32SWenjing Liu 
19398ce7d32SWenjing Liu /* link edp panel control implements retrieval and configuration of eDP panel
19498ce7d32SWenjing Liu  * features such as PSR and ABM and it also manages specs defined eDP panel
19598ce7d32SWenjing Liu  * power sequences.
19698ce7d32SWenjing Liu  */
construct_link_service_edp_panel_control(struct link_service * link_srv)19798ce7d32SWenjing Liu static void construct_link_service_edp_panel_control(struct link_service *link_srv)
19898ce7d32SWenjing Liu {
19998ce7d32SWenjing Liu 	link_srv->edp_panel_backlight_power_on = edp_panel_backlight_power_on;
20098ce7d32SWenjing Liu 	link_srv->edp_get_backlight_level = edp_get_backlight_level;
20198ce7d32SWenjing Liu 	link_srv->edp_get_backlight_level_nits = edp_get_backlight_level_nits;
20298ce7d32SWenjing Liu 	link_srv->edp_set_backlight_level = edp_set_backlight_level;
20398ce7d32SWenjing Liu 	link_srv->edp_set_backlight_level_nits = edp_set_backlight_level_nits;
20498ce7d32SWenjing Liu 	link_srv->edp_get_target_backlight_pwm = edp_get_target_backlight_pwm;
20598ce7d32SWenjing Liu 	link_srv->edp_get_psr_state = edp_get_psr_state;
20698ce7d32SWenjing Liu 	link_srv->edp_set_psr_allow_active = edp_set_psr_allow_active;
20798ce7d32SWenjing Liu 	link_srv->edp_setup_psr = edp_setup_psr;
20898ce7d32SWenjing Liu 	link_srv->edp_set_sink_vtotal_in_psr_active =
20998ce7d32SWenjing Liu 			edp_set_sink_vtotal_in_psr_active;
21098ce7d32SWenjing Liu 	link_srv->edp_get_psr_residency = edp_get_psr_residency;
211c7ddc0a8SBhawanpreet Lakha 
212c7ddc0a8SBhawanpreet Lakha 	link_srv->edp_get_replay_state = edp_get_replay_state;
213c7ddc0a8SBhawanpreet Lakha 	link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active;
214c7ddc0a8SBhawanpreet Lakha 	link_srv->edp_setup_replay = edp_setup_replay;
215c7ddc0a8SBhawanpreet Lakha 	link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
216c7ddc0a8SBhawanpreet Lakha 	link_srv->edp_replay_residency = edp_replay_residency;
217c7ddc0a8SBhawanpreet Lakha 
21898ce7d32SWenjing Liu 	link_srv->edp_wait_for_t12 = edp_wait_for_t12;
21998ce7d32SWenjing Liu 	link_srv->edp_is_ilr_optimization_required =
22098ce7d32SWenjing Liu 			edp_is_ilr_optimization_required;
22198ce7d32SWenjing Liu 	link_srv->edp_backlight_enable_aux = edp_backlight_enable_aux;
22298ce7d32SWenjing Liu 	link_srv->edp_add_delay_for_T9 = edp_add_delay_for_T9;
22398ce7d32SWenjing Liu 	link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9;
22498ce7d32SWenjing Liu 	link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7;
22598ce7d32SWenjing Liu 	link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable;
226a8728dbbSIan Chen 	link_srv->edp_set_panel_power = edp_set_panel_power;
22798ce7d32SWenjing Liu }
22898ce7d32SWenjing Liu 
22998ce7d32SWenjing Liu /* link dp cts implements dp compliance test automation protocols and manual
23098ce7d32SWenjing Liu  * testing interfaces for debugging and certification purpose.
23198ce7d32SWenjing Liu  */
construct_link_service_dp_cts(struct link_service * link_srv)23298ce7d32SWenjing Liu static void construct_link_service_dp_cts(struct link_service *link_srv)
23398ce7d32SWenjing Liu {
23498ce7d32SWenjing Liu 	link_srv->dp_handle_automated_test = dp_handle_automated_test;
23598ce7d32SWenjing Liu 	link_srv->dp_set_test_pattern = dp_set_test_pattern;
23698ce7d32SWenjing Liu 	link_srv->dp_set_preferred_link_settings =
23798ce7d32SWenjing Liu 			dp_set_preferred_link_settings;
23898ce7d32SWenjing Liu 	link_srv->dp_set_preferred_training_settings =
23998ce7d32SWenjing Liu 			dp_set_preferred_training_settings;
24098ce7d32SWenjing Liu }
24198ce7d32SWenjing Liu 
24298ce7d32SWenjing Liu /* link dp trace implements tracing interfaces for tracking major dp sequences
24398ce7d32SWenjing Liu  * including execution status and timestamps
24498ce7d32SWenjing Liu  */
construct_link_service_dp_trace(struct link_service * link_srv)24598ce7d32SWenjing Liu static void construct_link_service_dp_trace(struct link_service *link_srv)
24698ce7d32SWenjing Liu {
24798ce7d32SWenjing Liu 	link_srv->dp_trace_is_initialized = dp_trace_is_initialized;
24898ce7d32SWenjing Liu 	link_srv->dp_trace_set_is_logged_flag = dp_trace_set_is_logged_flag;
24998ce7d32SWenjing Liu 	link_srv->dp_trace_is_logged = dp_trace_is_logged;
25098ce7d32SWenjing Liu 	link_srv->dp_trace_get_lt_end_timestamp = dp_trace_get_lt_end_timestamp;
25198ce7d32SWenjing Liu 	link_srv->dp_trace_get_lt_counts = dp_trace_get_lt_counts;
25298ce7d32SWenjing Liu 	link_srv->dp_trace_get_link_loss_count = dp_trace_get_link_loss_count;
25398ce7d32SWenjing Liu 	link_srv->dp_trace_set_edp_power_timestamp =
25498ce7d32SWenjing Liu 			dp_trace_set_edp_power_timestamp;
25598ce7d32SWenjing Liu 	link_srv->dp_trace_get_edp_poweron_timestamp =
25698ce7d32SWenjing Liu 			dp_trace_get_edp_poweron_timestamp;
25798ce7d32SWenjing Liu 	link_srv->dp_trace_get_edp_poweroff_timestamp =
25898ce7d32SWenjing Liu 			dp_trace_get_edp_poweroff_timestamp;
25998ce7d32SWenjing Liu 	link_srv->dp_trace_source_sequence = dp_trace_source_sequence;
26098ce7d32SWenjing Liu }
26198ce7d32SWenjing Liu 
construct_link_service(struct link_service * link_srv)26298ce7d32SWenjing Liu static void construct_link_service(struct link_service *link_srv)
26398ce7d32SWenjing Liu {
26498ce7d32SWenjing Liu 	/* All link service functions should fall under some sub categories.
26598ce7d32SWenjing Liu 	 * If a new function doesn't perfectly fall under an existing sub
26698ce7d32SWenjing Liu 	 * category, it must be that you are either adding a whole new aspect of
26798ce7d32SWenjing Liu 	 * responsibility to link service or something doesn't belong to link
26898ce7d32SWenjing Liu 	 * service. In that case please contact the arch owner to arrange a
26998ce7d32SWenjing Liu 	 * design review meeting.
27098ce7d32SWenjing Liu 	 */
27198ce7d32SWenjing Liu 	construct_link_service_factory(link_srv);
27298ce7d32SWenjing Liu 	construct_link_service_detection(link_srv);
27398ce7d32SWenjing Liu 	construct_link_service_resource(link_srv);
27498ce7d32SWenjing Liu 	construct_link_service_validation(link_srv);
27598ce7d32SWenjing Liu 	construct_link_service_dpms(link_srv);
27698ce7d32SWenjing Liu 	construct_link_service_ddc(link_srv);
27798ce7d32SWenjing Liu 	construct_link_service_dp_capability(link_srv);
27898ce7d32SWenjing Liu 	construct_link_service_dp_phy_or_dpia(link_srv);
27998ce7d32SWenjing Liu 	construct_link_service_dp_irq_handler(link_srv);
28098ce7d32SWenjing Liu 	construct_link_service_edp_panel_control(link_srv);
28198ce7d32SWenjing Liu 	construct_link_service_dp_cts(link_srv);
28298ce7d32SWenjing Liu 	construct_link_service_dp_trace(link_srv);
28398ce7d32SWenjing Liu }
28498ce7d32SWenjing Liu 
link_create_link_service(void)28598ce7d32SWenjing Liu struct link_service *link_create_link_service(void)
28698ce7d32SWenjing Liu {
28798ce7d32SWenjing Liu 	struct link_service *link_srv = kzalloc(sizeof(*link_srv), GFP_KERNEL);
28898ce7d32SWenjing Liu 
28998ce7d32SWenjing Liu 	if (link_srv == NULL)
29098ce7d32SWenjing Liu 		goto fail;
29198ce7d32SWenjing Liu 
29298ce7d32SWenjing Liu 	construct_link_service(link_srv);
29398ce7d32SWenjing Liu 
29498ce7d32SWenjing Liu 	return link_srv;
29598ce7d32SWenjing Liu fail:
29698ce7d32SWenjing Liu 	return NULL;
29798ce7d32SWenjing Liu }
29898ce7d32SWenjing Liu 
link_destroy_link_service(struct link_service ** link_srv)29998ce7d32SWenjing Liu void link_destroy_link_service(struct link_service **link_srv)
30098ce7d32SWenjing Liu {
30198ce7d32SWenjing Liu 	kfree(*link_srv);
30298ce7d32SWenjing Liu 	*link_srv = NULL;
30398ce7d32SWenjing Liu }
30498ce7d32SWenjing Liu 
translate_encoder_to_transmitter(struct graphics_object_id encoder)30598ce7d32SWenjing Liu static enum transmitter translate_encoder_to_transmitter(
30698ce7d32SWenjing Liu 		struct graphics_object_id encoder)
30754618888SWenjing Liu {
30854618888SWenjing Liu 	switch (encoder.id) {
30954618888SWenjing Liu 	case ENCODER_ID_INTERNAL_UNIPHY:
31054618888SWenjing Liu 		switch (encoder.enum_id) {
31154618888SWenjing Liu 		case ENUM_ID_1:
31254618888SWenjing Liu 			return TRANSMITTER_UNIPHY_A;
31354618888SWenjing Liu 		case ENUM_ID_2:
31454618888SWenjing Liu 			return TRANSMITTER_UNIPHY_B;
31554618888SWenjing Liu 		default:
31654618888SWenjing Liu 			return TRANSMITTER_UNKNOWN;
31754618888SWenjing Liu 		}
31854618888SWenjing Liu 	break;
31954618888SWenjing Liu 	case ENCODER_ID_INTERNAL_UNIPHY1:
32054618888SWenjing Liu 		switch (encoder.enum_id) {
32154618888SWenjing Liu 		case ENUM_ID_1:
32254618888SWenjing Liu 			return TRANSMITTER_UNIPHY_C;
32354618888SWenjing Liu 		case ENUM_ID_2:
32454618888SWenjing Liu 			return TRANSMITTER_UNIPHY_D;
32554618888SWenjing Liu 		default:
32654618888SWenjing Liu 			return TRANSMITTER_UNKNOWN;
32754618888SWenjing Liu 		}
32854618888SWenjing Liu 	break;
32954618888SWenjing Liu 	case ENCODER_ID_INTERNAL_UNIPHY2:
33054618888SWenjing Liu 		switch (encoder.enum_id) {
33154618888SWenjing Liu 		case ENUM_ID_1:
33254618888SWenjing Liu 			return TRANSMITTER_UNIPHY_E;
33354618888SWenjing Liu 		case ENUM_ID_2:
33454618888SWenjing Liu 			return TRANSMITTER_UNIPHY_F;
33554618888SWenjing Liu 		default:
33654618888SWenjing Liu 			return TRANSMITTER_UNKNOWN;
33754618888SWenjing Liu 		}
33854618888SWenjing Liu 	break;
33954618888SWenjing Liu 	case ENCODER_ID_INTERNAL_UNIPHY3:
34054618888SWenjing Liu 		switch (encoder.enum_id) {
34154618888SWenjing Liu 		case ENUM_ID_1:
34254618888SWenjing Liu 			return TRANSMITTER_UNIPHY_G;
34354618888SWenjing Liu 		default:
34454618888SWenjing Liu 			return TRANSMITTER_UNKNOWN;
34554618888SWenjing Liu 		}
34654618888SWenjing Liu 	break;
34754618888SWenjing Liu 	case ENCODER_ID_EXTERNAL_NUTMEG:
34854618888SWenjing Liu 		switch (encoder.enum_id) {
34954618888SWenjing Liu 		case ENUM_ID_1:
35054618888SWenjing Liu 			return TRANSMITTER_NUTMEG_CRT;
35154618888SWenjing Liu 		default:
35254618888SWenjing Liu 			return TRANSMITTER_UNKNOWN;
35354618888SWenjing Liu 		}
35454618888SWenjing Liu 	break;
35554618888SWenjing Liu 	case ENCODER_ID_EXTERNAL_TRAVIS:
35654618888SWenjing Liu 		switch (encoder.enum_id) {
35754618888SWenjing Liu 		case ENUM_ID_1:
35854618888SWenjing Liu 			return TRANSMITTER_TRAVIS_CRT;
35954618888SWenjing Liu 		case ENUM_ID_2:
36054618888SWenjing Liu 			return TRANSMITTER_TRAVIS_LCD;
36154618888SWenjing Liu 		default:
36254618888SWenjing Liu 			return TRANSMITTER_UNKNOWN;
36354618888SWenjing Liu 		}
36454618888SWenjing Liu 	break;
36554618888SWenjing Liu 	default:
36654618888SWenjing Liu 		return TRANSMITTER_UNKNOWN;
36754618888SWenjing Liu 	}
36854618888SWenjing Liu }
36954618888SWenjing Liu 
translate_dig_inst_to_pwrseq_inst(struct dc_link * link)370*71be0f67SLewis Huang static uint8_t translate_dig_inst_to_pwrseq_inst(struct dc_link *link)
371*71be0f67SLewis Huang {
372*71be0f67SLewis Huang 	uint8_t pwrseq_inst = 0xF;
373*71be0f67SLewis Huang 
374*71be0f67SLewis Huang 	switch (link->eng_id) {
375*71be0f67SLewis Huang 	case ENGINE_ID_DIGA:
376*71be0f67SLewis Huang 		pwrseq_inst = 0;
377*71be0f67SLewis Huang 		break;
378*71be0f67SLewis Huang 	case ENGINE_ID_DIGB:
379*71be0f67SLewis Huang 		pwrseq_inst = 1;
380*71be0f67SLewis Huang 		break;
381*71be0f67SLewis Huang 	default:
382*71be0f67SLewis Huang 		DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n", link->eng_id);
383*71be0f67SLewis Huang 		ASSERT(false);
384*71be0f67SLewis Huang 		break;
385*71be0f67SLewis Huang 	}
386*71be0f67SLewis Huang 
387*71be0f67SLewis Huang 	return pwrseq_inst;
388*71be0f67SLewis Huang }
389*71be0f67SLewis Huang 
390*71be0f67SLewis Huang 
link_destruct(struct dc_link * link)39154618888SWenjing Liu static void link_destruct(struct dc_link *link)
39254618888SWenjing Liu {
39354618888SWenjing Liu 	int i;
39454618888SWenjing Liu 
39554618888SWenjing Liu 	if (link->hpd_gpio) {
39654618888SWenjing Liu 		dal_gpio_destroy_irq(&link->hpd_gpio);
39754618888SWenjing Liu 		link->hpd_gpio = NULL;
39854618888SWenjing Liu 	}
39954618888SWenjing Liu 
40054618888SWenjing Liu 	if (link->ddc)
40154618888SWenjing Liu 		link_destroy_ddc_service(&link->ddc);
40254618888SWenjing Liu 
40354618888SWenjing Liu 	if (link->panel_cntl)
40454618888SWenjing Liu 		link->panel_cntl->funcs->destroy(&link->panel_cntl);
40554618888SWenjing Liu 
40654618888SWenjing Liu 	if (link->link_enc) {
40754618888SWenjing Liu 		/* Update link encoder resource tracking variables. These are used for
40854618888SWenjing Liu 		 * the dynamic assignment of link encoders to streams. Virtual links
40954618888SWenjing Liu 		 * are not assigned encoder resources on creation.
41054618888SWenjing Liu 		 */
41154618888SWenjing Liu 		if (link->link_id.id != CONNECTOR_ID_VIRTUAL) {
41254618888SWenjing Liu 			link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = NULL;
41354618888SWenjing Liu 			link->dc->res_pool->dig_link_enc_count--;
41454618888SWenjing Liu 		}
41554618888SWenjing Liu 		link->link_enc->funcs->destroy(&link->link_enc);
41654618888SWenjing Liu 	}
41754618888SWenjing Liu 
41854618888SWenjing Liu 	if (link->local_sink)
41954618888SWenjing Liu 		dc_sink_release(link->local_sink);
42054618888SWenjing Liu 
42154618888SWenjing Liu 	for (i = 0; i < link->sink_count; ++i)
42254618888SWenjing Liu 		dc_sink_release(link->remote_sinks[i]);
42354618888SWenjing Liu }
42454618888SWenjing Liu 
get_ddc_line(struct dc_link * link)42554618888SWenjing Liu static enum channel_id get_ddc_line(struct dc_link *link)
42654618888SWenjing Liu {
42754618888SWenjing Liu 	struct ddc *ddc;
42854618888SWenjing Liu 	enum channel_id channel;
42954618888SWenjing Liu 
43054618888SWenjing Liu 	channel = CHANNEL_ID_UNKNOWN;
43154618888SWenjing Liu 
43254618888SWenjing Liu 	ddc = get_ddc_pin(link->ddc);
43354618888SWenjing Liu 
43454618888SWenjing Liu 	if (ddc) {
43554618888SWenjing Liu 		switch (dal_ddc_get_line(ddc)) {
43654618888SWenjing Liu 		case GPIO_DDC_LINE_DDC1:
43754618888SWenjing Liu 			channel = CHANNEL_ID_DDC1;
43854618888SWenjing Liu 			break;
43954618888SWenjing Liu 		case GPIO_DDC_LINE_DDC2:
44054618888SWenjing Liu 			channel = CHANNEL_ID_DDC2;
44154618888SWenjing Liu 			break;
44254618888SWenjing Liu 		case GPIO_DDC_LINE_DDC3:
44354618888SWenjing Liu 			channel = CHANNEL_ID_DDC3;
44454618888SWenjing Liu 			break;
44554618888SWenjing Liu 		case GPIO_DDC_LINE_DDC4:
44654618888SWenjing Liu 			channel = CHANNEL_ID_DDC4;
44754618888SWenjing Liu 			break;
44854618888SWenjing Liu 		case GPIO_DDC_LINE_DDC5:
44954618888SWenjing Liu 			channel = CHANNEL_ID_DDC5;
45054618888SWenjing Liu 			break;
45154618888SWenjing Liu 		case GPIO_DDC_LINE_DDC6:
45254618888SWenjing Liu 			channel = CHANNEL_ID_DDC6;
45354618888SWenjing Liu 			break;
45454618888SWenjing Liu 		case GPIO_DDC_LINE_DDC_VGA:
45554618888SWenjing Liu 			channel = CHANNEL_ID_DDC_VGA;
45654618888SWenjing Liu 			break;
45754618888SWenjing Liu 		case GPIO_DDC_LINE_I2C_PAD:
45854618888SWenjing Liu 			channel = CHANNEL_ID_I2C_PAD;
45954618888SWenjing Liu 			break;
46054618888SWenjing Liu 		default:
46154618888SWenjing Liu 			BREAK_TO_DEBUGGER();
46254618888SWenjing Liu 			break;
46354618888SWenjing Liu 		}
46454618888SWenjing Liu 	}
46554618888SWenjing Liu 
46654618888SWenjing Liu 	return channel;
46754618888SWenjing Liu }
46854618888SWenjing Liu 
construct_phy(struct dc_link * link,const struct link_init_data * init_params)46976f5dc40SWenjing Liu static bool construct_phy(struct dc_link *link,
47054618888SWenjing Liu 			      const struct link_init_data *init_params)
47154618888SWenjing Liu {
47254618888SWenjing Liu 	uint8_t i;
47354618888SWenjing Liu 	struct ddc_service_init_data ddc_service_init_data = { 0 };
47454618888SWenjing Liu 	struct dc_context *dc_ctx = init_params->ctx;
47554618888SWenjing Liu 	struct encoder_init_data enc_init_data = { 0 };
47654618888SWenjing Liu 	struct panel_cntl_init_data panel_cntl_init_data = { 0 };
47754618888SWenjing Liu 	struct integrated_info info = { 0 };
47854618888SWenjing Liu 	struct dc_bios *bios = init_params->dc->ctx->dc_bios;
47954618888SWenjing Liu 	const struct dc_vbios_funcs *bp_funcs = bios->funcs;
48054618888SWenjing Liu 	struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 };
48154618888SWenjing Liu 
48254618888SWenjing Liu 	DC_LOGGER_INIT(dc_ctx->logger);
48354618888SWenjing Liu 
48454618888SWenjing Liu 	link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
48554618888SWenjing Liu 	link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
48654618888SWenjing Liu 	link->link_status.dpcd_caps = &link->dpcd_caps;
48754618888SWenjing Liu 
48854618888SWenjing Liu 	link->dc = init_params->dc;
48954618888SWenjing Liu 	link->ctx = dc_ctx;
49054618888SWenjing Liu 	link->link_index = init_params->link_index;
49154618888SWenjing Liu 
49254618888SWenjing Liu 	memset(&link->preferred_training_settings, 0,
49354618888SWenjing Liu 	       sizeof(struct dc_link_training_overrides));
49454618888SWenjing Liu 	memset(&link->preferred_link_setting, 0,
49554618888SWenjing Liu 	       sizeof(struct dc_link_settings));
49654618888SWenjing Liu 
49754618888SWenjing Liu 	link->link_id =
49854618888SWenjing Liu 		bios->funcs->get_connector_id(bios, init_params->connector_index);
49954618888SWenjing Liu 
50054618888SWenjing Liu 	link->ep_type = DISPLAY_ENDPOINT_PHY;
50154618888SWenjing Liu 
50254618888SWenjing Liu 	DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);
50354618888SWenjing Liu 
50454618888SWenjing Liu 	if (bios->funcs->get_disp_connector_caps_info) {
50554618888SWenjing Liu 		bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);
50654618888SWenjing Liu 		link->is_internal_display = disp_connect_caps_info.INTERNAL_DISPLAY;
50754618888SWenjing Liu 		DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);
50854618888SWenjing Liu 	}
50954618888SWenjing Liu 
51054618888SWenjing Liu 	if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
51154618888SWenjing Liu 		dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n",
51254618888SWenjing Liu 				     __func__, init_params->connector_index,
51354618888SWenjing Liu 				     link->link_id.type, OBJECT_TYPE_CONNECTOR);
51454618888SWenjing Liu 		goto create_fail;
51554618888SWenjing Liu 	}
51654618888SWenjing Liu 
51754618888SWenjing Liu 	if (link->dc->res_pool->funcs->link_init)
51854618888SWenjing Liu 		link->dc->res_pool->funcs->link_init(link);
51954618888SWenjing Liu 
52054618888SWenjing Liu 	link->hpd_gpio = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
52154618888SWenjing Liu 				      link->ctx->gpio_service);
52254618888SWenjing Liu 
52354618888SWenjing Liu 	if (link->hpd_gpio) {
52454618888SWenjing Liu 		dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT);
52554618888SWenjing Liu 		dal_gpio_unlock_pin(link->hpd_gpio);
52654618888SWenjing Liu 		link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio);
52754618888SWenjing Liu 
52854618888SWenjing Liu 		DC_LOG_DC("BIOS object table - hpd_gpio id: %d", link->hpd_gpio->id);
52954618888SWenjing Liu 		DC_LOG_DC("BIOS object table - hpd_gpio en: %d", link->hpd_gpio->en);
53054618888SWenjing Liu 	}
53154618888SWenjing Liu 
53254618888SWenjing Liu 	switch (link->link_id.id) {
53354618888SWenjing Liu 	case CONNECTOR_ID_HDMI_TYPE_A:
53454618888SWenjing Liu 		link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
53554618888SWenjing Liu 
53654618888SWenjing Liu 		break;
53754618888SWenjing Liu 	case CONNECTOR_ID_SINGLE_LINK_DVID:
53854618888SWenjing Liu 	case CONNECTOR_ID_SINGLE_LINK_DVII:
53954618888SWenjing Liu 		link->connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
54054618888SWenjing Liu 		break;
54154618888SWenjing Liu 	case CONNECTOR_ID_DUAL_LINK_DVID:
54254618888SWenjing Liu 	case CONNECTOR_ID_DUAL_LINK_DVII:
54354618888SWenjing Liu 		link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
54454618888SWenjing Liu 		break;
54554618888SWenjing Liu 	case CONNECTOR_ID_DISPLAY_PORT:
54654618888SWenjing Liu 	case CONNECTOR_ID_USBC:
54754618888SWenjing Liu 		link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
54854618888SWenjing Liu 
54954618888SWenjing Liu 		if (link->hpd_gpio)
55054618888SWenjing Liu 			link->irq_source_hpd_rx =
55154618888SWenjing Liu 					dal_irq_get_rx_source(link->hpd_gpio);
55254618888SWenjing Liu 
55354618888SWenjing Liu 		break;
55454618888SWenjing Liu 	case CONNECTOR_ID_EDP:
55554618888SWenjing Liu 		link->connector_signal = SIGNAL_TYPE_EDP;
55654618888SWenjing Liu 
55754618888SWenjing Liu 		if (link->hpd_gpio) {
55854618888SWenjing Liu 			if (!link->dc->config.allow_edp_hotplug_detection)
55954618888SWenjing Liu 				link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
56054618888SWenjing Liu 
56154618888SWenjing Liu 			switch (link->dc->config.allow_edp_hotplug_detection) {
562eeefe7c4SRobin Chen 			case HPD_EN_FOR_ALL_EDP:
563eeefe7c4SRobin Chen 				link->irq_source_hpd_rx =
564eeefe7c4SRobin Chen 						dal_irq_get_rx_source(link->hpd_gpio);
565eeefe7c4SRobin Chen 				break;
566eeefe7c4SRobin Chen 			case HPD_EN_FOR_PRIMARY_EDP_ONLY:
56754618888SWenjing Liu 				if (link->link_index == 0)
56854618888SWenjing Liu 					link->irq_source_hpd_rx =
56954618888SWenjing Liu 						dal_irq_get_rx_source(link->hpd_gpio);
57054618888SWenjing Liu 				else
57154618888SWenjing Liu 					link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
57254618888SWenjing Liu 				break;
573eeefe7c4SRobin Chen 			case HPD_EN_FOR_SECONDARY_EDP_ONLY:
57454618888SWenjing Liu 				if (link->link_index == 1)
57554618888SWenjing Liu 					link->irq_source_hpd_rx =
57654618888SWenjing Liu 						dal_irq_get_rx_source(link->hpd_gpio);
57754618888SWenjing Liu 				else
57854618888SWenjing Liu 					link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
57954618888SWenjing Liu 				break;
58054618888SWenjing Liu 			default:
581eeefe7c4SRobin Chen 				link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
58254618888SWenjing Liu 				break;
58354618888SWenjing Liu 			}
58454618888SWenjing Liu 		}
58554618888SWenjing Liu 
58654618888SWenjing Liu 		break;
58754618888SWenjing Liu 	case CONNECTOR_ID_LVDS:
58854618888SWenjing Liu 		link->connector_signal = SIGNAL_TYPE_LVDS;
58954618888SWenjing Liu 		break;
59054618888SWenjing Liu 	default:
59154618888SWenjing Liu 		DC_LOG_WARNING("Unsupported Connector type:%d!\n",
59254618888SWenjing Liu 			       link->link_id.id);
59354618888SWenjing Liu 		goto create_fail;
59454618888SWenjing Liu 	}
59554618888SWenjing Liu 
5969c384ee8SRodrigo Siqueira 	LINK_INFO("Connector[%d] description: signal: %s\n",
59754618888SWenjing Liu 		  init_params->connector_index,
5989c384ee8SRodrigo Siqueira 		  signal_type_to_string(link->connector_signal));
59954618888SWenjing Liu 
60054618888SWenjing Liu 	ddc_service_init_data.ctx = link->ctx;
60154618888SWenjing Liu 	ddc_service_init_data.id = link->link_id;
60254618888SWenjing Liu 	ddc_service_init_data.link = link;
60354618888SWenjing Liu 	link->ddc = link_create_ddc_service(&ddc_service_init_data);
60454618888SWenjing Liu 
60554618888SWenjing Liu 	if (!link->ddc) {
60654618888SWenjing Liu 		DC_ERROR("Failed to create ddc_service!\n");
60754618888SWenjing Liu 		goto ddc_create_fail;
60854618888SWenjing Liu 	}
60954618888SWenjing Liu 
61054618888SWenjing Liu 	if (!link->ddc->ddc_pin) {
61154618888SWenjing Liu 		DC_ERROR("Failed to get I2C info for connector!\n");
61254618888SWenjing Liu 		goto ddc_create_fail;
61354618888SWenjing Liu 	}
61454618888SWenjing Liu 
61554618888SWenjing Liu 	link->ddc_hw_inst =
61654618888SWenjing Liu 		dal_ddc_get_line(get_ddc_pin(link->ddc));
61754618888SWenjing Liu 
61854618888SWenjing Liu 	enc_init_data.ctx = dc_ctx;
61954618888SWenjing Liu 	bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0,
62054618888SWenjing Liu 			      &enc_init_data.encoder);
62154618888SWenjing Liu 	enc_init_data.connector = link->link_id;
62254618888SWenjing Liu 	enc_init_data.channel = get_ddc_line(link);
62354618888SWenjing Liu 	enc_init_data.hpd_source = get_hpd_line(link);
62454618888SWenjing Liu 
62554618888SWenjing Liu 	link->hpd_src = enc_init_data.hpd_source;
62654618888SWenjing Liu 
62754618888SWenjing Liu 	enc_init_data.transmitter =
62854618888SWenjing Liu 		translate_encoder_to_transmitter(enc_init_data.encoder);
62954618888SWenjing Liu 	link->link_enc =
63054618888SWenjing Liu 		link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);
63154618888SWenjing Liu 
63254618888SWenjing Liu 	DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
63354618888SWenjing Liu 	DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
63454618888SWenjing Liu 
63554618888SWenjing Liu 	if (!link->link_enc) {
63654618888SWenjing Liu 		DC_ERROR("Failed to create link encoder!\n");
63754618888SWenjing Liu 		goto link_enc_create_fail;
63854618888SWenjing Liu 	}
63954618888SWenjing Liu 
64054618888SWenjing Liu 	/* Update link encoder tracking variables. These are used for the dynamic
64154618888SWenjing Liu 	 * assignment of link encoders to streams.
64254618888SWenjing Liu 	 */
64354618888SWenjing Liu 	link->eng_id = link->link_enc->preferred_engine;
64454618888SWenjing Liu 	link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = link->link_enc;
64554618888SWenjing Liu 	link->dc->res_pool->dig_link_enc_count++;
64654618888SWenjing Liu 
64754618888SWenjing Liu 	link->link_enc_hw_inst = link->link_enc->transmitter;
648*71be0f67SLewis Huang 
649*71be0f67SLewis Huang 	if (link->dc->res_pool->funcs->panel_cntl_create &&
650*71be0f67SLewis Huang 		(link->link_id.id == CONNECTOR_ID_EDP ||
651*71be0f67SLewis Huang 			link->link_id.id == CONNECTOR_ID_LVDS)) {
652*71be0f67SLewis Huang 		panel_cntl_init_data.ctx = dc_ctx;
653*71be0f67SLewis Huang 		panel_cntl_init_data.inst = panel_cntl_init_data.ctx->dc_edp_id_count;
654*71be0f67SLewis Huang 		panel_cntl_init_data.pwrseq_inst = translate_dig_inst_to_pwrseq_inst(link);
655*71be0f67SLewis Huang 		link->panel_cntl =
656*71be0f67SLewis Huang 			link->dc->res_pool->funcs->panel_cntl_create(
657*71be0f67SLewis Huang 								&panel_cntl_init_data);
658*71be0f67SLewis Huang 		panel_cntl_init_data.ctx->dc_edp_id_count++;
659*71be0f67SLewis Huang 
660*71be0f67SLewis Huang 		if (link->panel_cntl == NULL) {
661*71be0f67SLewis Huang 			DC_ERROR("Failed to create link panel_cntl!\n");
662*71be0f67SLewis Huang 			goto panel_cntl_create_fail;
663*71be0f67SLewis Huang 		}
664*71be0f67SLewis Huang 	}
66554618888SWenjing Liu 	for (i = 0; i < 4; i++) {
66654618888SWenjing Liu 		if (bp_funcs->get_device_tag(dc_ctx->dc_bios,
66754618888SWenjing Liu 					     link->link_id, i,
66854618888SWenjing Liu 					     &link->device_tag) != BP_RESULT_OK) {
66954618888SWenjing Liu 			DC_ERROR("Failed to find device tag!\n");
67054618888SWenjing Liu 			goto device_tag_fail;
67154618888SWenjing Liu 		}
67254618888SWenjing Liu 
67354618888SWenjing Liu 		/* Look for device tag that matches connector signal,
67454618888SWenjing Liu 		 * CRT for rgb, LCD for other supported signal tyes
67554618888SWenjing Liu 		 */
67654618888SWenjing Liu 		if (!bp_funcs->is_device_id_supported(dc_ctx->dc_bios,
67754618888SWenjing Liu 						      link->device_tag.dev_id))
67854618888SWenjing Liu 			continue;
67954618888SWenjing Liu 		if (link->device_tag.dev_id.device_type == DEVICE_TYPE_CRT &&
68054618888SWenjing Liu 		    link->connector_signal != SIGNAL_TYPE_RGB)
68154618888SWenjing Liu 			continue;
68254618888SWenjing Liu 		if (link->device_tag.dev_id.device_type == DEVICE_TYPE_LCD &&
68354618888SWenjing Liu 		    link->connector_signal == SIGNAL_TYPE_RGB)
68454618888SWenjing Liu 			continue;
68554618888SWenjing Liu 
68654618888SWenjing Liu 		DC_LOG_DC("BIOS object table - device_tag.acpi_device: %d", link->device_tag.acpi_device);
68754618888SWenjing Liu 		DC_LOG_DC("BIOS object table - device_tag.dev_id.device_type: %d", link->device_tag.dev_id.device_type);
68854618888SWenjing Liu 		DC_LOG_DC("BIOS object table - device_tag.dev_id.enum_id: %d", link->device_tag.dev_id.enum_id);
68954618888SWenjing Liu 		break;
69054618888SWenjing Liu 	}
69154618888SWenjing Liu 
69254618888SWenjing Liu 	if (bios->integrated_info)
69354618888SWenjing Liu 		info = *bios->integrated_info;
69454618888SWenjing Liu 
69554618888SWenjing Liu 	/* Look for channel mapping corresponding to connector and device tag */
69654618888SWenjing Liu 	for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; i++) {
69754618888SWenjing Liu 		struct external_display_path *path =
69854618888SWenjing Liu 			&info.ext_disp_conn_info.path[i];
69954618888SWenjing Liu 
70054618888SWenjing Liu 		if (path->device_connector_id.enum_id == link->link_id.enum_id &&
70154618888SWenjing Liu 		    path->device_connector_id.id == link->link_id.id &&
70254618888SWenjing Liu 		    path->device_connector_id.type == link->link_id.type) {
70354618888SWenjing Liu 			if (link->device_tag.acpi_device != 0 &&
70454618888SWenjing Liu 			    path->device_acpi_enum == link->device_tag.acpi_device) {
70554618888SWenjing Liu 				link->ddi_channel_mapping = path->channel_mapping;
70654618888SWenjing Liu 				link->chip_caps = path->caps;
70754618888SWenjing Liu 				DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
70854618888SWenjing Liu 				DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
70954618888SWenjing Liu 			} else if (path->device_tag ==
71054618888SWenjing Liu 				   link->device_tag.dev_id.raw_device_tag) {
71154618888SWenjing Liu 				link->ddi_channel_mapping = path->channel_mapping;
71254618888SWenjing Liu 				link->chip_caps = path->caps;
71354618888SWenjing Liu 				DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
71454618888SWenjing Liu 				DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
71554618888SWenjing Liu 			}
71654618888SWenjing Liu 
71754618888SWenjing Liu 			if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) {
71854618888SWenjing Liu 				link->bios_forced_drive_settings.VOLTAGE_SWING =
71954618888SWenjing Liu 						(info.ext_disp_conn_info.fixdpvoltageswing & 0x3);
72054618888SWenjing Liu 				link->bios_forced_drive_settings.PRE_EMPHASIS =
72154618888SWenjing Liu 						((info.ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3);
72254618888SWenjing Liu 			}
72354618888SWenjing Liu 
72454618888SWenjing Liu 			break;
72554618888SWenjing Liu 		}
72654618888SWenjing Liu 	}
72754618888SWenjing Liu 
72854618888SWenjing Liu 	if (bios->funcs->get_atom_dc_golden_table)
72954618888SWenjing Liu 		bios->funcs->get_atom_dc_golden_table(bios);
73054618888SWenjing Liu 
73154618888SWenjing Liu 	/*
73254618888SWenjing Liu 	 * TODO check if GPIO programmed correctly
73354618888SWenjing Liu 	 *
73454618888SWenjing Liu 	 * If GPIO isn't programmed correctly HPD might not rise or drain
73554618888SWenjing Liu 	 * fast enough, leading to bounces.
73654618888SWenjing Liu 	 */
73754618888SWenjing Liu 	program_hpd_filter(link);
73854618888SWenjing Liu 
73954618888SWenjing Liu 	link->psr_settings.psr_vtotal_control_support = false;
74054618888SWenjing Liu 	link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
74154618888SWenjing Liu 
74209efa4a0SColin Ian King 	DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
74354618888SWenjing Liu 	return true;
74454618888SWenjing Liu device_tag_fail:
74554618888SWenjing Liu 	link->link_enc->funcs->destroy(&link->link_enc);
74654618888SWenjing Liu link_enc_create_fail:
74754618888SWenjing Liu 	if (link->panel_cntl != NULL)
74854618888SWenjing Liu 		link->panel_cntl->funcs->destroy(&link->panel_cntl);
74954618888SWenjing Liu panel_cntl_create_fail:
75054618888SWenjing Liu 	link_destroy_ddc_service(&link->ddc);
75154618888SWenjing Liu ddc_create_fail:
75254618888SWenjing Liu create_fail:
75354618888SWenjing Liu 
75454618888SWenjing Liu 	if (link->hpd_gpio) {
75554618888SWenjing Liu 		dal_gpio_destroy_irq(&link->hpd_gpio);
75654618888SWenjing Liu 		link->hpd_gpio = NULL;
75754618888SWenjing Liu 	}
75854618888SWenjing Liu 
75909efa4a0SColin Ian King 	DC_LOG_DC("BIOS object table - %s failed.\n", __func__);
76054618888SWenjing Liu 	return false;
76154618888SWenjing Liu }
76254618888SWenjing Liu 
construct_dpia(struct dc_link * link,const struct link_init_data * init_params)76376f5dc40SWenjing Liu static bool construct_dpia(struct dc_link *link,
76454618888SWenjing Liu 			      const struct link_init_data *init_params)
76554618888SWenjing Liu {
76654618888SWenjing Liu 	struct ddc_service_init_data ddc_service_init_data = { 0 };
76754618888SWenjing Liu 	struct dc_context *dc_ctx = init_params->ctx;
76854618888SWenjing Liu 
76954618888SWenjing Liu 	DC_LOGGER_INIT(dc_ctx->logger);
77054618888SWenjing Liu 
77154618888SWenjing Liu 	/* Initialized irq source for hpd and hpd rx */
77254618888SWenjing Liu 	link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
77354618888SWenjing Liu 	link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
77454618888SWenjing Liu 	link->link_status.dpcd_caps = &link->dpcd_caps;
77554618888SWenjing Liu 
77654618888SWenjing Liu 	link->dc = init_params->dc;
77754618888SWenjing Liu 	link->ctx = dc_ctx;
77854618888SWenjing Liu 	link->link_index = init_params->link_index;
77954618888SWenjing Liu 
78054618888SWenjing Liu 	memset(&link->preferred_training_settings, 0,
78154618888SWenjing Liu 	       sizeof(struct dc_link_training_overrides));
78254618888SWenjing Liu 	memset(&link->preferred_link_setting, 0,
78354618888SWenjing Liu 	       sizeof(struct dc_link_settings));
78454618888SWenjing Liu 
78554618888SWenjing Liu 	/* Dummy Init for linkid */
78654618888SWenjing Liu 	link->link_id.type = OBJECT_TYPE_CONNECTOR;
78754618888SWenjing Liu 	link->link_id.id = CONNECTOR_ID_DISPLAY_PORT;
78854618888SWenjing Liu 	link->link_id.enum_id = ENUM_ID_1 + init_params->connector_index;
78954618888SWenjing Liu 	link->is_internal_display = false;
79054618888SWenjing Liu 	link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
79154618888SWenjing Liu 	LINK_INFO("Connector[%d] description:signal %d\n",
79254618888SWenjing Liu 		  init_params->connector_index,
79354618888SWenjing Liu 		  link->connector_signal);
79454618888SWenjing Liu 
79554618888SWenjing Liu 	link->ep_type = DISPLAY_ENDPOINT_USB4_DPIA;
79654618888SWenjing Liu 	link->is_dig_mapping_flexible = true;
79754618888SWenjing Liu 
79854618888SWenjing Liu 	/* TODO: Initialize link : funcs->link_init */
79954618888SWenjing Liu 
80054618888SWenjing Liu 	ddc_service_init_data.ctx = link->ctx;
80154618888SWenjing Liu 	ddc_service_init_data.id = link->link_id;
80254618888SWenjing Liu 	ddc_service_init_data.link = link;
80354618888SWenjing Liu 	/* Set indicator for dpia link so that ddc wont be created */
80454618888SWenjing Liu 	ddc_service_init_data.is_dpia_link = true;
80554618888SWenjing Liu 
80654618888SWenjing Liu 	link->ddc = link_create_ddc_service(&ddc_service_init_data);
80754618888SWenjing Liu 	if (!link->ddc) {
80854618888SWenjing Liu 		DC_ERROR("Failed to create ddc_service!\n");
80954618888SWenjing Liu 		goto ddc_create_fail;
81054618888SWenjing Liu 	}
81154618888SWenjing Liu 
81254618888SWenjing Liu 	/* Set dpia port index : 0 to number of dpia ports */
81354618888SWenjing Liu 	link->ddc_hw_inst = init_params->connector_index;
81454618888SWenjing Liu 
81564be47baSMustapha Ghaddar 	// Assign Dpia preferred eng_id
81664be47baSMustapha Ghaddar 	if (link->dc->res_pool->funcs->get_preferred_eng_id_dpia)
81764be47baSMustapha Ghaddar 		link->dpia_preferred_eng_id = link->dc->res_pool->funcs->get_preferred_eng_id_dpia(link->ddc_hw_inst);
81864be47baSMustapha Ghaddar 
81954618888SWenjing Liu 	/* TODO: Create link encoder */
82054618888SWenjing Liu 
82154618888SWenjing Liu 	link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
82254618888SWenjing Liu 
82354618888SWenjing Liu 	/* Some docks seem to NAK I2C writes to segment pointer with mot=0. */
82454618888SWenjing Liu 	link->wa_flags.dp_mot_reset_segment = true;
82554618888SWenjing Liu 
82654618888SWenjing Liu 	return true;
82754618888SWenjing Liu 
82854618888SWenjing Liu ddc_create_fail:
82954618888SWenjing Liu 	return false;
83054618888SWenjing Liu }
83154618888SWenjing Liu 
link_construct(struct dc_link * link,const struct link_init_data * init_params)83254618888SWenjing Liu static bool link_construct(struct dc_link *link,
83354618888SWenjing Liu 			      const struct link_init_data *init_params)
83454618888SWenjing Liu {
83554618888SWenjing Liu 	/* Handle dpia case */
83654618888SWenjing Liu 	if (init_params->is_dpia_link == true)
83776f5dc40SWenjing Liu 		return construct_dpia(link, init_params);
83854618888SWenjing Liu 	else
83976f5dc40SWenjing Liu 		return construct_phy(link, init_params);
84054618888SWenjing Liu }
84154618888SWenjing Liu 
link_create(const struct link_init_data * init_params)84254618888SWenjing Liu struct dc_link *link_create(const struct link_init_data *init_params)
84354618888SWenjing Liu {
84454618888SWenjing Liu 	struct dc_link *link =
84554618888SWenjing Liu 			kzalloc(sizeof(*link), GFP_KERNEL);
84654618888SWenjing Liu 
84754618888SWenjing Liu 	if (NULL == link)
84854618888SWenjing Liu 		goto alloc_fail;
84954618888SWenjing Liu 
85054618888SWenjing Liu 	if (false == link_construct(link, init_params))
85154618888SWenjing Liu 		goto construct_fail;
85254618888SWenjing Liu 
85354618888SWenjing Liu 	return link;
85454618888SWenjing Liu 
85554618888SWenjing Liu construct_fail:
85654618888SWenjing Liu 	kfree(link);
85754618888SWenjing Liu 
85854618888SWenjing Liu alloc_fail:
85954618888SWenjing Liu 	return NULL;
86054618888SWenjing Liu }
86154618888SWenjing Liu 
link_destroy(struct dc_link ** link)86254618888SWenjing Liu void link_destroy(struct dc_link **link)
86354618888SWenjing Liu {
86454618888SWenjing Liu 	link_destruct(*link);
86554618888SWenjing Liu 	kfree(*link);
86654618888SWenjing Liu 	*link = NULL;
86754618888SWenjing Liu }
868