/* * Copyright 2023 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD *
*/
/* FILE POLICY AND INTENDED USAGE: * This file owns the creation/destruction of link structure.
*/ #include"link_factory.h" #include"link_detection.h" #include"link_resource.h" #include"link_validation.h" #include"link_dpms.h" #include"accessories/link_dp_cts.h" #include"accessories/link_dp_trace.h" #include"protocols/link_ddc.h" #include"protocols/link_dp_capability.h" #include"protocols/link_dp_dpia_bw.h" #include"protocols/link_dp_dpia.h" #include"protocols/link_dp_irq_handler.h" #include"protocols/link_dp_phy.h" #include"protocols/link_dp_training.h" #include"protocols/link_edp_panel_control.h" #include"protocols/link_hpd.h" #include"gpio_service_interface.h" #include"atomfirmware.h"
/* link_detection manages link detection states and receiver states by using * various link protocols. It also provides helper functions to interpret * certain capabilities or status based on the states it manages or retrieve * them directly from connected receivers.
*/ staticvoid construct_link_service_detection(struct link_service *link_srv)
{
link_srv->detect_link = link_detect;
link_srv->detect_connection_type = link_detect_connection_type;
link_srv->add_remote_sink = link_add_remote_sink;
link_srv->remove_remote_sink = link_remove_remote_sink;
link_srv->get_hpd_state = link_get_hpd_state;
link_srv->get_hpd_gpio = link_get_hpd_gpio;
link_srv->enable_hpd = link_enable_hpd;
link_srv->disable_hpd = link_disable_hpd;
link_srv->enable_hpd_filter = link_enable_hpd_filter;
link_srv->reset_cur_dp_mst_topology = link_reset_cur_dp_mst_topology;
link_srv->get_status = link_get_status;
link_srv->is_hdcp1x_supported = link_is_hdcp14;
link_srv->is_hdcp2x_supported = link_is_hdcp22;
link_srv->clear_dprx_states = link_clear_dprx_states;
}
/* link resource implements accessors to link resource. */ staticvoid construct_link_service_resource(struct link_service *link_srv)
{
link_srv->get_cur_res_map = link_get_cur_res_map;
link_srv->restore_res_map = link_restore_res_map;
link_srv->get_cur_link_res = link_get_cur_link_res;
}
/* link validation owns timing validation against various link limitations. (ex. * link bandwidth, receiver capability or our hardware capability) It also * provides helper functions exposing bandwidth formulas used in validation.
*/ staticvoid construct_link_service_validation(struct link_service *link_srv)
{
link_srv->validate_mode_timing = link_validate_mode_timing;
link_srv->dp_link_bandwidth_kbps = dp_link_bandwidth_kbps;
link_srv->validate_dp_tunnel_bandwidth = link_validate_dp_tunnel_bandwidth;
link_srv->dp_required_hblank_size_bytes = dp_required_hblank_size_bytes;
}
/* link dpms owns the programming sequence of stream's dpms state associated * with the link and link's enable/disable sequences as result of the stream's * dpms state change.
*/ staticvoid construct_link_service_dpms(struct link_service *link_srv)
{
link_srv->set_dpms_on = link_set_dpms_on;
link_srv->set_dpms_off = link_set_dpms_off;
link_srv->resume = link_resume;
link_srv->blank_all_dp_displays = link_blank_all_dp_displays;
link_srv->blank_all_edp_displays = link_blank_all_edp_displays;
link_srv->blank_dp_stream = link_blank_dp_stream;
link_srv->increase_mst_payload = link_increase_mst_payload;
link_srv->reduce_mst_payload = link_reduce_mst_payload;
link_srv->set_dsc_on_stream = link_set_dsc_on_stream;
link_srv->set_dsc_enable = link_set_dsc_enable;
link_srv->update_dsc_config = link_update_dsc_config;
}
/* link ddc implements generic display communication protocols such as i2c, aux * and scdc. It should not contain any specific applications of these * protocols such as display capability query, detection, or handshaking such as * link training.
*/ staticvoid construct_link_service_ddc(struct link_service *link_srv)
{
link_srv->create_ddc_service = link_create_ddc_service;
link_srv->destroy_ddc_service = link_destroy_ddc_service;
link_srv->query_ddc_data = link_query_ddc_data;
link_srv->aux_transfer_raw = link_aux_transfer_raw;
link_srv->configure_fixed_vs_pe_retimer = link_configure_fixed_vs_pe_retimer;
link_srv->aux_transfer_with_retries_no_mutex =
link_aux_transfer_with_retries_no_mutex;
link_srv->is_in_aux_transaction_mode = link_is_in_aux_transaction_mode;
link_srv->get_aux_defer_delay = link_get_aux_defer_delay;
}
/* link dp capability implements dp specific link capability retrieval sequence. * It is responsible for retrieving, parsing, overriding, deciding capability * obtained from dp link. Link capability consists of encoders, DPRXs, cables, * retimers, usb and all other possible backend capabilities.
*/ staticvoid construct_link_service_dp_capability(struct link_service *link_srv)
{
link_srv->dp_is_sink_present = dp_is_sink_present;
link_srv->dp_is_fec_supported = dp_is_fec_supported;
link_srv->dp_is_128b_132b_signal = dp_is_128b_132b_signal;
link_srv->dp_get_max_link_enc_cap = dp_get_max_link_enc_cap;
link_srv->dp_get_verified_link_cap = dp_get_verified_link_cap;
link_srv->dp_get_encoding_format = link_dp_get_encoding_format;
link_srv->dp_should_enable_fec = dp_should_enable_fec;
link_srv->dp_decide_link_settings = link_decide_link_settings;
link_srv->dp_decide_tunnel_settings = link_decide_dp_tunnel_settings;
link_srv->mst_decide_link_encoding_format =
mst_decide_link_encoding_format;
link_srv->edp_decide_link_settings = edp_decide_link_settings;
link_srv->bw_kbps_from_raw_frl_link_rate_data =
link_bw_kbps_from_raw_frl_link_rate_data;
link_srv->dp_overwrite_extended_receiver_cap =
dp_overwrite_extended_receiver_cap;
link_srv->dp_decide_lttpr_mode = dp_decide_lttpr_mode;
}
/* link dp phy/dpia implements basic dp phy/dpia functionality such as * enable/disable output and set lane/drive settings. It is responsible for * maintaining and update software state representing current phy/dpia status * such as current link settings.
*/ staticvoid construct_link_service_dp_phy_or_dpia(struct link_service *link_srv)
{
link_srv->dpia_handle_usb4_bandwidth_allocation_for_link =
dpia_handle_usb4_bandwidth_allocation_for_link;
link_srv->dp_set_drive_settings = dp_set_drive_settings;
link_srv->dpcd_write_rx_power_ctrl = dpcd_write_rx_power_ctrl;
}
/* link dp irq handler implements DP HPD short pulse handling sequence according * to DP specifications
*/ staticvoid construct_link_service_dp_irq_handler(struct link_service *link_srv)
{
link_srv->dp_parse_link_loss_status = dp_parse_link_loss_status;
link_srv->dp_should_allow_hpd_rx_irq = dp_should_allow_hpd_rx_irq;
link_srv->dp_handle_link_loss = dp_handle_link_loss;
link_srv->dp_read_hpd_rx_irq_data = dp_read_hpd_rx_irq_data;
link_srv->dp_handle_hpd_rx_irq = dp_handle_hpd_rx_irq;
}
/* link edp panel control implements retrieval and configuration of eDP panel * features such as PSR and ABM and it also manages specs defined eDP panel * power sequences.
*/ staticvoid construct_link_service_edp_panel_control(struct link_service *link_srv)
{
link_srv->edp_panel_backlight_power_on = edp_panel_backlight_power_on;
link_srv->edp_get_backlight_level = edp_get_backlight_level;
link_srv->edp_get_backlight_level_nits = edp_get_backlight_level_nits;
link_srv->edp_set_backlight_level = edp_set_backlight_level;
link_srv->edp_set_backlight_level_nits = edp_set_backlight_level_nits;
link_srv->edp_get_target_backlight_pwm = edp_get_target_backlight_pwm;
link_srv->edp_get_psr_state = edp_get_psr_state;
link_srv->edp_set_psr_allow_active = edp_set_psr_allow_active;
link_srv->edp_setup_psr = edp_setup_psr;
link_srv->edp_set_sink_vtotal_in_psr_active =
edp_set_sink_vtotal_in_psr_active;
link_srv->edp_get_psr_residency = edp_get_psr_residency;
/* link dp cts implements dp compliance test automation protocols and manual * testing interfaces for debugging and certification purpose.
*/ staticvoid construct_link_service_dp_cts(struct link_service *link_srv)
{
link_srv->dp_handle_automated_test = dp_handle_automated_test;
link_srv->dp_set_test_pattern = dp_set_test_pattern;
link_srv->dp_set_preferred_link_settings =
dp_set_preferred_link_settings;
link_srv->dp_set_preferred_training_settings =
dp_set_preferred_training_settings;
}
/* link dp trace implements tracing interfaces for tracking major dp sequences * including execution status and timestamps
*/ staticvoid construct_link_service_dp_trace(struct link_service *link_srv)
{
link_srv->dp_trace_is_initialized = dp_trace_is_initialized;
link_srv->dp_trace_set_is_logged_flag = dp_trace_set_is_logged_flag;
link_srv->dp_trace_is_logged = dp_trace_is_logged;
link_srv->dp_trace_get_lt_end_timestamp = dp_trace_get_lt_end_timestamp;
link_srv->dp_trace_get_lt_counts = dp_trace_get_lt_counts;
link_srv->dp_trace_get_link_loss_count = dp_trace_get_link_loss_count;
link_srv->dp_trace_set_edp_power_timestamp =
dp_trace_set_edp_power_timestamp;
link_srv->dp_trace_get_edp_poweron_timestamp =
dp_trace_get_edp_poweron_timestamp;
link_srv->dp_trace_get_edp_poweroff_timestamp =
dp_trace_get_edp_poweroff_timestamp;
link_srv->dp_trace_source_sequence = dp_trace_source_sequence;
}
staticvoid construct_link_service(struct link_service *link_srv)
{ /* All link service functions should fall under some sub categories. * If a new function doesn't perfectly fall under an existing sub * category, it must be that you are either adding a whole new aspect of * responsibility to link service or something doesn't belong to link * service. In that case please contact the arch owner to arrange a * design review meeting.
*/
construct_link_service_factory(link_srv);
construct_link_service_detection(link_srv);
construct_link_service_resource(link_srv);
construct_link_service_validation(link_srv);
construct_link_service_dpms(link_srv);
construct_link_service_ddc(link_srv);
construct_link_service_dp_capability(link_srv);
construct_link_service_dp_phy_or_dpia(link_srv);
construct_link_service_dp_irq_handler(link_srv);
construct_link_service_edp_panel_control(link_srv);
construct_link_service_dp_cts(link_srv);
construct_link_service_dp_trace(link_srv);
}
staticenum transmitter translate_encoder_to_transmitter( struct graphics_object_id encoder)
{ switch (encoder.id) { case ENCODER_ID_INTERNAL_UNIPHY: switch (encoder.enum_id) { case ENUM_ID_1: return TRANSMITTER_UNIPHY_A; case ENUM_ID_2: return TRANSMITTER_UNIPHY_B; default: return TRANSMITTER_UNKNOWN;
} break; case ENCODER_ID_INTERNAL_UNIPHY1: switch (encoder.enum_id) { case ENUM_ID_1: return TRANSMITTER_UNIPHY_C; case ENUM_ID_2: return TRANSMITTER_UNIPHY_D; default: return TRANSMITTER_UNKNOWN;
} break; case ENCODER_ID_INTERNAL_UNIPHY2: switch (encoder.enum_id) { case ENUM_ID_1: return TRANSMITTER_UNIPHY_E; case ENUM_ID_2: return TRANSMITTER_UNIPHY_F; default: return TRANSMITTER_UNKNOWN;
} break; case ENCODER_ID_INTERNAL_UNIPHY3: switch (encoder.enum_id) { case ENUM_ID_1: return TRANSMITTER_UNIPHY_G; default: return TRANSMITTER_UNKNOWN;
} break; case ENCODER_ID_EXTERNAL_NUTMEG: switch (encoder.enum_id) { case ENUM_ID_1: return TRANSMITTER_NUTMEG_CRT; default: return TRANSMITTER_UNKNOWN;
} break; case ENCODER_ID_EXTERNAL_TRAVIS: switch (encoder.enum_id) { case ENUM_ID_1: return TRANSMITTER_TRAVIS_CRT; case ENUM_ID_2: return TRANSMITTER_TRAVIS_LCD; default: return TRANSMITTER_UNKNOWN;
} break; default: return TRANSMITTER_UNKNOWN;
}
}
staticvoid link_destruct(struct dc_link *link)
{ int i;
if (link->hpd_gpio) {
dal_gpio_destroy_irq(&link->hpd_gpio);
link->hpd_gpio = NULL;
}
if (link->ddc)
link_destroy_ddc_service(&link->ddc);
if (link->panel_cntl)
link->panel_cntl->funcs->destroy(&link->panel_cntl);
if (link->link_enc && !link->is_dig_mapping_flexible) { /* Update link encoder resource tracking variables. These are used for * the dynamic assignment of link encoders to streams. Virtual links * are not assigned encoder resources on creation.
*/ if (link->link_id.id != CONNECTOR_ID_VIRTUAL && link->eng_id != ENGINE_ID_UNKNOWN) {
link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = NULL;
link->dc->res_pool->dig_link_enc_count--;
}
link->link_enc->funcs->destroy(&link->link_enc);
}
if (link->local_sink)
dc_sink_release(link->local_sink);
for (i = 0; i < link->sink_count; ++i)
dc_sink_release(link->remote_sinks[i]);
}
switch (link->link_id.id) { case CONNECTOR_ID_HDMI_TYPE_A:
link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
if (link->hpd_gpio)
link->irq_source_read_request =
dal_irq_get_read_request(link->hpd_gpio); break; case CONNECTOR_ID_SINGLE_LINK_DVID: case CONNECTOR_ID_SINGLE_LINK_DVII:
link->connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; break; case CONNECTOR_ID_DUAL_LINK_DVID: case CONNECTOR_ID_DUAL_LINK_DVII:
link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK; break; case CONNECTOR_ID_DISPLAY_PORT: case CONNECTOR_ID_MXM: case CONNECTOR_ID_USBC:
link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
if (link->hpd_gpio)
link->irq_source_hpd_rx =
dal_irq_get_rx_source(link->hpd_gpio);
break; case CONNECTOR_ID_EDP: // If smartmux is supported, only create the link on the primary eDP. // Dual eDP is not supported with smartmux. if (!(!link->dc->config.smart_mux_version || dc_ctx->dc_edp_id_count == 0)) goto create_fail;
link->connector_signal = SIGNAL_TYPE_EDP;
if (link->hpd_gpio) { if (!link->dc->config.allow_edp_hotplug_detection
&& !is_smartmux_suported(link))
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
switch (link->dc->config.allow_edp_hotplug_detection) { case HPD_EN_FOR_ALL_EDP:
link->irq_source_hpd_rx =
dal_irq_get_rx_source(link->hpd_gpio); break; case HPD_EN_FOR_PRIMARY_EDP_ONLY: if (link->link_index == 0)
link->irq_source_hpd_rx =
dal_irq_get_rx_source(link->hpd_gpio); else
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; case HPD_EN_FOR_SECONDARY_EDP_ONLY: if (link->link_index == 1)
link->irq_source_hpd_rx =
dal_irq_get_rx_source(link->hpd_gpio); else
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; default:
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break;
}
}
/* Update link encoder tracking variables. These are used for the dynamic * assignment of link encoders to streams.
*/
link->eng_id = link->link_enc->preferred_engine;
link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = link->link_enc;
link->dc->res_pool->dig_link_enc_count++;
if (link->panel_cntl == NULL) {
DC_ERROR("Failed to create link panel_cntl!\n"); goto panel_cntl_create_fail;
}
} for (i = 0; i < 4; i++) { if (bp_funcs->get_device_tag(dc_ctx->dc_bios,
link->link_id, i,
&link->device_tag) != BP_RESULT_OK) {
DC_ERROR("Failed to find device tag!\n"); goto device_tag_fail;
}
/* Look for device tag that matches connector signal, * CRT for rgb, LCD for other supported signal types
*/ if (!bp_funcs->is_device_id_supported(dc_ctx->dc_bios,
link->device_tag.dev_id)) continue; if (link->device_tag.dev_id.device_type == DEVICE_TYPE_CRT &&
link->connector_signal != SIGNAL_TYPE_RGB) continue; if (link->device_tag.dev_id.device_type == DEVICE_TYPE_LCD &&
link->connector_signal == SIGNAL_TYPE_RGB) continue;
if (bios->integrated_info) { /* Look for channel mapping corresponding to connector and device tag */ for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; i++) { struct external_display_path *path =
&bios->integrated_info->ext_disp_conn_info.path[i];
break;
}
}
} if (bios->funcs->get_atom_dc_golden_table)
bios->funcs->get_atom_dc_golden_table(bios);
/* * TODO check if GPIO programmed correctly * * If GPIO isn't programmed correctly HPD might not rise or drain * fast enough, leading to bounces.
*/
program_hpd_filter(link);
ddc_service_init_data.ctx = link->ctx;
ddc_service_init_data.id = link->link_id;
ddc_service_init_data.link = link; /* Set indicator for dpia link so that ddc wont be created */
ddc_service_init_data.is_dpia_link = true;
link->ddc = link_create_ddc_service(&ddc_service_init_data); if (!link->ddc) {
DC_ERROR("Failed to create ddc_service!\n"); goto ddc_create_fail;
}
/* Set dpia port index : 0 to number of dpia ports */
link->ddc_hw_inst = init_params->connector_index;
// Assign Dpia preferred eng_id if (link->dc->res_pool->funcs->get_preferred_eng_id_dpia)
link->dpia_preferred_eng_id = link->dc->res_pool->funcs->get_preferred_eng_id_dpia(link->ddc_hw_inst);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.