852 lines · c
1/*2 * Copyright 2023 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *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->logger50#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 using65 * various link protocols. It also provides helper functions to interpret66 * certain capabilities or status based on the states it manages or retrieve67 * 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 also97 * 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 associated107 * with the link and link's enable/disable sequences as result of the stream's108 * 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, aux126 * and scdc. It should not contain any specific applications of these127 * protocols such as display capability query, detection, or handshaking such as128 * 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 capability145 * 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 as169 * enable/disable output and set lane/drive settings. It is responsible for170 * maintaining and update software state representing current phy/dpia status171 * 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 according183 * to DP specifications184 */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 panel195 * features such as PSR and ABM and it also manages specs defined eDP panel196 * 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 manual233 * 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 sequences246 * including execution status and timestamps247 */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 sub269 * category, it must be that you are either adding a whole new aspect of270 * responsibility to link service or something doesn't belong to link271 * service. In that case please contact the arch owner to arrange a272 * 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(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(*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(&link->hpd_gpio);379 link->hpd_gpio = NULL;380 }381 382 if (link->ddc)383 link_destroy_ddc_service(&link->ddc);384 385 if (link->panel_cntl)386 link->panel_cntl->funcs->destroy(&link->panel_cntl);387 388 if (link->link_enc && !link->is_dig_mapping_flexible) {389 /* Update link encoder resource tracking variables. These are used for390 * the dynamic assignment of link encoders to streams. Virtual links391 * are not assigned encoder resources on creation.392 */393 if (link->link_id.id != CONNECTOR_ID_VIRTUAL && link->eng_id != ENGINE_ID_UNKNOWN) {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(link->local_sink);402 403 for (i = 0; i < link->sink_count; ++i)404 dc_sink_release(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(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 dc_bios *bios = init_params->dc->ctx->dc_bios;460 const struct dc_vbios_funcs *bp_funcs = bios->funcs;461 struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 };462 463 DC_LOGGER_INIT(dc_ctx->logger);464 465 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;466 link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;467 link->link_status.dpcd_caps = &link->dpcd_caps;468 469 link->dc = init_params->dc;470 link->ctx = dc_ctx;471 link->link_index = init_params->link_index;472 473 memset(&link->preferred_training_settings, 0,474 sizeof(struct dc_link_training_overrides));475 memset(&link->preferred_link_setting, 0,476 sizeof(struct dc_link_settings));477 478 link->link_id =479 bios->funcs->get_connector_id(bios, init_params->connector_index);480 481 link->ep_type = DISPLAY_ENDPOINT_PHY;482 483 DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);484 485 if (bios->funcs->get_disp_connector_caps_info) {486 bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);487 link->is_internal_display = disp_connect_caps_info.INTERNAL_DISPLAY;488 DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);489 }490 491 if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {492 dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n",493 __func__, init_params->connector_index,494 link->link_id.type, OBJECT_TYPE_CONNECTOR);495 goto create_fail;496 }497 498 if (link->dc->res_pool->funcs->link_init)499 link->dc->res_pool->funcs->link_init(link);500 501 link->hpd_gpio = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,502 link->ctx->gpio_service);503 504 if (link->hpd_gpio) {505 dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT);506 dal_gpio_unlock_pin(link->hpd_gpio);507 link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio);508 509 DC_LOG_DC("BIOS object table - hpd_gpio id: %d", link->hpd_gpio->id);510 DC_LOG_DC("BIOS object table - hpd_gpio en: %d", link->hpd_gpio->en);511 }512 513 switch (link->link_id.id) {514 case CONNECTOR_ID_HDMI_TYPE_A:515 link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;516 517 break;518 case CONNECTOR_ID_SINGLE_LINK_DVID:519 case CONNECTOR_ID_SINGLE_LINK_DVII:520 link->connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;521 break;522 case CONNECTOR_ID_DUAL_LINK_DVID:523 case CONNECTOR_ID_DUAL_LINK_DVII:524 link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;525 break;526 case CONNECTOR_ID_DISPLAY_PORT:527 case CONNECTOR_ID_MXM: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(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(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(link->hpd_gpio);552 else553 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(link->hpd_gpio);559 else560 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_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(get_ddc_pin(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(enc_init_data.encoder);611 link->link_enc =612 link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);613 614 if (!link->link_enc) {615 DC_ERROR("Failed to create link encoder!\n");616 goto link_enc_create_fail;617 }618 619 DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);620 DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);621 622 /* Update link encoder tracking variables. These are used for the dynamic623 * 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 tyes657 */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 /* Look for channel mapping corresponding to connector and device tag */676 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; i++) {677 struct external_display_path *path =678 &bios->integrated_info->ext_disp_conn_info.path[i];679 680 if (path->device_connector_id.enum_id == link->link_id.enum_id &&681 path->device_connector_id.id == link->link_id.id &&682 path->device_connector_id.type == link->link_id.type) {683 if (link->device_tag.acpi_device != 0 &&684 path->device_acpi_enum == link->device_tag.acpi_device) {685 link->ddi_channel_mapping = path->channel_mapping;686 link->chip_caps = path->caps;687 DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X",688 link->ddi_channel_mapping.raw);689 DC_LOG_DC("BIOS object table - chip_caps: %d",690 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",696 link->ddi_channel_mapping.raw);697 DC_LOG_DC("BIOS object table - chip_caps: %d",698 link->chip_caps);699 }700 701 if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) {702 link->bios_forced_drive_settings.VOLTAGE_SWING =703 (bios->integrated_info->ext_disp_conn_info.fixdpvoltageswing & 0x3);704 link->bios_forced_drive_settings.PRE_EMPHASIS =705 ((bios->integrated_info->ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3);706 }707 708 break;709 }710 }711 }712 if (bios->funcs->get_atom_dc_golden_table)713 bios->funcs->get_atom_dc_golden_table(bios);714 715 /*716 * TODO check if GPIO programmed correctly717 *718 * If GPIO isn't programmed correctly HPD might not rise or drain719 * fast enough, leading to bounces.720 */721 program_hpd_filter(link);722 723 link->psr_settings.psr_vtotal_control_support = false;724 link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;725 726 DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);727 return true;728device_tag_fail:729 link->link_enc->funcs->destroy(&link->link_enc);730link_enc_create_fail:731 if (link->panel_cntl != NULL)732 link->panel_cntl->funcs->destroy(&link->panel_cntl);733panel_cntl_create_fail:734 link_destroy_ddc_service(&link->ddc);735ddc_create_fail:736create_fail:737 738 if (link->hpd_gpio) {739 dal_gpio_destroy_irq(&link->hpd_gpio);740 link->hpd_gpio = NULL;741 }742 743 DC_LOG_DC("BIOS object table - %s failed.\n", __func__);744 return false;745}746 747static bool construct_dpia(struct dc_link *link,748 const struct link_init_data *init_params)749{750 struct ddc_service_init_data ddc_service_init_data = { 0 };751 struct dc_context *dc_ctx = init_params->ctx;752 753 DC_LOGGER_INIT(dc_ctx->logger);754 755 /* Initialized irq source for hpd and hpd rx */756 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;757 link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;758 link->link_status.dpcd_caps = &link->dpcd_caps;759 760 link->dc = init_params->dc;761 link->ctx = dc_ctx;762 link->link_index = init_params->link_index;763 764 memset(&link->preferred_training_settings, 0,765 sizeof(struct dc_link_training_overrides));766 memset(&link->preferred_link_setting, 0,767 sizeof(struct dc_link_settings));768 769 /* Dummy Init for linkid */770 link->link_id.type = OBJECT_TYPE_CONNECTOR;771 link->link_id.id = CONNECTOR_ID_DISPLAY_PORT;772 link->link_id.enum_id = ENUM_ID_1 + init_params->connector_index;773 link->is_internal_display = false;774 link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;775 LINK_INFO("Connector[%d] description:signal %d\n",776 init_params->connector_index,777 link->connector_signal);778 779 link->ep_type = DISPLAY_ENDPOINT_USB4_DPIA;780 link->is_dig_mapping_flexible = true;781 782 /* TODO: Initialize link : funcs->link_init */783 784 ddc_service_init_data.ctx = link->ctx;785 ddc_service_init_data.id = link->link_id;786 ddc_service_init_data.link = link;787 /* Set indicator for dpia link so that ddc wont be created */788 ddc_service_init_data.is_dpia_link = true;789 790 link->ddc = link_create_ddc_service(&ddc_service_init_data);791 if (!link->ddc) {792 DC_ERROR("Failed to create ddc_service!\n");793 goto ddc_create_fail;794 }795 796 /* Set dpia port index : 0 to number of dpia ports */797 link->ddc_hw_inst = init_params->connector_index;798 799 // Assign Dpia preferred eng_id800 if (link->dc->res_pool->funcs->get_preferred_eng_id_dpia)801 link->dpia_preferred_eng_id = link->dc->res_pool->funcs->get_preferred_eng_id_dpia(link->ddc_hw_inst);802 803 /* TODO: Create link encoder */804 805 link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;806 807 /* Some docks seem to NAK I2C writes to segment pointer with mot=0. */808 link->wa_flags.dp_mot_reset_segment = true;809 810 return true;811 812ddc_create_fail:813 return false;814}815 816static bool link_construct(struct dc_link *link,817 const struct link_init_data *init_params)818{819 /* Handle dpia case */820 if (init_params->is_dpia_link == true)821 return construct_dpia(link, init_params);822 else823 return construct_phy(link, init_params);824}825 826struct dc_link *link_create(const struct link_init_data *init_params)827{828 struct dc_link *link =829 kzalloc(sizeof(*link), GFP_KERNEL);830 831 if (NULL == link)832 goto alloc_fail;833 834 if (false == link_construct(link, init_params))835 goto construct_fail;836 837 return link;838 839construct_fail:840 kfree(link);841 842alloc_fail:843 return NULL;844}845 846void link_destroy(struct dc_link **link)847{848 link_destruct(*link);849 kfree(*link);850 *link = NULL;851}852