mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
drm/amd/display: Add DC link support for FRL
Start bringing in the protocol layer for FRL in DC link. This includes FRL training, timing validation, and other protocol bits. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
70ed4679c5
commit
cbb8e2044b
|
|
@ -45,6 +45,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_LINK_ACCESSORIES)
|
|||
LINK_HWSS = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o \
|
||||
link_hwss_dio_fixed_vs_pe_retimer.o link_hwss_hpo_fixed_vs_pe_retimer_dp.o \
|
||||
link_hwss_virtual.o
|
||||
LINK_HWSS += link_hwss_hpo_frl.o
|
||||
|
||||
AMD_DAL_LINK_HWSS = $(addprefix $(AMDDALPATH)/dc/link/hwss/, \
|
||||
$(LINK_HWSS))
|
||||
|
|
@ -58,6 +59,7 @@ link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \
|
|||
link_dp_training_dpia.o link_dp_training_auxless.o \
|
||||
link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \
|
||||
link_edp_panel_control.o link_dp_panel_replay.o link_dp_irq_handler.o link_dp_dpia_bw.o
|
||||
LINK_PROTOCOLS += link_hdmi_frl.o
|
||||
|
||||
AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \
|
||||
$(LINK_PROTOCOLS))
|
||||
|
|
|
|||
113
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_frl.c
Normal file
113
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_frl.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
*/
|
||||
#include "link_hwss_hpo_frl.h"
|
||||
#include "core_types.h"
|
||||
#include "link/hwss/link_hwss_virtual.h"
|
||||
|
||||
static void setup_hpo_frl_stream_attribute(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
struct hpo_frl_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_frl_stream_enc;
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct pipe_ctx *odm_pipe;
|
||||
struct dc *dc = stream->link->ctx->dc;
|
||||
struct dc_stream_state *temp_stream = &dc->scratch.temp_stream;
|
||||
int odm_combine_num_segments = 1;
|
||||
|
||||
memcpy(temp_stream, stream, sizeof(struct dc_stream_state));
|
||||
|
||||
/* Modify patched_crtc_timing as required for padding */
|
||||
if (pipe_ctx->dsc_padding_params.dsc_hactive_padding) {
|
||||
temp_stream->timing.h_addressable = stream->timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding;
|
||||
temp_stream->timing.h_total = stream->timing.h_total + pipe_ctx->dsc_padding_params.dsc_htotal_padding;
|
||||
}
|
||||
|
||||
/* get number of ODM combine input segments */
|
||||
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
|
||||
odm_combine_num_segments++;
|
||||
|
||||
stream_enc->funcs->hdmi_frl_set_stream_attribute(
|
||||
stream_enc,
|
||||
&temp_stream->timing,
|
||||
&stream->link->frl_link_settings.borrow_params,
|
||||
odm_combine_num_segments);
|
||||
}
|
||||
|
||||
static void disable_hpo_frl_link_output(struct dc_link *link,
|
||||
const struct link_resource *link_res,
|
||||
enum signal_type signal)
|
||||
{
|
||||
(void)link_res;
|
||||
if (dc_is_hdmi_frl_signal(signal))
|
||||
link->hpo_frl_link_enc->funcs->disable_link_encoder(link->hpo_frl_link_enc);
|
||||
link->link_enc->funcs->disable_output(link->link_enc, signal);
|
||||
}
|
||||
|
||||
static void setup_hpo_frl_audio_output(struct pipe_ctx *pipe_ctx,
|
||||
struct audio_output *audio_output, uint32_t audio_inst)
|
||||
{
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_audio_setup(
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc,
|
||||
audio_inst,
|
||||
&pipe_ctx->stream->audio_info,
|
||||
&audio_output->crtc_info);
|
||||
}
|
||||
|
||||
static void enable_hpo_frl_audio_packet(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->audio_mute_control(
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc, false);
|
||||
}
|
||||
|
||||
static void disable_hpo_frl_audio_packet(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->audio_mute_control(
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc, true);
|
||||
|
||||
if (pipe_ctx->stream_res.audio)
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_audio_disable(
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc);
|
||||
}
|
||||
|
||||
static const struct link_hwss hpo_frl_link_hwss = {
|
||||
.setup_stream_encoder = virtual_setup_stream_encoder,
|
||||
.reset_stream_encoder = virtual_reset_stream_encoder,
|
||||
.setup_stream_attribute = setup_hpo_frl_stream_attribute,
|
||||
.disable_link_output = disable_hpo_frl_link_output,
|
||||
.setup_audio_output = setup_hpo_frl_audio_output,
|
||||
.enable_audio_packet = enable_hpo_frl_audio_packet,
|
||||
.disable_audio_packet = disable_hpo_frl_audio_packet,
|
||||
};
|
||||
|
||||
bool can_use_hpo_frl_link_hwss(const struct dc_link *link,
|
||||
const struct link_resource *link_res)
|
||||
{
|
||||
(void)link;
|
||||
return link_res->hpo_frl_link_enc != NULL;
|
||||
}
|
||||
|
||||
const struct link_hwss *get_hpo_frl_link_hwss(void)
|
||||
{
|
||||
return &hpo_frl_link_hwss;
|
||||
}
|
||||
34
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_frl.h
Normal file
34
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_frl.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
*/
|
||||
#ifndef __LINK_HWSS_HPO_FRL_H__
|
||||
#define __LINK_HWSS_HPO_FRL_H__
|
||||
|
||||
#include "link_hwss.h"
|
||||
|
||||
bool can_use_hpo_frl_link_hwss(const struct dc_link *link,
|
||||
const struct link_resource *link_res);
|
||||
const struct link_hwss *get_hpo_frl_link_hwss(void);
|
||||
|
||||
#endif /* __LINK_HWSS_HPO_FRL_H__ */
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
#include "protocols/link_dp_dpia.h"
|
||||
#include "protocols/link_dp_phy.h"
|
||||
#include "protocols/link_dp_training.h"
|
||||
#include "protocols/link_hdmi_frl.h"
|
||||
#include "protocols/link_dp_dpia_bw.h"
|
||||
#include "accessories/link_dp_trace.h"
|
||||
|
||||
|
|
@ -78,6 +79,7 @@ static enum ddc_transaction_type get_ddc_transaction_type(enum signal_type sink_
|
|||
case SIGNAL_TYPE_DVI_SINGLE_LINK:
|
||||
case SIGNAL_TYPE_DVI_DUAL_LINK:
|
||||
case SIGNAL_TYPE_HDMI_TYPE_A:
|
||||
case SIGNAL_TYPE_HDMI_FRL:
|
||||
case SIGNAL_TYPE_LVDS:
|
||||
case SIGNAL_TYPE_RGB:
|
||||
transaction_type = DDC_TRANSACTION_TYPE_I2C;
|
||||
|
|
@ -769,6 +771,60 @@ static bool should_prepare_phy_clocks_for_link_verification(const struct dc *dc,
|
|||
return !can_apply_seamless_boot && reason != DETECT_REASON_BOOT;
|
||||
}
|
||||
|
||||
static bool is_hdmi_frl_in_use(struct dc_link *link)
|
||||
{
|
||||
int i;
|
||||
unsigned int hdmi_conn_count = 0;
|
||||
unsigned int hdmi_stream_count = 0;
|
||||
bool hdmi_frl_in_use = false;
|
||||
bool incoming_link_identical = false;
|
||||
|
||||
/*Enumerate HDMI connector from all present links */
|
||||
for (i = 0; i < link->dc->link_count; i++) {
|
||||
if (link->dc->links[i] != NULL &&
|
||||
dc_is_hdmi_signal(link->dc->links[i]->connector_signal))
|
||||
hdmi_conn_count++;
|
||||
}
|
||||
/* If less than 2 HDMI Connector, assume HPO is always available*/
|
||||
if (hdmi_conn_count < 2)
|
||||
return false;
|
||||
|
||||
/*Enumerate existing HDMI stream count*/
|
||||
for (i = 0; i < link->dc->current_state->stream_count; i++) {
|
||||
if (dc_is_hdmi_signal(link->dc->current_state->streams[i]->signal))
|
||||
hdmi_stream_count++;
|
||||
if (link == link->dc->current_state->streams[i]->link &&
|
||||
(dc_is_hdmi_frl_signal(link->dc->current_state->streams[i]->signal)))
|
||||
incoming_link_identical = true;
|
||||
}
|
||||
|
||||
if (hdmi_stream_count > 1 || (hdmi_stream_count == 1 && !incoming_link_identical)) {
|
||||
for (i = 0; i < link->dc->current_state->stream_count; i++) {
|
||||
if (dc_is_hdmi_frl_signal(
|
||||
link->dc->current_state->streams[i]->signal)) {
|
||||
hdmi_frl_in_use = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if previous link already has been assigned with FRL*/
|
||||
if (!hdmi_frl_in_use && !incoming_link_identical) {
|
||||
for (i = 0; i < link->dc->link_count; i++) {
|
||||
if (link->dc->links[i] != NULL &&
|
||||
link->dc->links[i]->local_sink != NULL &&
|
||||
link != link->dc->links[i] &&
|
||||
dc_is_hdmi_frl_signal(
|
||||
link->dc->links[i]->local_sink->sink_signal)) {
|
||||
hdmi_frl_in_use = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hdmi_frl_in_use;
|
||||
}
|
||||
|
||||
static void prepare_phy_clocks_for_destructive_link_verification(const struct dc *dc)
|
||||
{
|
||||
dc_z10_restore(dc);
|
||||
|
|
@ -796,6 +852,16 @@ static void verify_link_capability_destructive(struct dc_link *link,
|
|||
dp_verify_link_cap_with_retries(
|
||||
link, &known_limit_link_setting,
|
||||
LINK_TRAINING_MAX_VERIFY_RETRY);
|
||||
} else if (dc_is_hdmi_signal(link->local_sink->sink_signal)) {
|
||||
if (!is_hdmi_frl_in_use(link)) {
|
||||
link_set_all_streams_dpms_off_for_link(link);
|
||||
hdmi_frl_verify_link_cap(link, &link->frl_reported_link_cap);
|
||||
link->local_sink->sink_signal = (link->frl_verified_link_cap.frl_link_rate != HDMI_FRL_LINK_RATE_DISABLE)
|
||||
? SIGNAL_TYPE_HDMI_FRL : SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
} else {
|
||||
link->local_sink->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
link->frl_verified_link_cap.frl_link_rate = HDMI_FRL_LINK_RATE_DISABLE;
|
||||
}
|
||||
} else {
|
||||
ASSERT(0);
|
||||
}
|
||||
|
|
@ -815,6 +881,13 @@ static void verify_link_capability_non_destructive(struct dc_link *link)
|
|||
link->verified_link_cap = link->reported_link_cap;
|
||||
else
|
||||
link->verified_link_cap = dp_get_max_link_cap(link);
|
||||
} else if (dc_is_hdmi_signal(link->local_sink->sink_signal)) {
|
||||
link->verified_link_cap = link->reported_link_cap;
|
||||
|
||||
if (is_hdmi_frl_in_use(link)) {
|
||||
link->local_sink->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
link->frl_verified_link_cap.frl_link_rate = HDMI_FRL_LINK_RATE_DISABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -850,6 +923,27 @@ static bool should_verify_link_capability_destructively(struct dc_link *link,
|
|||
destrictive = false;
|
||||
}
|
||||
}
|
||||
} else if (dc_is_hdmi_signal(link->local_sink->sink_signal) && link->link_enc &&
|
||||
link->link_enc->features.flags.bits.IS_HDMI_FRL_CAPABLE &&
|
||||
link->local_sink->edid_caps.max_frl_rate != 0) {
|
||||
int i = 0;
|
||||
struct pipe_ctx *pipes =
|
||||
link->dc->current_state->res_ctx.pipe_ctx;
|
||||
|
||||
destrictive = true;
|
||||
if (is_hdmi_frl_in_use(link)) {
|
||||
destrictive = false;
|
||||
} else if (link->dc->config.skip_frl_pretraining) {
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
if (pipes[i].stream != NULL &&
|
||||
pipes[i].stream->link == link) {
|
||||
/*If link is already active, skip PHY programming*/
|
||||
if (link->link_status.link_active) {
|
||||
destrictive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return destrictive;
|
||||
|
|
@ -1007,6 +1101,7 @@ static bool detect_link_and_local_sink(struct dc_link *link,
|
|||
|
||||
/* From Disconnected-to-Connected. */
|
||||
switch (link->connector_signal) {
|
||||
case SIGNAL_TYPE_HDMI_FRL:
|
||||
case SIGNAL_TYPE_HDMI_TYPE_A: {
|
||||
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
|
||||
if (aud_support->hdmi_audio_native)
|
||||
|
|
@ -1234,6 +1329,13 @@ static bool detect_link_and_local_sink(struct dc_link *link,
|
|||
if (dc_is_hdmi_signal(link->connector_signal))
|
||||
read_scdc_caps(link->ddc, link->local_sink);
|
||||
|
||||
if (dc_is_hdmi_signal(link->connector_signal) && dc->debug.enable_hdmi_idcc) {
|
||||
memset(&link->hdmi_cable_id, 0, sizeof(union hdmi_idcc_cable_id));
|
||||
read_idcc_data(link->ddc, HDMI_IDCC_SCOPE_RW_CA,
|
||||
link->hdmi_cable_id.raw, 0, 4);
|
||||
}
|
||||
if (sink->edid_caps.rr_capable)
|
||||
hdmi_frl_write_read_request_enable(link->ddc);
|
||||
/* When FreeSync is toggled through OSD,
|
||||
* we see same EDID no matter what. Check MCCS caps
|
||||
* to see if we should update FreeSync caps now.
|
||||
|
|
@ -1248,6 +1350,12 @@ static bool detect_link_and_local_sink(struct dc_link *link,
|
|||
same_edid = false;
|
||||
}
|
||||
|
||||
if (reason != DETECT_REASON_FALLBACK && dc_is_hdmi_signal(link->connector_signal) &&
|
||||
link->link_enc->features.flags.bits.IS_HDMI_FRL_CAPABLE && sink->edid_caps.max_frl_rate != 0) {
|
||||
hdmi_frl_retrieve_link_cap(link, link->local_sink);
|
||||
}
|
||||
if (reason == DETECT_REASON_FALLBACK && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
|
||||
same_edid = false;
|
||||
if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
|
||||
sink_caps.transaction_type ==
|
||||
DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
|
||||
|
|
@ -1262,6 +1370,8 @@ static bool detect_link_and_local_sink(struct dc_link *link,
|
|||
link_disconnect_remap(prev_sink, link);
|
||||
sink = prev_sink;
|
||||
prev_sink = NULL;
|
||||
if (reason == DETECT_REASON_FALLBACK && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
|
||||
sink->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
}
|
||||
|
||||
if (!sink->edid_caps.analog)
|
||||
|
|
@ -1529,6 +1639,7 @@ bool link_is_hdcp22(struct dc_link *link, enum signal_type signal)
|
|||
case SIGNAL_TYPE_DVI_SINGLE_LINK:
|
||||
case SIGNAL_TYPE_DVI_DUAL_LINK:
|
||||
case SIGNAL_TYPE_HDMI_TYPE_A:
|
||||
case SIGNAL_TYPE_HDMI_FRL:
|
||||
ret = (link->hdcp_caps.rx_caps.fields.version == 0x4) ? 1:0;
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "protocols/link_edp_panel_control.h"
|
||||
#include "protocols/link_dp_panel_replay.h"
|
||||
#include "protocols/link_dp_dpia_bw.h"
|
||||
#include "link/protocols/link_hdmi_frl.h"
|
||||
|
||||
#include "dm_helpers.h"
|
||||
#include "link_enc_cfg.h"
|
||||
|
|
@ -71,6 +72,10 @@
|
|||
DC_LOG_RETIMER_REDRIVER( \
|
||||
__VA_ARGS__)
|
||||
|
||||
#define FRL_INFO(...) \
|
||||
DC_LOG_HDMI_FRL_LTP( \
|
||||
__VA_ARGS__)
|
||||
|
||||
#define MAX_MTP_SLOT_COUNT 64
|
||||
#define LINK_TRAINING_ATTEMPTS 4
|
||||
#define PEAK_FACTOR_X1000 1006
|
||||
|
|
@ -550,14 +555,21 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
|
|||
if (dp_is_128b_132b_signal(pipe_ctx))
|
||||
config.stream_enc_idx =
|
||||
(uint8_t)(pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0);
|
||||
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
config.stream_enc_idx =
|
||||
(uint8_t)(pipe_ctx->stream_res.hpo_frl_stream_enc->id - ENGINE_ID_HPO_0);
|
||||
|
||||
/* dig back end */
|
||||
config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst;
|
||||
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
config.dig_be = (uint8_t)pipe_ctx->stream_res.hpo_frl_stream_enc->stream_enc_inst;
|
||||
|
||||
/* link encoder index */
|
||||
config.link_enc_idx = (uint8_t)(link_enc->transmitter - TRANSMITTER_UNIPHY_A);
|
||||
if (dp_is_128b_132b_signal(pipe_ctx))
|
||||
config.link_enc_idx = (uint8_t)pipe_ctx->link_res.hpo_dp_link_enc->inst;
|
||||
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
config.link_enc_idx = (uint8_t)pipe_ctx->stream->link->hpo_frl_link_enc->inst;
|
||||
|
||||
/* dio output index is dpia index for DPIA endpoint & dcio index by default */
|
||||
if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
|
||||
|
|
@ -577,6 +589,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
|
|||
config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0;
|
||||
config.mst_enabled = (pipe_ctx->stream->signal ==
|
||||
SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0;
|
||||
config.frl_enabled = dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ? 1 : 0;
|
||||
config.dp2_enabled = dp_is_128b_132b_signal(pipe_ctx) ? 1 : 0;
|
||||
config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ?
|
||||
1 : 0;
|
||||
|
|
@ -588,6 +601,38 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
|
|||
cp_psp->funcs.update_stream_config(cp_psp->handle, &config);
|
||||
}
|
||||
|
||||
void link_wait_for_unlocked(struct dc_link *link)
|
||||
{
|
||||
unsigned long long enter_timestamp;
|
||||
unsigned long long finish_timestamp;
|
||||
unsigned long long time_taken_in_ns;
|
||||
bool waited = false;
|
||||
|
||||
DC_LOGGER_INIT(link->ctx->logger);
|
||||
|
||||
enter_timestamp = dm_get_timestamp(link->ctx);
|
||||
|
||||
while (link->is_link_locked) { // busy wait
|
||||
if (!waited) {
|
||||
DC_LOG_DC("%s: 0x%p ...", __func__, link);
|
||||
|
||||
waited = true;
|
||||
}
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (!waited)
|
||||
return;
|
||||
|
||||
finish_timestamp = dm_get_timestamp(link->ctx);
|
||||
time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx,
|
||||
finish_timestamp, enter_timestamp);
|
||||
|
||||
DC_LOG_DC("%s: 0x%p took %llu ms.", __func__,
|
||||
link, div_u64(time_taken_in_ns, 1000000));
|
||||
}
|
||||
|
||||
static void set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
|
||||
{
|
||||
struct dc *dc = pipe_ctx->stream->ctx->dc;
|
||||
|
|
@ -595,6 +640,9 @@ static void set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
|
|||
if (!dc_is_hdmi_signal(pipe_ctx->stream->signal))
|
||||
return;
|
||||
|
||||
if (pipe_ctx->stream->timing.flags.DSC)
|
||||
return;
|
||||
|
||||
dc->hwss.set_avmute(pipe_ctx, enable);
|
||||
}
|
||||
|
||||
|
|
@ -1813,6 +1861,13 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
|
|||
stream->phy_pix_clk,
|
||||
(stream->timing.flags.LTE_340MCSC_SCRAMBLE != 0));
|
||||
|
||||
if (dc->debug.enable_hdmi_idcc) {
|
||||
union hdmi_idcc_source_id source_id;
|
||||
|
||||
source_id.raw = 0xff;
|
||||
write_idcc_data(stream->link->ddc, HDMI_IDCC_SCOPE_WRITE,
|
||||
&source_id.raw, 0, 1);
|
||||
}
|
||||
memset(&stream->link->cur_link_settings, 0,
|
||||
sizeof(struct dc_link_settings));
|
||||
|
||||
|
|
@ -1838,6 +1893,109 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
|
|||
read_scdc_data(link->ddc);
|
||||
}
|
||||
|
||||
static enum dc_status enable_link_hdmi_frl(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
enum link_result link_stat = LINK_RESULT_UNKNOWN;
|
||||
enum dc_status status = DC_OK;
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
|
||||
enum clock_source_id frl_phy_clock_source_id;
|
||||
bool frl_poll_start = true;
|
||||
|
||||
DC_LOGGER_INIT(stream->ctx->logger);
|
||||
|
||||
if ((!stream->link->link_enc) ||
|
||||
(!stream->link->hpo_frl_link_enc) ||
|
||||
(!core_dc->res_pool->dccg->funcs->enable_hdmicharclk) ||
|
||||
(!(pipe_ctx->stream_res.hpo_frl_stream_enc)))
|
||||
return DC_ERROR_UNEXPECTED;
|
||||
|
||||
/* get link settings for video mode timing */
|
||||
hdmi_frl_decide_link_settings(stream, &stream->link->frl_link_settings, &pipe_ctx->dsc_padding_params);
|
||||
|
||||
switch (stream->link->frl_link_settings.frl_link_rate) {
|
||||
case HDMI_FRL_LINK_RATE_3GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 166667;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_6GBPS:
|
||||
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 333333;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_8GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 444444;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_10GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 555555;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_12GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 666667;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_16GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 888889;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_20GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 1111111;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_24GBPS:
|
||||
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = 1333333;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
stream->phy_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_sym_clk;
|
||||
|
||||
memset(&stream->link->cur_link_settings, 0,
|
||||
sizeof(struct dc_link_settings));
|
||||
|
||||
/* Find proper clock source in HDMI FRL mode for phy used for DCCG */
|
||||
frl_phy_clock_source_id = hdmi_frl_find_matching_phypll(stream->link);
|
||||
|
||||
FRL_INFO("FRL LINK TRAINING: LTS:P Start\n");
|
||||
/* Setup FRL PHY, enable HDMI character clock and HPO link encoder */
|
||||
core_dc->hwss.setup_hdmi_frl_link(stream->link,
|
||||
(pipe_ctx->stream_res.hpo_frl_stream_enc->id - ENGINE_ID_HPO_0),
|
||||
frl_phy_clock_source_id);
|
||||
|
||||
link_stat = hdmi_frl_perform_link_training_with_retries(stream->link);
|
||||
|
||||
if (core_dc->res_pool->dccg->funcs->set_valid_pixel_rate)
|
||||
core_dc->res_pool->dccg->funcs->set_valid_pixel_rate(
|
||||
core_dc->res_pool->dccg,
|
||||
core_dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(core_dc->clk_mgr),
|
||||
pipe_ctx->stream_res.tg->inst,
|
||||
(stream->timing.pix_clk_100hz / 10));
|
||||
|
||||
/* Enable FRL packet transmission */
|
||||
if (link_stat == LINK_RESULT_SUCCESS) {
|
||||
stream->link->hpo_frl_link_enc->funcs->enable_output(
|
||||
stream->link->hpo_frl_link_enc);
|
||||
if (stream->link->frl_flags.apply_vsdb_rcc_wa)
|
||||
stream->link->hpo_frl_link_enc->funcs->apply_vsdb_rcc_wa(stream->link->hpo_frl_link_enc);
|
||||
if (frl_poll_start)
|
||||
hdmi_frl_poll_start(stream->link->ddc);
|
||||
|
||||
FRL_INFO("FRL LINK TRAINING: LTS:P Success\n");
|
||||
|
||||
/* Set HDMISTREAMCLK source to DTBCLK0 and bypass DTO */
|
||||
if (core_dc->res_pool->dccg->funcs->set_hdmistreamclk) {
|
||||
core_dc->res_pool->dccg->funcs->set_hdmistreamclk(
|
||||
core_dc->res_pool->dccg,
|
||||
DTBCLK0,
|
||||
pipe_ctx->stream_res.tg->inst);
|
||||
}
|
||||
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_enable(
|
||||
pipe_ctx->stream_res.hpo_frl_stream_enc,
|
||||
pipe_ctx->stream_res.tg->inst);
|
||||
} else {
|
||||
status = DC_FAIL_HDMI_FRL_LINK_TRAINING;
|
||||
stream->link->frl_link_settings.frl_link_rate = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum dc_status enable_link_dp(struct dc_state *state,
|
||||
struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
|
|
@ -2076,6 +2234,14 @@ static enum dc_status enable_link(
|
|||
enable_link_hdmi(pipe_ctx);
|
||||
status = DC_OK;
|
||||
break;
|
||||
case SIGNAL_TYPE_HDMI_FRL:
|
||||
if (link->local_sink &&
|
||||
link->local_sink->edid_caps.panel_patch.delay_hdmi_link_training &&
|
||||
stream->timing.pix_clk_100hz == 6627500) {
|
||||
msleep(link->local_sink->edid_caps.panel_patch.delay_hdmi_link_training);
|
||||
}
|
||||
status = enable_link_hdmi_frl(pipe_ctx);
|
||||
break;
|
||||
case SIGNAL_TYPE_LVDS:
|
||||
enable_link_lvds(pipe_ctx);
|
||||
status = DC_OK;
|
||||
|
|
@ -2178,6 +2344,8 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
|
|||
|
||||
if (dp_is_128b_132b_signal(pipe_ctx))
|
||||
vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
|
||||
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
vpg = pipe_ctx->stream_res.hpo_frl_stream_enc->vpg;
|
||||
if (dc_is_virtual_signal(pipe_ctx->stream->signal))
|
||||
return;
|
||||
|
||||
|
|
@ -2190,6 +2358,8 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
|
|||
}
|
||||
}
|
||||
|
||||
link_wait_for_unlocked(link);
|
||||
|
||||
if (!pipe_ctx->stream->sink->edid_caps.panel_patch.skip_avmute) {
|
||||
if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
|
||||
set_avmute(pipe_ctx, true);
|
||||
|
|
@ -2292,6 +2462,8 @@ void link_set_dpms_on(
|
|||
|
||||
if (dp_is_128b_132b_signal(pipe_ctx))
|
||||
vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
|
||||
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
vpg = pipe_ctx->stream_res.hpo_frl_stream_enc->vpg;
|
||||
if (dc_is_virtual_signal(pipe_ctx->stream->signal))
|
||||
return;
|
||||
|
||||
|
|
@ -2306,11 +2478,13 @@ void link_set_dpms_on(
|
|||
}
|
||||
}
|
||||
|
||||
link_wait_for_unlocked(stream->link);
|
||||
if (!dc->config.unify_link_enc_assignment)
|
||||
link_enc = link_enc_cfg_get_link_enc(link);
|
||||
ASSERT(link_enc);
|
||||
|
||||
if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
|
||||
&& !dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)
|
||||
&& !dp_is_128b_132b_signal(pipe_ctx)) {
|
||||
if (link_enc)
|
||||
link_enc->funcs->setup(
|
||||
|
|
@ -2320,9 +2494,14 @@ void link_set_dpms_on(
|
|||
|
||||
pipe_ctx->stream->link->link_state_valid = true;
|
||||
|
||||
if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
hdmi_frl_decide_link_settings(stream, &stream->link->frl_link_settings, &pipe_ctx->dsc_padding_params);
|
||||
|
||||
if (pipe_ctx->stream_res.tg->funcs->set_out_mux) {
|
||||
if (dp_is_128b_132b_signal(pipe_ctx))
|
||||
otg_out_dest = OUT_MUX_HPO_DP;
|
||||
else if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
|
||||
otg_out_dest = OUT_MUX_HPO_FRL;
|
||||
else
|
||||
otg_out_dest = OUT_MUX_DIO;
|
||||
pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, otg_out_dest);
|
||||
|
|
@ -2413,8 +2592,9 @@ void link_set_dpms_on(
|
|||
* show the stream anyway. But MST displays can't proceed
|
||||
* without link training.
|
||||
*/
|
||||
if (status != DC_FAIL_DP_LINK_TRAINING ||
|
||||
pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
|
||||
if ((status != DC_FAIL_DP_LINK_TRAINING &&
|
||||
status != DC_FAIL_HDMI_FRL_LINK_TRAINING) ||
|
||||
pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
|
||||
if (false == stream->link->link_status.link_active)
|
||||
disable_link(stream->link, &pipe_ctx->link_res,
|
||||
pipe_ctx->stream->signal);
|
||||
|
|
@ -2434,6 +2614,7 @@ void link_set_dpms_on(
|
|||
* from transmitter control.
|
||||
*/
|
||||
if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
|
||||
dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ||
|
||||
dp_is_128b_132b_signal(pipe_ctx))) {
|
||||
|
||||
if (link_enc)
|
||||
|
|
|
|||
|
|
@ -50,4 +50,5 @@ struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp(
|
|||
void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
bool link_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
bool link_update_dsc_config(struct pipe_ctx *pipe_ctx);
|
||||
void link_wait_for_unlocked(struct dc_link *link);
|
||||
#endif /* __DC_LINK_DPMS_H__ */
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "protocols/link_dp_training.h"
|
||||
#include "protocols/link_edp_panel_control.h"
|
||||
#include "protocols/link_dp_panel_replay.h"
|
||||
#include "protocols/link_hdmi_frl.h"
|
||||
#include "protocols/link_hpd.h"
|
||||
#include "gpio_service_interface.h"
|
||||
#include "atomfirmware.h"
|
||||
|
|
@ -101,6 +102,8 @@ static void 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->frl_link_bandwidth_kbps = frl_link_bandwidth_kbps;
|
||||
link_srv->frl_margin_check_uncompressed_video = frl_capacity_computations_uncompressed_video;
|
||||
link_srv->dp_required_hblank_size_bytes = dp_required_hblank_size_bytes;
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +124,7 @@ static void construct_link_service_dpms(struct link_service *link_srv)
|
|||
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_srv->wait_for_unlocked = link_wait_for_unlocked;
|
||||
}
|
||||
|
||||
/* link ddc implements generic display communication protocols such as i2c, aux
|
||||
|
|
@ -243,6 +247,25 @@ static void construct_link_service_dp_panel_replay(struct link_service *link_srv
|
|||
link_srv->dp_pr_get_state = dp_pr_get_state;
|
||||
}
|
||||
|
||||
/* link hdmi frl implements FRL link capability and link training related
|
||||
* functions. FRL link is established by order of retrieve_link, verify_link,
|
||||
* and poll_status. Other helper functions exist to obtain information required
|
||||
* to maintain the correct sequence according to HDMI specification. Each
|
||||
* sequence and state inside link training functions are timing sensitive and order sensitive.
|
||||
* It is mandatory that these functions are debugged with FRL_LTP output message
|
||||
* configurable in DSAT. Any changes in the LT sequence should follow the HDMI
|
||||
* specification as much as possible and tested through HDMI electrical and
|
||||
* link layer compliance.
|
||||
*/
|
||||
static void construct_link_service_hdmi_frl(struct link_service *link_srv)
|
||||
{
|
||||
link_srv->hdmi_frl_poll_status_flag = hdmi_frl_poll_status_flag;
|
||||
link_srv->hdmi_frl_get_verified_link_cap =
|
||||
hdmi_frl_get_verified_link_cap;
|
||||
link_srv->hdmi_frl_set_preferred_link_settings =
|
||||
hdmi_frl_set_preferred_link_settings;
|
||||
}
|
||||
|
||||
/* link dp cts implements dp compliance test automation protocols and manual
|
||||
* testing interfaces for debugging and certification purpose.
|
||||
*/
|
||||
|
|
@ -296,6 +319,7 @@ static void construct_link_service(struct link_service *link_srv)
|
|||
construct_link_service_dp_irq_handler(link_srv);
|
||||
construct_link_service_edp_panel_control(link_srv);
|
||||
construct_link_service_dp_panel_replay(link_srv);
|
||||
construct_link_service_hdmi_frl(link_srv);
|
||||
construct_link_service_dp_cts(link_srv);
|
||||
construct_link_service_dp_trace(link_srv);
|
||||
}
|
||||
|
|
@ -401,6 +425,8 @@ static void link_destruct(struct dc_link *link)
|
|||
link->link_enc->funcs->destroy(&link->link_enc);
|
||||
}
|
||||
|
||||
if (link->hpo_frl_link_enc)
|
||||
link->hpo_frl_link_enc->funcs->destroy(&link->hpo_frl_link_enc);
|
||||
if (link->local_sink)
|
||||
dc_sink_release(link->local_sink);
|
||||
|
||||
|
|
@ -630,6 +656,7 @@ static bool construct_phy(struct dc_link *link,
|
|||
|
||||
DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
|
||||
DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
|
||||
DC_LOG_DC("BIOS object table - IS_HDMI_FRL_CAPABLE: %d", link->link_enc->features.flags.bits.IS_HDMI_FRL_CAPABLE);
|
||||
|
||||
switch (link->link_id.id) {
|
||||
case CONNECTOR_ID_HDMI_TYPE_A:
|
||||
|
|
@ -833,12 +860,29 @@ static bool construct_phy(struct dc_link *link,
|
|||
*/
|
||||
program_hpd_filter(link);
|
||||
|
||||
/* If the connector is HDMI FRL capable, also create an HPO link encoder */
|
||||
if ((link->link_enc->features.flags.bits.IS_HDMI_FRL_CAPABLE) &&
|
||||
(!link->link_enc->features.flags.bits.DP_IS_USB_C) &&
|
||||
(link->dc->res_pool->funcs->hpo_frl_link_enc_create)) {
|
||||
enum engine_id hpo_eng_id;
|
||||
hpo_eng_id = ENGINE_ID_HPO_0;
|
||||
|
||||
link->hpo_frl_link_enc = link->dc->res_pool->funcs->hpo_frl_link_enc_create(
|
||||
hpo_eng_id,
|
||||
dc_ctx);
|
||||
if (link->hpo_frl_link_enc == NULL) {
|
||||
DC_ERROR("Failed to create HPO link encoder!\n");
|
||||
goto hpo_enc_create_fail;
|
||||
}
|
||||
}
|
||||
|
||||
link->psr_settings.psr_vtotal_control_support = false;
|
||||
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
|
||||
link->replay_settings.config.replay_version = DC_REPLAY_VERSION_UNSUPPORTED;
|
||||
|
||||
DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
|
||||
return true;
|
||||
hpo_enc_create_fail:
|
||||
device_tag_fail:
|
||||
link_enc_create_fail:
|
||||
panel_cntl_create_fail:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "link_validation.h"
|
||||
#include "protocols/link_dp_capability.h"
|
||||
#include "protocols/link_dp_dpia_bw.h"
|
||||
#include "protocols/link_hdmi_frl.h"
|
||||
#include "resource.h"
|
||||
|
||||
#define DC_LOGGER_INIT(logger)
|
||||
|
|
@ -263,6 +264,195 @@ uint32_t dp_link_bandwidth_kbps(
|
|||
return link_rate_per_lane_kbps * link_settings->lane_count / 10000 * total_data_bw_efficiency_x10000;
|
||||
}
|
||||
|
||||
uint32_t frl_link_bandwidth_kbps(enum hdmi_frl_link_rate link_rate)
|
||||
{
|
||||
switch (link_rate) {
|
||||
case HDMI_FRL_LINK_RATE_3GBPS:
|
||||
return 9000000;
|
||||
case HDMI_FRL_LINK_RATE_6GBPS:
|
||||
return 18000000;
|
||||
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
|
||||
return 24000000;
|
||||
case HDMI_FRL_LINK_RATE_8GBPS:
|
||||
return 32000000;
|
||||
case HDMI_FRL_LINK_RATE_10GBPS:
|
||||
return 40000000;
|
||||
case HDMI_FRL_LINK_RATE_12GBPS:
|
||||
return 48000000;
|
||||
case HDMI_FRL_LINK_RATE_16GBPS:
|
||||
return 64000000;
|
||||
case HDMI_FRL_LINK_RATE_20GBPS:
|
||||
return 80000000;
|
||||
case HDMI_FRL_LINK_RATE_24GBPS:
|
||||
return 96000000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool frl_capacity_computations_common(struct frl_cap_chk_params_fixed31_32 *params,
|
||||
struct frl_cap_chk_intermediates_fixed31_32 *inter)
|
||||
{
|
||||
struct fixed31_32 audio_bw_reserve = dc_fixpt_from_int((params->compressed ? 192000 : 0));
|
||||
struct fixed31_32 pixel_rate_tolerance = dc_fixpt_div_int(dc_fixpt_from_int(5), 1000);
|
||||
struct fixed31_32 max_audio_tol_rate;
|
||||
struct fixed31_32 overhead_m;
|
||||
|
||||
inter->c_frl_sb = 4 * C_FRL_CB + params->lanes;
|
||||
inter->overhead_sb = dc_fixpt_div_int(dc_fixpt_from_int(params->lanes), inter->c_frl_sb);
|
||||
inter->overhead_rs = dc_fixpt_div_int(dc_fixpt_from_int(32), inter->c_frl_sb);
|
||||
inter->overhead_map = dc_fixpt_div_int(dc_fixpt_from_int(25), (inter->c_frl_sb * 10));
|
||||
|
||||
inter->overhead_min = dc_fixpt_add(inter->overhead_sb, inter->overhead_rs);
|
||||
inter->overhead_min = dc_fixpt_add(inter->overhead_min, inter->overhead_map);
|
||||
overhead_m = dc_fixpt_div_int(dc_fixpt_from_int(3), 1000);
|
||||
inter->overhead_max = dc_fixpt_add(inter->overhead_min, overhead_m);
|
||||
|
||||
pixel_rate_tolerance = dc_fixpt_add_int(pixel_rate_tolerance, 1);
|
||||
|
||||
inter->f_pixel_clock_max = dc_fixpt_mul(params->f_pixel_clock_nominal, pixel_rate_tolerance);
|
||||
inter->t_line = dc_fixpt_div(dc_fixpt_from_int(params->h_active + params->h_blank), inter->f_pixel_clock_max);
|
||||
inter->r_bit_min = dc_fixpt_div_int(dc_fixpt_from_int(TOLERANCE_FRL_BIT), 1000000);
|
||||
inter->r_bit_min = dc_fixpt_sub(dc_fixpt_from_int(1), inter->r_bit_min);
|
||||
inter->r_bit_min = dc_fixpt_mul(params->r_bit_nominal, inter->r_bit_min);
|
||||
|
||||
inter->r_frl_char_min = dc_fixpt_div_int(inter->r_bit_min, 18);
|
||||
inter->c_frl_line = dc_fixpt_mul(inter->t_line, inter->r_frl_char_min);
|
||||
inter->c_frl_line = dc_fixpt_mul_int(inter->c_frl_line, params->lanes);
|
||||
|
||||
switch (params->audio_packet_type) {
|
||||
case 0x02:
|
||||
if (params->layout == 0)
|
||||
inter->ap = dc_fixpt_div_int(dc_fixpt_from_int(25), 100);
|
||||
else if (params->layout == 1)
|
||||
inter->ap = dc_fixpt_from_int(1);
|
||||
break;
|
||||
case 0x08:
|
||||
inter->ap = dc_fixpt_div_int(dc_fixpt_from_int(25), 100);
|
||||
break;
|
||||
case 0x09:
|
||||
inter->ap = dc_fixpt_from_int(1);
|
||||
break;
|
||||
case 0x07:
|
||||
case 0x0e:
|
||||
case 0x0f:
|
||||
case 0x0b:
|
||||
case 0x0c:
|
||||
/* Unsupported audio format */
|
||||
return false;
|
||||
default:
|
||||
inter->ap = dc_fixpt_from_int(0);
|
||||
}
|
||||
|
||||
inter->r_ap = dc_fixpt_max(audio_bw_reserve, dc_fixpt_mul(params->f_audio, inter->ap));
|
||||
inter->r_ap = dc_fixpt_add(inter->r_ap, dc_fixpt_from_int(2 * ACR_RATE_MAX));
|
||||
max_audio_tol_rate = dc_fixpt_div_int(dc_fixpt_from_int(TOLERANCE_AUDIO_CLOCK), 1000000);
|
||||
max_audio_tol_rate = dc_fixpt_add(dc_fixpt_from_int(1), max_audio_tol_rate);
|
||||
inter->r_ap = dc_fixpt_mul(inter->r_ap, max_audio_tol_rate);
|
||||
|
||||
inter->avg_audio_packets_line = dc_fixpt_mul(inter->r_ap, inter->t_line);
|
||||
inter->avg_audio_packets_line = dc_fixpt_div_int(inter->avg_audio_packets_line, 1000000);
|
||||
inter->audio_packets_line = dc_fixpt_ceil(inter->avg_audio_packets_line);
|
||||
|
||||
inter->blank_audio_min = 32 + 32 * inter->audio_packets_line;
|
||||
|
||||
params->borrow_params.audio_packets_line = inter->audio_packets_line;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool frl_capacity_computations_uncompressed_video(struct frl_cap_chk_params_fixed31_32 *params,
|
||||
struct frl_cap_chk_intermediates_fixed31_32 *inter)
|
||||
{
|
||||
bool res;
|
||||
int k_420;
|
||||
struct fixed31_32 k_cd;
|
||||
struct fixed31_32 c_frl_free;
|
||||
int c_frl_free_int;
|
||||
int c_frl_rc_margin;
|
||||
struct fixed31_32 c_frl_rc_savings;
|
||||
int c_frl_rc_savings_int;
|
||||
int bpp;
|
||||
struct fixed31_32 bytes_line;
|
||||
int tb_active;
|
||||
int tb_blank;
|
||||
struct fixed31_32 f_tb_average;
|
||||
struct fixed31_32 t_active_ref;
|
||||
struct fixed31_32 t_blank_ref;
|
||||
struct fixed31_32 t_active_min;
|
||||
struct fixed31_32 t_blank_min;
|
||||
int c_frl_actual_payload;
|
||||
struct fixed31_32 utilization;
|
||||
|
||||
res = frl_capacity_computations_common(params, inter);
|
||||
if (res != true)
|
||||
return res;
|
||||
|
||||
k_420 = params->pixel_encoding == HDMI_FRL_PIXEL_ENCODING_420 ? 2 : 1;
|
||||
if (params->pixel_encoding == HDMI_FRL_PIXEL_ENCODING_422)
|
||||
k_cd = dc_fixpt_from_int(1);
|
||||
else
|
||||
k_cd = dc_fixpt_div_int(dc_fixpt_from_int(params->bpc), 8);
|
||||
|
||||
c_frl_free = dc_fixpt_div_int(dc_fixpt_mul_int(k_cd, params->h_blank), k_420);
|
||||
c_frl_free = dc_fixpt_sub_int(c_frl_free, 32 * (1 + inter->audio_packets_line) + 7);
|
||||
c_frl_free = dc_fixpt_max(c_frl_free, dc_fixpt_from_int(0));
|
||||
c_frl_free_int = dc_fixpt_ceil(c_frl_free);
|
||||
c_frl_rc_margin = 4;
|
||||
c_frl_rc_savings = dc_fixpt_mul_int(dc_fixpt_div_int(dc_fixpt_from_int(7), 8), c_frl_free_int);
|
||||
c_frl_rc_savings = dc_fixpt_sub_int(c_frl_rc_savings, c_frl_rc_margin);
|
||||
c_frl_rc_savings_int = dc_fixpt_floor(dc_fixpt_max(c_frl_rc_savings, dc_fixpt_from_int(0)));
|
||||
|
||||
bpp = dc_fixpt_ceil(dc_fixpt_mul_int(dc_fixpt_div_int(k_cd, k_420), 24));
|
||||
bytes_line = dc_fixpt_div_int(dc_fixpt_from_int(bpp * params->h_active), 8);
|
||||
tb_active = dc_fixpt_ceil(dc_fixpt_div_int(bytes_line, 3));
|
||||
tb_blank = dc_fixpt_ceil(dc_fixpt_div_int(dc_fixpt_mul_int(k_cd, params->h_blank), k_420));
|
||||
|
||||
if (!(inter->blank_audio_min <= tb_blank)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f_tb_average = dc_fixpt_div_int(inter->f_pixel_clock_max, (params->h_active + params->h_blank));
|
||||
f_tb_average = dc_fixpt_mul_int(f_tb_average, (tb_active + tb_blank));
|
||||
|
||||
t_active_ref = dc_fixpt_div(dc_fixpt_from_int(params->h_active), dc_fixpt_from_int(params->h_active + params->h_blank));
|
||||
t_active_ref = dc_fixpt_mul(inter->t_line, t_active_ref);
|
||||
|
||||
t_blank_ref = dc_fixpt_div(dc_fixpt_from_int(params->h_blank), dc_fixpt_from_int(params->h_active + params->h_blank));
|
||||
t_blank_ref = dc_fixpt_mul(inter->t_line, t_blank_ref);
|
||||
|
||||
t_active_min = dc_fixpt_sub(dc_fixpt_from_int(1), inter->overhead_max);
|
||||
t_active_min = dc_fixpt_mul(t_active_min, inter->r_frl_char_min);
|
||||
t_active_min = dc_fixpt_mul_int(t_active_min, params->lanes);
|
||||
t_active_min = dc_fixpt_div_int(t_active_min, 1000);
|
||||
t_blank_min = t_active_min;
|
||||
|
||||
t_active_min = dc_fixpt_div(dc_fixpt_mul_int(dc_fixpt_div(dc_fixpt_from_int(3), dc_fixpt_from_int(2)), tb_active), t_active_min);
|
||||
|
||||
t_blank_min = dc_fixpt_div(dc_fixpt_from_int(tb_blank), t_blank_min);
|
||||
|
||||
if (dc_fixpt_le(t_active_min, t_active_ref) && dc_fixpt_le(t_blank_min, t_blank_ref)) {
|
||||
params->borrow_params.borrow_mode = FRL_BORROW_MODE_NONE;
|
||||
} else if (dc_fixpt_lt(t_active_ref, t_active_min) && dc_fixpt_le(t_blank_min, t_blank_ref)) {
|
||||
params->borrow_params.borrow_mode = FRL_BORROW_MODE_FROM_BLANK;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
c_frl_actual_payload = dc_fixpt_ceil(dc_fixpt_mul_int(dc_fixpt_div(dc_fixpt_from_int(3), dc_fixpt_from_int(2)), tb_active)) + tb_blank - c_frl_rc_savings_int;
|
||||
|
||||
utilization = dc_fixpt_div(dc_fixpt_from_int(c_frl_actual_payload), inter->c_frl_line);
|
||||
utilization = dc_fixpt_mul_int(utilization, 1000);
|
||||
|
||||
inter->margin = dc_fixpt_sub(dc_fixpt_from_int(1), dc_fixpt_add(utilization, inter->overhead_max));
|
||||
|
||||
if (dc_fixpt_lt(inter->margin, dc_fixpt_from_int(0)) && dc_fixpt_lt(dc_fixpt_from_fraction(1, 100), dc_fixpt_abs(inter->margin)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t dp_get_timing_bandwidth_kbps(
|
||||
const struct dc_crtc_timing *timing,
|
||||
const struct dc_link *link)
|
||||
|
|
@ -331,6 +521,86 @@ static bool dp_validate_mode_timing(
|
|||
return false;
|
||||
}
|
||||
|
||||
bool frl_validate_mode_timing(
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing,
|
||||
struct dc_hdmi_frl_link_settings *frl_link_settings)
|
||||
{
|
||||
uint32_t req_bw;
|
||||
uint32_t max_bw;
|
||||
enum engine_id hpo_eng_id;
|
||||
unsigned int i;
|
||||
unsigned int hpo_frl_stream_enc_index = 0;
|
||||
bool frl_output_valid = false;
|
||||
|
||||
if (!link)
|
||||
return false;
|
||||
if (!link->local_sink)
|
||||
return false;
|
||||
|
||||
req_bw = dc_bandwidth_in_kbps_from_timing(timing, dc_link_get_highest_encoding_format(link));
|
||||
max_bw = frl_link_bandwidth_kbps(frl_link_settings->frl_link_rate);
|
||||
|
||||
/* Use Engine ID to determine which hpo stream
|
||||
* encoder should be used.
|
||||
*/
|
||||
if (link->connector_signal == SIGNAL_TYPE_VIRTUAL)
|
||||
frl_output_valid = true;
|
||||
else {
|
||||
struct audio_check audio_frl_check = {0};
|
||||
struct audio_info audio_info = {0};
|
||||
hpo_eng_id = ENGINE_ID_HPO_0;
|
||||
|
||||
for (i = 0; i < link->dc->res_pool->hpo_frl_stream_enc_count; i++) {
|
||||
if (link->dc->res_pool->hpo_frl_stream_enc[i]->id == hpo_eng_id) {
|
||||
hpo_frl_stream_enc_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*add audio check*/
|
||||
for (i = 0; i < (link->local_sink->edid_caps.audio_mode_count); i++) {
|
||||
audio_info.modes[i].channel_count = link->local_sink->edid_caps.audio_modes[i].channel_count;
|
||||
audio_info.modes[i].format_code = link->local_sink->edid_caps.audio_modes[i].format_code;
|
||||
audio_info.modes[i].sample_rates.all = link->local_sink->edid_caps.audio_modes[i].sample_rate;
|
||||
audio_info.modes[i].sample_size = link->local_sink->edid_caps.audio_modes[i].sample_size;
|
||||
}
|
||||
audio_info.mode_count = link->local_sink->edid_caps.audio_mode_count;
|
||||
get_audio_check(&audio_info, &audio_frl_check);
|
||||
|
||||
frl_output_valid =
|
||||
link->dc->res_pool->hpo_frl_stream_enc[hpo_frl_stream_enc_index]->funcs->validate_hdmi_frl_output(
|
||||
link->dc->res_pool->hpo_frl_stream_enc[hpo_frl_stream_enc_index],
|
||||
timing, &audio_frl_check,
|
||||
frl_link_settings,
|
||||
link->local_sink->edid_caps.frl_dsc_max_frl_rate);
|
||||
}
|
||||
|
||||
if (req_bw <= max_bw && frl_output_valid) {
|
||||
/* remember the biggest mode here, during
|
||||
* initial link training (to get
|
||||
* verified_link_cap), LS sends event about
|
||||
* cannot train at reported cap to upper
|
||||
* layer and upper layer will re-enumerate modes.
|
||||
* this is not necessary if the lower
|
||||
* verified_link_cap is enough to drive
|
||||
* all the modes
|
||||
*/
|
||||
|
||||
/* TODO: DYNAMIC_VALIDATION needs to be implemented */
|
||||
/* if (flags.DYNAMIC_VALIDATION == 1)
|
||||
* dpsst->max_req_bw_for_verified_linkcap = dal_max(
|
||||
* dpsst->max_req_bw_for_verified_linkcap, req_bw);
|
||||
*/
|
||||
return true;
|
||||
} else if (frl_output_valid && timing->dsc_cfg.is_frl) {
|
||||
/* HDMI DSC calculation is validated within frl_output_valid
|
||||
* and req_bw may exceed max_bw
|
||||
*/
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
enum dc_status link_validate_mode_timing(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
|
|
@ -345,6 +615,15 @@ enum dc_status link_validate_mode_timing(
|
|||
if (link->remote_sinks[0] && link->remote_sinks[0]->sink_signal == SIGNAL_TYPE_VIRTUAL)
|
||||
return DC_OK;
|
||||
|
||||
/* If DSC is supported, but native 422 DSC is not supported,
|
||||
* HDMI 2.1a specification requires that all 422 format be disabled (7.7.1)
|
||||
*/
|
||||
if (dc_is_hdmi_signal(stream->signal)) {
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 && link->dc->config.no_native422_support) {
|
||||
return DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Passive Dongle */
|
||||
if (max_pix_clk != 0 && get_tmds_output_pixel_clock_100hz(timing) > max_pix_clk)
|
||||
return DC_EXCEED_DONGLE_CAP;
|
||||
|
|
@ -362,6 +641,25 @@ enum dc_status link_validate_mode_timing(
|
|||
return DC_NO_DP_LINK_BANDWIDTH;
|
||||
break;
|
||||
|
||||
case SIGNAL_TYPE_HDMI_FRL:
|
||||
{
|
||||
uint32_t pxl_clk_mhz;
|
||||
/* Limit pixel clock to DTBCLK Limit (Base Pix > 4 * DTBCLK) */
|
||||
pxl_clk_mhz = (timing->pix_clk_100hz + 10000 - 1) / 10000 ;
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
|
||||
pxl_clk_mhz /= 2;
|
||||
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
|
||||
pxl_clk_mhz = pxl_clk_mhz * 2 / 3;
|
||||
if (pxl_clk_mhz > DTBCLK_LIMIT && link->ctx->dce_version < DCN_VERSION_3_1)
|
||||
return DC_NO_HDMI_FRL_LINK_BANDWIDTH;
|
||||
}
|
||||
|
||||
if (!frl_validate_mode_timing(
|
||||
link,
|
||||
timing,
|
||||
hdmi_frl_get_verified_link_cap(link)))
|
||||
return DC_NO_HDMI_FRL_LINK_BANDWIDTH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#define __LINK_VALIDATION_H__
|
||||
#include "link_service.h"
|
||||
|
||||
#define TOLERANCE_AUDIO_CLOCK 1000
|
||||
|
||||
enum dc_status link_validate_mode_timing(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
|
|
@ -33,9 +35,20 @@ enum dc_status link_validate_mode_timing(
|
|||
enum dc_status link_validate_dp_tunnel_bandwidth(
|
||||
const struct dc *dc,
|
||||
const struct dc_state *new_ctx);
|
||||
bool frl_validate_mode_timing(
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing,
|
||||
struct dc_hdmi_frl_link_settings *frl_link_settings);
|
||||
uint32_t dp_link_bandwidth_kbps(
|
||||
const struct dc_link *link,
|
||||
const struct dc_link_settings *link_settings);
|
||||
uint32_t frl_link_bandwidth_kbps(enum hdmi_frl_link_rate link_rate);
|
||||
uint32_t link_timing_bandwidth_kbps(const struct dc_crtc_timing *timing);
|
||||
bool frl_capacity_computations_common(struct frl_cap_chk_params_fixed31_32 *params,
|
||||
struct frl_cap_chk_intermediates_fixed31_32 *inter);
|
||||
bool frl_capacity_computations_uncompressed_video(
|
||||
struct frl_cap_chk_params_fixed31_32 *params,
|
||||
struct frl_cap_chk_intermediates_fixed31_32 *inter);
|
||||
|
||||
|
||||
uint32_t dp_required_hblank_size_bytes(
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
* link training.
|
||||
*/
|
||||
#include "link_ddc.h"
|
||||
#include "link_hdmi_frl.h"
|
||||
#include "vector.h"
|
||||
#include "dce/dce_aux.h"
|
||||
#include "dal_asic_id.h"
|
||||
|
|
@ -560,6 +561,8 @@ void write_scdc_data(struct ddc_service *ddc_service,
|
|||
(ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite ||
|
||||
!ddc_service->link->local_sink->edid_caps.scdc_present))
|
||||
return;
|
||||
hdmi_frl_LTS_clear_Link_Setting(ddc_service);
|
||||
hdmi_frl_LTS_clear_Update_flag(ddc_service);
|
||||
|
||||
link_query_ddc_data(ddc_service, slave_address, &offset,
|
||||
sizeof(offset), &sink_version, sizeof(sink_version));
|
||||
|
|
@ -610,3 +613,90 @@ void read_scdc_data(struct ddc_service *ddc_service)
|
|||
sizeof(status_data.byte));
|
||||
}
|
||||
}
|
||||
void write_idcc_data(struct ddc_service *ddc_service, enum hdmi_idcc_scope idcc_scope,
|
||||
uint8_t *write_buf, uint8_t offset, uint8_t write_len)
|
||||
{
|
||||
uint8_t slave_address = HDMI_IDCC_ADDRESS;
|
||||
uint8_t idcc_header[5] = {0};
|
||||
uint8_t dummy_buf[1] = {0};
|
||||
uint8_t checksum = 0;
|
||||
int i;
|
||||
|
||||
idcc_header[0] = HDMI_IDCC_MARKER0;
|
||||
idcc_header[1] = HDMI_IDCC_MARKER1;
|
||||
idcc_header[2] = (uint8_t)(HDMI_IDCC_MARKER2 | idcc_scope);
|
||||
idcc_header[3] = offset;
|
||||
idcc_header[4] = write_len;
|
||||
|
||||
/* Write the IDCC header */
|
||||
for (i = 0; i < sizeof(idcc_header); ++i) {
|
||||
link_query_ddc_data(ddc_service, slave_address,
|
||||
&idcc_header[i], 1,
|
||||
&dummy_buf[0], 1);
|
||||
checksum += idcc_header[i];
|
||||
}
|
||||
|
||||
/* Write the payload */
|
||||
for (i = 0; i < write_len; ++i) {
|
||||
link_query_ddc_data(ddc_service, slave_address,
|
||||
&write_buf[i], 1,
|
||||
&dummy_buf[0], 1);
|
||||
checksum += write_buf[i];
|
||||
}
|
||||
|
||||
/* Write the checksum */
|
||||
if (write_len > 0) {
|
||||
checksum = 0xff - checksum + 1;
|
||||
link_query_ddc_data(ddc_service, slave_address,
|
||||
&checksum, 1,
|
||||
&dummy_buf[0], 1);
|
||||
}
|
||||
}
|
||||
|
||||
int read_idcc_data(struct ddc_service *ddc_service, enum hdmi_idcc_scope idcc_scope,
|
||||
uint8_t *read_buf, uint8_t offset, uint8_t read_len)
|
||||
{
|
||||
uint8_t slave_address = HDMI_IDCC_ADDRESS;
|
||||
uint8_t idcc_header[5] = {0};
|
||||
uint8_t dummy_buf[1] = {0};
|
||||
uint8_t read_buf_local[6] = {0};
|
||||
uint8_t checksum = 0;
|
||||
int i;
|
||||
|
||||
idcc_header[0] = HDMI_IDCC_MARKER0;
|
||||
idcc_header[1] = HDMI_IDCC_MARKER1;
|
||||
idcc_header[2] = (uint8_t)(HDMI_IDCC_MARKER2 | idcc_scope);
|
||||
idcc_header[3] = offset;
|
||||
idcc_header[4] = read_len;
|
||||
|
||||
/* Write the IDCC header */
|
||||
for (i = 0; i < sizeof(idcc_header); ++i) {
|
||||
link_query_ddc_data(ddc_service, slave_address,
|
||||
&idcc_header[i], 1,
|
||||
&dummy_buf[0], 1);
|
||||
checksum += idcc_header[i];
|
||||
}
|
||||
|
||||
/* Read the payload */
|
||||
if (read_len > 0) {
|
||||
dummy_buf[0] = 0x01;
|
||||
if (read_len > 5)
|
||||
read_len = 5;
|
||||
link_query_ddc_data(ddc_service, slave_address,
|
||||
&dummy_buf[0], 1,
|
||||
&read_buf_local[0], read_len + 1);
|
||||
|
||||
memcpy(read_buf, read_buf_local, read_len);
|
||||
|
||||
/* Check checksum */
|
||||
checksum = read_buf_local[read_len];
|
||||
for (i = 0; i < 5; ++i)
|
||||
checksum += idcc_header[i];
|
||||
for (i = 0; i < read_len; ++i)
|
||||
checksum += read_buf_local[i];
|
||||
if (checksum != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ void write_scdc_data(
|
|||
void read_scdc_data(
|
||||
struct ddc_service *ddc_service);
|
||||
|
||||
void write_idcc_data(struct ddc_service *ddc_service, enum hdmi_idcc_scope idcc_scope,
|
||||
uint8_t *write_buf, uint8_t offset, uint8_t write_len);
|
||||
int read_idcc_data(struct ddc_service *ddc_service, enum hdmi_idcc_scope idcc_scope,
|
||||
uint8_t *read_buf, uint8_t offset, uint8_t read_len);
|
||||
void set_dongle_type(struct ddc_service *ddc,
|
||||
enum display_dongle_type dongle_type);
|
||||
|
||||
|
|
|
|||
1128
drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c
Normal file
1128
drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef __LINK_HDMI_FRL_H__
|
||||
#define __LINK_HDMI_FRL_H__
|
||||
#include "link_service.h"
|
||||
enum clock_source_id hdmi_frl_find_matching_phypll(
|
||||
struct dc_link *link);
|
||||
void hdmi_frl_LTS_clear_Update_flag(struct ddc_service *ddc_service);
|
||||
void hdmi_frl_poll_start(struct ddc_service *ddc_service);
|
||||
void hdmi_frl_LTS_clear_Link_Setting(struct ddc_service *ddc_service);
|
||||
void hdmi_frl_retrieve_link_cap(struct dc_link *link, struct dc_sink *sink);
|
||||
enum link_result hdmi_frl_perform_link_training_with_retries(
|
||||
struct dc_link *link);
|
||||
enum link_result hdmi_frl_perform_link_training_with_fallback(
|
||||
struct dc_link *link, struct link_resource *link_res,
|
||||
enum clock_source_id frl_phy_clock_source_id);
|
||||
void hdmi_frl_verify_link_cap(struct dc_link *link,
|
||||
struct dc_hdmi_frl_link_settings *known_limit_link_setting);
|
||||
void hdmi_frl_decide_link_settings(struct dc_stream_state *stream,
|
||||
struct dc_hdmi_frl_link_settings *frl_link_settings,
|
||||
struct dsc_padding_params *dsc_paddding_params);
|
||||
bool hdmi_frl_poll_status_flag(struct dc_link *link);
|
||||
struct dc_hdmi_frl_link_settings *hdmi_frl_get_verified_link_cap(
|
||||
struct dc_link *link);
|
||||
void hdmi_frl_set_preferred_link_settings(struct dc *dc,
|
||||
struct dc_hdmi_frl_link_settings *link_setting,
|
||||
struct dc_hdmi_frl_link_training_overrides *lt_overrides,
|
||||
struct dc_link *link);
|
||||
void hdmi_frl_write_read_request_enable(
|
||||
struct ddc_service *ddc_service);
|
||||
#endif /* __LINK_HDMI_FRL_H__ */
|
||||
|
|
@ -80,6 +80,7 @@ bool program_hpd_filter(const struct dc_link *link)
|
|||
case SIGNAL_TYPE_DVI_SINGLE_LINK:
|
||||
case SIGNAL_TYPE_DVI_DUAL_LINK:
|
||||
case SIGNAL_TYPE_HDMI_TYPE_A:
|
||||
case SIGNAL_TYPE_HDMI_FRL:
|
||||
/* Program hpd filter */
|
||||
delay_on_connect_in_ms = 500;
|
||||
delay_on_disconnect_in_ms = 100;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user