drm/amd/display: break down dc_link.c
[why] dc_link contains over 30k line of code, the decision is to break it down to files residing in link folder based on functionality. This change is the last break down change which will remove dc_link.c file after everything is broken down. [how] Move remaining dc_link.c functions into link_detection, link_dpms, link_validation, link_resource, and link_fpga and remove dc_link. Reviewed-by: George Shen <George.Shen@amd.com> Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com> Signed-off-by: Wenjing Liu <wenjing.liu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
71d7e8904d
commit
54618888d1
@ -1283,7 +1283,7 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
|
||||
dc_link = aconnector->dc_link;
|
||||
|
||||
mutex_lock(&aconnector->hpd_lock);
|
||||
if (!dc_link_detect_sink(dc_link, &new_connection_type))
|
||||
if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
|
||||
DRM_ERROR("KMS: Failed to detect connector\n");
|
||||
mutex_unlock(&aconnector->hpd_lock);
|
||||
|
||||
@ -1334,7 +1334,7 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
|
||||
offload_work->offload_wq->is_handling_link_loss = false;
|
||||
spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
|
||||
|
||||
if ((dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) &&
|
||||
if ((dc_link_dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) &&
|
||||
dc_link_check_link_loss_status(dc_link, &irq_data))
|
||||
dc_link_dp_handle_link_loss(dc_link);
|
||||
}
|
||||
@ -2777,7 +2777,7 @@ static int dm_resume(void *handle)
|
||||
continue;
|
||||
|
||||
mutex_lock(&aconnector->hpd_lock);
|
||||
if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
|
||||
if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
|
||||
DRM_ERROR("KMS: Failed to detect connector\n");
|
||||
|
||||
if (aconnector->base.force && new_connection_type == dc_connection_none) {
|
||||
@ -3118,7 +3118,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
|
||||
|
||||
aconnector->timing_changed = false;
|
||||
|
||||
if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
|
||||
if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
|
||||
DRM_ERROR("KMS: Failed to detect connector\n");
|
||||
|
||||
if (aconnector->base.force && new_connection_type == dc_connection_none) {
|
||||
@ -3321,7 +3321,7 @@ static void handle_hpd_rx_irq(void *param)
|
||||
out:
|
||||
if (result && !is_mst_root_connector) {
|
||||
/* Downstream Port status changed. */
|
||||
if (!dc_link_detect_sink(dc_link, &new_connection_type))
|
||||
if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
|
||||
DRM_ERROR("KMS: Failed to detect connector\n");
|
||||
|
||||
if (aconnector->base.force && new_connection_type == dc_connection_none) {
|
||||
@ -4370,7 +4370,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
|
||||
link = dc_get_link_at_index(dm->dc, i);
|
||||
|
||||
if (!dc_link_detect_sink(link, &new_connection_type))
|
||||
if (!dc_link_detect_connection_type(link, &new_connection_type))
|
||||
DRM_ERROR("KMS: Failed to detect connector\n");
|
||||
|
||||
if (aconnector->base.force && new_connection_type == dc_connection_none) {
|
||||
|
@ -1257,7 +1257,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
|
||||
|
||||
if (param[0] == 1) {
|
||||
|
||||
if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type) &&
|
||||
if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type) &&
|
||||
new_connection_type != dc_connection_none)
|
||||
goto unlock;
|
||||
|
||||
@ -1294,7 +1294,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
|
||||
|
||||
/* If the aconnector is the root node in mst topology */
|
||||
if (aconnector->mst_mgr.mst_state == true)
|
||||
reset_cur_dp_mst_topology(link);
|
||||
dc_link_reset_cur_dp_mst_topology(link);
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
dm_restore_drm_connector_state(dev, connector);
|
||||
|
@ -1104,7 +1104,7 @@ bool dm_helpers_dp_handle_test_pattern_request(
|
||||
pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
|
||||
pipe_ctx->stream->timing.pixel_encoding = requestPixelEncoding;
|
||||
|
||||
dp_update_dsc_config(pipe_ctx);
|
||||
dc_link_update_dsc_config(pipe_ctx);
|
||||
|
||||
aconnector->timing_changed = true;
|
||||
/* store current timing */
|
||||
|
@ -50,7 +50,7 @@
|
||||
#include "dc/dcn20/dcn20_resource.h"
|
||||
bool is_timing_changed(struct dc_stream_state *cur_stream,
|
||||
struct dc_stream_state *new_stream);
|
||||
|
||||
#define PEAK_FACTOR_X1000 1006
|
||||
|
||||
static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
|
@ -64,7 +64,7 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI
|
||||
|
||||
include $(AMD_DC)
|
||||
|
||||
DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
|
||||
DISPLAY_CORE = dc.o dc_stat.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
|
||||
dc_surface.o dc_debug.o dc_stream.o dc_link_enc_cfg.o
|
||||
|
||||
DISPLAY_CORE += dc_vm_helper.o
|
||||
|
@ -1199,7 +1199,7 @@ static void disable_vbios_mode_if_required(
|
||||
pipe->stream_res.pix_clk_params.requested_pix_clk_100hz;
|
||||
|
||||
if (pix_clk_100hz != requested_pix_clk_100hz) {
|
||||
core_link_disable_stream(pipe);
|
||||
link_set_dpms_off(pipe);
|
||||
pipe->stream->dpms_off = false;
|
||||
}
|
||||
}
|
||||
@ -1307,7 +1307,7 @@ static void detect_edp_presence(struct dc *dc)
|
||||
if (dc->config.edp_not_connected) {
|
||||
edp_link->edp_sink_present = false;
|
||||
} else {
|
||||
dc_link_detect_sink(edp_link, &type);
|
||||
dc_link_detect_connection_type(edp_link, &type);
|
||||
edp_link->edp_sink_present = (type != dc_connection_none);
|
||||
}
|
||||
}
|
||||
@ -3173,7 +3173,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
|
||||
dc->hwss.update_info_frame(pipe_ctx);
|
||||
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
|
||||
link_dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
|
||||
}
|
||||
|
||||
if (stream_update->hdr_static_metadata &&
|
||||
@ -3209,14 +3209,14 @@ static void commit_planes_do_stream_update(struct dc *dc,
|
||||
continue;
|
||||
|
||||
if (stream_update->dsc_config)
|
||||
dp_update_dsc_config(pipe_ctx);
|
||||
link_update_dsc_config(pipe_ctx);
|
||||
|
||||
if (stream_update->mst_bw_update) {
|
||||
if (stream_update->mst_bw_update->is_increase)
|
||||
dc_link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
|
||||
else
|
||||
dc_link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
|
||||
}
|
||||
link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
|
||||
else
|
||||
link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
|
||||
}
|
||||
|
||||
if (stream_update->pending_test_pattern) {
|
||||
dc_link_dp_set_test_pattern(stream->link,
|
||||
@ -3229,7 +3229,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
|
||||
|
||||
if (stream_update->dpms_off) {
|
||||
if (*stream_update->dpms_off) {
|
||||
core_link_disable_stream(pipe_ctx);
|
||||
link_set_dpms_off(pipe_ctx);
|
||||
/* for dpms, keep acquired resources*/
|
||||
if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only)
|
||||
pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
|
||||
@ -3239,7 +3239,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
|
||||
} else {
|
||||
if (get_seamless_boot_stream_count(context) == 0)
|
||||
dc->hwss.prepare_bandwidth(dc, dc->current_state);
|
||||
core_link_enable_stream(dc->current_state, pipe_ctx);
|
||||
link_set_dpms_on(dc->current_state, pipe_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4305,7 +4305,7 @@ void dc_resume(struct dc *dc)
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < dc->link_count; i++)
|
||||
core_link_resume(dc->links[i]);
|
||||
link_resume(dc->links[i]);
|
||||
}
|
||||
|
||||
bool dc_is_dmcu_initialized(struct dc *dc)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3685,7 +3685,7 @@ enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
|
||||
/* TODO: validate audio ASIC caps, encoder */
|
||||
|
||||
if (res == DC_OK)
|
||||
res = dc_link_validate_mode_timing(stream,
|
||||
res = link_validate_mode_timing(stream,
|
||||
link,
|
||||
&stream->timing);
|
||||
|
||||
|
@ -384,11 +384,6 @@ bool dc_link_setup_psr(struct dc_link *dc_link,
|
||||
const struct dc_stream_state *stream, struct psr_config *psr_config,
|
||||
struct psr_context *psr_context);
|
||||
|
||||
void dc_link_blank_all_dp_displays(struct dc *dc);
|
||||
void dc_link_blank_all_edp_displays(struct dc *dc);
|
||||
|
||||
void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init);
|
||||
|
||||
/* Request DC to detect if there is a Panel connected.
|
||||
* boot - If this call is during initial boot.
|
||||
* Return false for any type of detection failure or MST detection
|
||||
@ -407,9 +402,6 @@ enum dc_detect_reason {
|
||||
|
||||
bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason);
|
||||
bool dc_link_get_hpd_state(struct dc_link *dc_link);
|
||||
enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx);
|
||||
enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
|
||||
enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
|
||||
|
||||
/* Notify DC about DP RX Interrupt (aka Short Pulse Interrupt).
|
||||
* Return:
|
||||
@ -432,8 +424,8 @@ void dc_link_dp_handle_automated_test(struct dc_link *link);
|
||||
void dc_link_dp_handle_link_loss(struct dc_link *link);
|
||||
bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link);
|
||||
bool dc_link_check_link_loss_status(struct dc_link *link,
|
||||
union hpd_irq_data *hpd_irq_dpcd_data);
|
||||
enum dc_status dp_read_hpd_rx_irq_data(
|
||||
union hpd_irq_data *hpd_irq_dpcd_data);
|
||||
enum dc_status dc_link_dp_read_hpd_rx_irq_data(
|
||||
struct dc_link *link,
|
||||
union hpd_irq_data *irq_data);
|
||||
struct dc_sink_init_data;
|
||||
@ -479,7 +471,7 @@ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable);
|
||||
|
||||
bool dc_link_is_dp_sink_present(struct dc_link *link);
|
||||
|
||||
bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type);
|
||||
bool dc_link_detect_connection_type(struct dc_link *link, enum dc_connection_type *type);
|
||||
/*
|
||||
* DPCD access interfaces
|
||||
*/
|
||||
@ -561,7 +553,7 @@ struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
|
||||
unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
|
||||
|
||||
/* Destruct the mst topology of the link and reset the allocated payload table */
|
||||
bool reset_cur_dp_mst_topology(struct dc_link *link);
|
||||
bool dc_link_reset_cur_dp_mst_topology(struct dc_link *link);
|
||||
|
||||
/* Attempt to transfer the given aux payload. This function does not perform
|
||||
* retries or handle error states. The reply is returned in the payload->reply
|
||||
@ -581,55 +573,6 @@ bool dc_link_decide_edp_link_settings(struct dc_link *link,
|
||||
void dc_link_edp_panel_backlight_power_on(struct dc_link *link,
|
||||
bool wait_for_hpd);
|
||||
|
||||
#define LINK_TRAINING_ATTEMPTS 4
|
||||
#define LINK_TRAINING_RETRY_DELAY 50 /* ms */
|
||||
#define MAX_MTP_SLOT_COUNT 64
|
||||
#define TRAINING_AUX_RD_INTERVAL 100 //us
|
||||
#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX.
|
||||
|
||||
struct dc_link;
|
||||
struct dc_stream_state;
|
||||
struct dc_link_settings;
|
||||
|
||||
enum {
|
||||
/*
|
||||
* Some receivers fail to train on first try and are good
|
||||
* on subsequent tries. 2 retries should be plenty. If we
|
||||
* don't have a successful training then we don't expect to
|
||||
* ever get one.
|
||||
*/
|
||||
LINK_TRAINING_MAX_VERIFY_RETRY = 2,
|
||||
PEAK_FACTOR_X1000 = 1006,
|
||||
};
|
||||
|
||||
bool dp_validate_mode_timing(
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing);
|
||||
|
||||
void dp_enable_mst_on_sink(struct dc_link *link, bool enable);
|
||||
|
||||
enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready);
|
||||
void dp_set_fec_enable(struct dc_link *link, bool enable);
|
||||
bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update);
|
||||
void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx);
|
||||
bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
|
||||
bool dpcd_write_128b_132b_sst_payload_allocation_table(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
struct link_mst_stream_allocation_table *proposed_table,
|
||||
bool allocate);
|
||||
|
||||
bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link);
|
||||
|
||||
struct fixed31_32 calculate_sst_avg_time_slots_per_mtp(
|
||||
const struct dc_stream_state *stream,
|
||||
const struct dc_link *link);
|
||||
void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
|
||||
|
||||
/*
|
||||
* USB4 DPIA BW ALLOCATION PUBLIC FUNCTIONS
|
||||
*/
|
||||
@ -657,4 +600,8 @@ void dc_link_set_usb4_req_bw_req(struct dc_link *link, int req_bw);
|
||||
*/
|
||||
void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result);
|
||||
|
||||
/* TODO: this is not meant to be exposed to DM. Should switch to stream update
|
||||
* interface i.e stream_update->dsc_config
|
||||
*/
|
||||
bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx);
|
||||
#endif /* DC_LINK_H_ */
|
||||
|
@ -1566,10 +1566,10 @@ static enum dc_status apply_single_controller_ctx_to_hw(
|
||||
pipe_ctx->stream_res.tg->inst);
|
||||
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
|
||||
|
||||
if (!stream->dpms_off)
|
||||
core_link_enable_stream(context, pipe_ctx);
|
||||
link_set_dpms_on(context, pipe_ctx);
|
||||
|
||||
/* DCN3.1 FPGA Workaround
|
||||
* Need to enable HPO DP Stream Encoder before setting OTG master enable.
|
||||
@ -1602,7 +1602,7 @@ static void power_down_encoders(struct dc *dc)
|
||||
for (i = 0; i < dc->link_count; i++) {
|
||||
enum signal_type signal = dc->links[i]->connector_signal;
|
||||
|
||||
dc_link_blank_dp_stream(dc->links[i], false);
|
||||
link_blank_dp_stream(dc->links[i], false);
|
||||
|
||||
if (signal != SIGNAL_TYPE_EDP)
|
||||
signal = SIGNAL_TYPE_NONE;
|
||||
@ -2085,7 +2085,7 @@ static void dce110_reset_hw_ctx_wrap(
|
||||
* disabled already, no need to disable again.
|
||||
*/
|
||||
if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) {
|
||||
core_link_disable_stream(pipe_ctx_old);
|
||||
link_set_dpms_off(pipe_ctx_old);
|
||||
|
||||
/* free acquired resources*/
|
||||
if (pipe_ctx_old->stream_res.audio) {
|
||||
@ -3079,7 +3079,7 @@ void dce110_enable_dp_link_output(
|
||||
if (dmcu != NULL && dmcu->funcs->unlock_phy)
|
||||
dmcu->funcs->unlock_phy(dmcu);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
|
||||
}
|
||||
|
||||
void dce110_disable_link_output(struct dc_link *link,
|
||||
@ -3104,7 +3104,7 @@ void dce110_disable_link_output(struct dc_link *link,
|
||||
link->dc->hwss.edp_power_control(link, false);
|
||||
else if (dmcu != NULL && dmcu->funcs->lock_phy)
|
||||
dmcu->funcs->unlock_phy(dmcu);
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
|
||||
}
|
||||
|
||||
static const struct hw_sequencer_funcs dce110_funcs = {
|
||||
|
@ -1017,7 +1017,7 @@ static void dcn10_reset_back_end_for_pipe(
|
||||
* VBIOS lit up eDP, so check link status too.
|
||||
*/
|
||||
if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
|
||||
core_link_disable_stream(pipe_ctx);
|
||||
link_set_dpms_off(pipe_ctx);
|
||||
else if (pipe_ctx->stream_res.audio)
|
||||
dc->hwss.disable_audio_stream(pipe_ctx);
|
||||
|
||||
@ -1564,7 +1564,7 @@ void dcn10_init_hw(struct dc *dc)
|
||||
}
|
||||
|
||||
/* we want to turn off all dp displays before doing detection */
|
||||
dc_link_blank_all_dp_displays(dc);
|
||||
link_blank_all_dp_displays(dc);
|
||||
|
||||
if (hws->funcs.enable_power_gating_plane)
|
||||
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
|
||||
|
@ -933,7 +933,7 @@ void enc1_stream_encoder_dp_blank(
|
||||
/* disable DP stream */
|
||||
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM);
|
||||
|
||||
/* the encoder stops sending the video stream
|
||||
* at the start of the vertical blanking.
|
||||
@ -952,7 +952,7 @@ void enc1_stream_encoder_dp_blank(
|
||||
|
||||
REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, true);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET);
|
||||
}
|
||||
|
||||
/* output video stream to link encoder */
|
||||
@ -1025,7 +1025,7 @@ void enc1_stream_encoder_dp_unblank(
|
||||
|
||||
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
}
|
||||
|
||||
void enc1_stream_encoder_set_avmute(
|
||||
|
@ -2449,7 +2449,7 @@ static void dcn20_reset_back_end_for_pipe(
|
||||
* VBIOS lit up eDP, so check link status too.
|
||||
*/
|
||||
if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
|
||||
core_link_disable_stream(pipe_ctx);
|
||||
link_set_dpms_off(pipe_ctx);
|
||||
else if (pipe_ctx->stream_res.audio)
|
||||
dc->hwss.disable_audio_stream(pipe_ctx);
|
||||
|
||||
@ -2469,7 +2469,7 @@ static void dcn20_reset_back_end_for_pipe(
|
||||
}
|
||||
}
|
||||
else if (pipe_ctx->stream_res.dsc) {
|
||||
dp_set_dsc_enable(pipe_ctx, false);
|
||||
link_set_dsc_enable(pipe_ctx, false);
|
||||
}
|
||||
|
||||
/* by upper caller loop, parent pipe: pipe0, will be reset last.
|
||||
@ -2743,7 +2743,7 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
|
||||
dc->hwss.update_info_frame(pipe_ctx);
|
||||
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
|
||||
|
||||
/* enable early control to avoid corruption on DP monitor*/
|
||||
active_total_with_borders =
|
||||
|
@ -546,7 +546,7 @@ void enc2_stream_encoder_dp_unblank(
|
||||
|
||||
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
}
|
||||
|
||||
static void enc2_dp_set_odm_combine(
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "hw/clk_mgr.h"
|
||||
#include "dc_dmub_srv.h"
|
||||
#include "abm.h"
|
||||
|
||||
#include "link.h"
|
||||
|
||||
#define DC_LOGGER_INIT(logger)
|
||||
|
||||
@ -132,8 +132,8 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx)
|
||||
return;
|
||||
|
||||
pipe_ctx->stream->dpms_off = false;
|
||||
core_link_enable_stream(context, pipe_ctx);
|
||||
core_link_disable_stream(pipe_ctx);
|
||||
link_set_dpms_on(context, pipe_ctx);
|
||||
link_set_dpms_off(pipe_ctx);
|
||||
pipe_ctx->stream->dpms_off = true;
|
||||
}
|
||||
|
||||
|
@ -539,7 +539,7 @@ void dcn30_init_hw(struct dc *dc)
|
||||
hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
|
||||
|
||||
/* we want to turn off all dp displays before doing detection */
|
||||
dc_link_blank_all_dp_displays(dc);
|
||||
link_blank_all_dp_displays(dc);
|
||||
|
||||
if (hws->funcs.enable_power_gating_plane)
|
||||
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
|
||||
|
@ -202,7 +202,7 @@ void dcn31_init_hw(struct dc *dc)
|
||||
dmub_enable_outbox_notification(dc->ctx->dmub_srv);
|
||||
|
||||
/* we want to turn off all dp displays before doing detection */
|
||||
dc_link_blank_all_dp_displays(dc);
|
||||
link_blank_all_dp_displays(dc);
|
||||
|
||||
if (hws->funcs.enable_power_gating_plane)
|
||||
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
|
||||
@ -230,7 +230,7 @@ void dcn31_init_hw(struct dc *dc)
|
||||
}
|
||||
|
||||
if (num_opps > 1) {
|
||||
dc_link_blank_all_edp_displays(dc);
|
||||
link_blank_all_edp_displays(dc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -565,7 +565,7 @@ static void dcn31_reset_back_end_for_pipe(
|
||||
* VBIOS lit up eDP, so check link status too.
|
||||
*/
|
||||
if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
|
||||
core_link_disable_stream(pipe_ctx);
|
||||
link_set_dpms_off(pipe_ctx);
|
||||
else if (pipe_ctx->stream_res.audio)
|
||||
dc->hwss.disable_audio_stream(pipe_ctx);
|
||||
|
||||
@ -584,7 +584,7 @@ static void dcn31_reset_back_end_for_pipe(
|
||||
}
|
||||
}
|
||||
} else if (pipe_ctx->stream_res.dsc) {
|
||||
dp_set_dsc_enable(pipe_ctx, false);
|
||||
link_set_dsc_enable(pipe_ctx, false);
|
||||
}
|
||||
|
||||
pipe_ctx->stream = NULL;
|
||||
|
@ -366,7 +366,7 @@ static void enc314_stream_encoder_dp_unblank(
|
||||
*/
|
||||
enc314_enable_fifo(enc);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
}
|
||||
|
||||
/* Set DSC-related configuration.
|
||||
|
@ -373,7 +373,7 @@ static void enc32_stream_encoder_dp_unblank(
|
||||
|
||||
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
|
||||
}
|
||||
|
||||
/* Set DSC-related configuration.
|
||||
|
@ -792,7 +792,7 @@ void dcn32_init_hw(struct dc *dc)
|
||||
hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
|
||||
|
||||
/* we want to turn off all dp displays before doing detection */
|
||||
dc_link_blank_all_dp_displays(dc);
|
||||
link_blank_all_dp_displays(dc);
|
||||
|
||||
/* If taking control over from VBIOS, we may want to optimize our first
|
||||
* mode set, so we need to skip powering down pipes until we know which
|
||||
@ -1252,7 +1252,7 @@ void dcn32_disable_link_output(struct dc_link *link,
|
||||
else if (dmcu != NULL && dmcu->funcs->lock_phy)
|
||||
dmcu->funcs->unlock_phy(dmcu);
|
||||
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
|
||||
|
||||
apply_symclk_on_tx_off_wa(link);
|
||||
}
|
||||
|
@ -56,33 +56,6 @@ void enable_surface_flip_reporting(struct dc_plane_state *plane_state,
|
||||
#endif
|
||||
#include "link_hwss.h"
|
||||
|
||||
/************ link *****************/
|
||||
struct link_init_data {
|
||||
const struct dc *dc;
|
||||
struct dc_context *ctx; /* TODO: remove 'dal' when DC is complete. */
|
||||
uint32_t connector_index; /* this will be mapped to the HPD pins */
|
||||
uint32_t link_index; /* this is mapped to DAL display_index
|
||||
TODO: remove it when DC is complete. */
|
||||
bool is_dpia_link;
|
||||
};
|
||||
|
||||
struct dc_link *link_create(const struct link_init_data *init_params);
|
||||
void link_destroy(struct dc_link **link);
|
||||
|
||||
enum dc_status dc_link_validate_mode_timing(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing);
|
||||
|
||||
void core_link_resume(struct dc_link *link);
|
||||
|
||||
void core_link_enable_stream(
|
||||
struct dc_state *state,
|
||||
struct pipe_ctx *pipe_ctx);
|
||||
|
||||
void core_link_disable_stream(struct pipe_ctx *pipe_ctx);
|
||||
|
||||
void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
|
||||
/********** DAL Core*********************/
|
||||
#include "transform.h"
|
||||
#include "dpp.h"
|
||||
|
@ -40,6 +40,19 @@
|
||||
#include "core_types.h"
|
||||
#include "dc_link.h"
|
||||
|
||||
struct link_init_data {
|
||||
const struct dc *dc;
|
||||
struct dc_context *ctx; /* TODO: remove 'dal' when DC is complete. */
|
||||
uint32_t connector_index; /* this will be mapped to the HPD pins */
|
||||
uint32_t link_index; /* this is mapped to DAL display_index
|
||||
TODO: remove it when DC is complete. */
|
||||
bool is_dpia_link;
|
||||
};
|
||||
|
||||
struct dc_link *link_create(const struct link_init_data *init_params);
|
||||
void link_destroy(struct dc_link **link);
|
||||
|
||||
// TODO - convert any function declarations below to function pointers
|
||||
struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
|
||||
struct graphics_object_id link_id,
|
||||
struct gpio_service *gpio_service);
|
||||
@ -105,5 +118,22 @@ bool link_power_alpm_dpcd_enable(struct dc_link *link, bool enable);
|
||||
bool link_set_sink_vtotal_in_psr_active(const struct dc_link *link,
|
||||
uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);
|
||||
void link_get_psr_residency(const struct dc_link *link, uint32_t *residency);
|
||||
|
||||
enum dc_status link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
|
||||
enum dc_status link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
|
||||
void link_blank_all_dp_displays(struct dc *dc);
|
||||
void link_blank_all_edp_displays(struct dc *dc);
|
||||
void link_blank_dp_stream(struct dc_link *link, bool hw_init);
|
||||
void link_resume(struct dc_link *link);
|
||||
void link_set_dpms_on(
|
||||
struct dc_state *state,
|
||||
struct pipe_ctx *pipe_ctx);
|
||||
void link_set_dpms_off(struct pipe_ctx *pipe_ctx);
|
||||
void link_dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
|
||||
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);
|
||||
enum dc_status link_validate_mode_timing(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing);
|
||||
#endif /* __DC_LINK_HPD_H__ */
|
||||
|
@ -23,10 +23,17 @@
|
||||
# It abstracts the control and status of back end pipe such as DIO, HPO, DPIA,
|
||||
# PHY, HPD, DDC and etc).
|
||||
|
||||
LINK = link_detection.o link_dpms.o link_factory.o link_resource.o \
|
||||
link_validation.o
|
||||
|
||||
AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/, \
|
||||
$(LINK))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_LINK)
|
||||
###############################################################################
|
||||
# accessories
|
||||
###############################################################################
|
||||
LINK_ACCESSORIES = link_dp_trace.o link_dp_cts.o
|
||||
LINK_ACCESSORIES = link_dp_trace.o link_dp_cts.o link_fpga.o
|
||||
|
||||
AMD_DAL_LINK_ACCESSORIES = $(addprefix $(AMDDALPATH)/dc/link/accessories/, \
|
||||
$(LINK_ACCESSORIES))
|
||||
|
@ -88,7 +88,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
|
||||
pipe->stream->link == link &&
|
||||
!pipe->stream->dpms_off &&
|
||||
!pipe->top_pipe && !pipe->prev_odm_pipe) {
|
||||
core_link_disable_stream(pipe);
|
||||
link_set_dpms_off(pipe);
|
||||
pipe->link_config.dp_link_settings = *link_setting;
|
||||
update_dp_encoder_resources_for_test_harness(
|
||||
link->dc,
|
||||
@ -103,7 +103,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
|
||||
pipe->stream->link == link &&
|
||||
!pipe->stream->dpms_off &&
|
||||
!pipe->top_pipe && !pipe->prev_odm_pipe) {
|
||||
core_link_enable_stream(
|
||||
link_set_dpms_on(
|
||||
pipe->stream->ctx->dc->current_state,
|
||||
pipe);
|
||||
}
|
||||
|
@ -22,8 +22,8 @@
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
#include "dc_link.h"
|
||||
#include "link_dp_trace.h"
|
||||
#include "link/protocols/link_dpcd.h"
|
||||
|
||||
void dp_trace_init(struct dc_link *link)
|
||||
{
|
||||
@ -164,3 +164,10 @@ uint64_t link_dp_trace_get_edp_poweroff_timestamp(struct dc_link *link)
|
||||
{
|
||||
return link->dp_trace.edp_trace_power_timestamps.poweroff;
|
||||
}
|
||||
|
||||
void link_dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode)
|
||||
{
|
||||
if (link != NULL && link->dc->debug.enable_driver_sequence_debug)
|
||||
core_link_write_dpcd(link, DP_SOURCE_SEQUENCE,
|
||||
&dp_test_mode, sizeof(dp_test_mode));
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
#ifndef __LINK_DP_TRACE_H__
|
||||
#define __LINK_DP_TRACE_H__
|
||||
#include "link.h"
|
||||
|
||||
void dp_trace_init(struct dc_link *link);
|
||||
void dp_trace_reset(struct dc_link *link);
|
||||
|
95
drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.c
Normal file
95
drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#include "link_fpga.h"
|
||||
#include "link/link_dpms.h"
|
||||
#include "dm_helpers.h"
|
||||
#include "link_hwss.h"
|
||||
#include "dccg.h"
|
||||
#include "resource.h"
|
||||
|
||||
#define DC_LOGGER_INIT(logger)
|
||||
|
||||
void dp_fpga_hpo_enable_link_and_stream(struct dc_state *state, struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
struct dc *dc = pipe_ctx->stream->ctx->dc;
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct link_mst_stream_allocation_table proposed_table = {0};
|
||||
struct fixed31_32 avg_time_slots_per_mtp;
|
||||
uint8_t req_slot_count = 0;
|
||||
uint8_t vc_id = 1; /// VC ID always 1 for SST
|
||||
struct dc_link_settings link_settings = pipe_ctx->link_config.dp_link_settings;
|
||||
const struct link_hwss *link_hwss = get_link_hwss(stream->link, &pipe_ctx->link_res);
|
||||
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
|
||||
|
||||
stream->link->cur_link_settings = link_settings;
|
||||
|
||||
if (link_hwss->ext.enable_dp_link_output)
|
||||
link_hwss->ext.enable_dp_link_output(stream->link, &pipe_ctx->link_res,
|
||||
stream->signal, pipe_ctx->clock_source->id,
|
||||
&link_settings);
|
||||
|
||||
/* Enable DP_STREAM_ENC */
|
||||
dc->hwss.enable_stream(pipe_ctx);
|
||||
|
||||
/* Set DPS PPS SDP (AKA "info frames") */
|
||||
if (pipe_ctx->stream->timing.flags.DSC) {
|
||||
link_set_dsc_pps_packet(pipe_ctx, true, true);
|
||||
}
|
||||
|
||||
/* Allocate Payload */
|
||||
if ((stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) && (state->stream_count > 1)) {
|
||||
// MST case
|
||||
uint8_t i;
|
||||
|
||||
proposed_table.stream_count = state->stream_count;
|
||||
for (i = 0; i < state->stream_count; i++) {
|
||||
avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(state->streams[i], state->streams[i]->link);
|
||||
req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
|
||||
proposed_table.stream_allocations[i].slot_count = req_slot_count;
|
||||
proposed_table.stream_allocations[i].vcp_id = i+1;
|
||||
/* NOTE: This makes assumption that pipe_ctx index is same as stream index */
|
||||
proposed_table.stream_allocations[i].hpo_dp_stream_enc = state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc;
|
||||
}
|
||||
} else {
|
||||
// SST case
|
||||
avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(stream, stream->link);
|
||||
req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
|
||||
proposed_table.stream_count = 1; /// Always 1 stream for SST
|
||||
proposed_table.stream_allocations[0].slot_count = req_slot_count;
|
||||
proposed_table.stream_allocations[0].vcp_id = vc_id;
|
||||
proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
|
||||
}
|
||||
|
||||
link_hwss->ext.update_stream_allocation_table(stream->link,
|
||||
&pipe_ctx->link_res,
|
||||
&proposed_table);
|
||||
|
||||
if (link_hwss->ext.set_throttled_vcp_size)
|
||||
link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
|
||||
|
||||
dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
|
||||
dc->hwss.enable_audio_stream(pipe_ctx);
|
||||
}
|
||||
|
30
drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.h
Normal file
30
drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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_FPGA_H__
|
||||
#define __LINK_FPGA_H__
|
||||
#include "link.h"
|
||||
void dp_fpga_hpo_enable_link_and_stream(struct dc_state *state,
|
||||
struct pipe_ctx *pipe_ctx);
|
||||
#endif /* __LINK_FPGA_H__ */
|
@ -44,7 +44,7 @@ void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
|
||||
link_enc->funcs->connect_dig_be_to_fe(link_enc,
|
||||
pipe_ctx->stream_res.stream_enc->id, true);
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
link_dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
|
||||
if (stream_enc->funcs->enable_fifo)
|
||||
stream_enc->funcs->enable_fifo(stream_enc);
|
||||
@ -63,7 +63,7 @@ void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
|
||||
pipe_ctx->stream_res.stream_enc->id,
|
||||
false);
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
link_dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
|
||||
|
||||
}
|
||||
@ -105,7 +105,7 @@ void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx)
|
||||
&stream->timing);
|
||||
|
||||
if (dc_is_dp_signal(stream->signal))
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
|
||||
}
|
||||
|
||||
void enable_dio_dp_link_output(struct dc_link *link,
|
||||
@ -126,7 +126,7 @@ void enable_dio_dp_link_output(struct dc_link *link,
|
||||
link_enc,
|
||||
link_settings,
|
||||
clock_source);
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
|
||||
}
|
||||
|
||||
void disable_dio_link_output(struct dc_link *link,
|
||||
@ -136,7 +136,7 @@ void disable_dio_link_output(struct dc_link *link,
|
||||
struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
|
||||
|
||||
link_enc->funcs->disable_output(link_enc, signal);
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
|
||||
}
|
||||
|
||||
void set_dio_dp_link_test_pattern(struct dc_link *link,
|
||||
@ -146,7 +146,7 @@ void set_dio_dp_link_test_pattern(struct dc_link *link,
|
||||
struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
|
||||
|
||||
link_enc->funcs->dp_set_phy_pattern(link_enc, tp_params);
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
|
||||
}
|
||||
|
||||
void set_dio_dp_lane_settings(struct dc_link *link,
|
||||
@ -195,7 +195,7 @@ void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
|
||||
pipe_ctx->stream_res.stream_enc, false);
|
||||
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
link_dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
|
||||
}
|
||||
|
||||
@ -214,7 +214,7 @@ void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
|
||||
}
|
||||
|
||||
if (dc_is_dp_signal(pipe_ctx->stream->signal))
|
||||
dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
link_dp_source_sequence_trace(pipe_ctx->stream->link,
|
||||
DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
|
||||
stream->use_vsc_sdp_for_colorimetry,
|
||||
stream->timing.flags.DSC,
|
||||
false);
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
|
||||
}
|
||||
|
||||
static void enable_hpo_dp_fpga_link_output(struct dc_link *link,
|
||||
@ -201,7 +201,7 @@ static void set_hpo_dp_link_test_pattern(struct dc_link *link,
|
||||
{
|
||||
link_res->hpo_dp_link_enc->funcs->set_link_test_pattern(
|
||||
link_res->hpo_dp_link_enc, tp_params);
|
||||
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
|
||||
link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
|
||||
}
|
||||
|
||||
static void set_hpo_dp_lane_settings(struct dc_link *link,
|
||||
|
1356
drivers/gpu/drm/amd/display/dc/link/link_detection.c
Normal file
1356
drivers/gpu/drm/amd/display/dc/link/link_detection.c
Normal file
File diff suppressed because it is too large
Load Diff
30
drivers/gpu/drm/amd/display/dc/link/link_detection.h
Normal file
30
drivers/gpu/drm/amd/display/dc/link/link_detection.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 __DC_LINK_DETECTION_H__
|
||||
#define __DC_LINK_DETECTION_H__
|
||||
#include "link.h"
|
||||
|
||||
#endif /* __DC_LINK_DETECTION_H__ */
|
2395
drivers/gpu/drm/amd/display/dc/link/link_dpms.c
Normal file
2395
drivers/gpu/drm/amd/display/dc/link/link_dpms.c
Normal file
File diff suppressed because it is too large
Load Diff
35
drivers/gpu/drm/amd/display/dc/link/link_dpms.h
Normal file
35
drivers/gpu/drm/amd/display/dc/link/link_dpms.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 __DC_LINK_DPMS_H__
|
||||
#define __DC_LINK_DPMS_H__
|
||||
|
||||
#include "link.h"
|
||||
bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx,
|
||||
bool enable, bool immediate_update);
|
||||
struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp(
|
||||
const struct dc_stream_state *stream,
|
||||
const struct dc_link *link);
|
||||
#endif /* __DC_LINK_DPMS_H__ */
|
577
drivers/gpu/drm/amd/display/dc/link/link_factory.c
Normal file
577
drivers/gpu/drm/amd/display/dc/link/link_factory.c
Normal file
@ -0,0 +1,577 @@
|
||||
/*
|
||||
* 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 "protocols/link_ddc.h"
|
||||
#include "protocols/link_edp_panel_control.h"
|
||||
#include "protocols/link_hpd.h"
|
||||
#include "gpio_service_interface.h"
|
||||
#include "atomfirmware.h"
|
||||
|
||||
#define DC_LOGGER_INIT(logger)
|
||||
|
||||
#define LINK_INFO(...) \
|
||||
DC_LOG_HW_HOTPLUG( \
|
||||
__VA_ARGS__)
|
||||
|
||||
static enum 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void 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) {
|
||||
/* 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->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]);
|
||||
}
|
||||
|
||||
static enum channel_id get_ddc_line(struct dc_link *link)
|
||||
{
|
||||
struct ddc *ddc;
|
||||
enum channel_id channel;
|
||||
|
||||
channel = CHANNEL_ID_UNKNOWN;
|
||||
|
||||
ddc = get_ddc_pin(link->ddc);
|
||||
|
||||
if (ddc) {
|
||||
switch (dal_ddc_get_line(ddc)) {
|
||||
case GPIO_DDC_LINE_DDC1:
|
||||
channel = CHANNEL_ID_DDC1;
|
||||
break;
|
||||
case GPIO_DDC_LINE_DDC2:
|
||||
channel = CHANNEL_ID_DDC2;
|
||||
break;
|
||||
case GPIO_DDC_LINE_DDC3:
|
||||
channel = CHANNEL_ID_DDC3;
|
||||
break;
|
||||
case GPIO_DDC_LINE_DDC4:
|
||||
channel = CHANNEL_ID_DDC4;
|
||||
break;
|
||||
case GPIO_DDC_LINE_DDC5:
|
||||
channel = CHANNEL_ID_DDC5;
|
||||
break;
|
||||
case GPIO_DDC_LINE_DDC6:
|
||||
channel = CHANNEL_ID_DDC6;
|
||||
break;
|
||||
case GPIO_DDC_LINE_DDC_VGA:
|
||||
channel = CHANNEL_ID_DDC_VGA;
|
||||
break;
|
||||
case GPIO_DDC_LINE_I2C_PAD:
|
||||
channel = CHANNEL_ID_I2C_PAD;
|
||||
break;
|
||||
default:
|
||||
BREAK_TO_DEBUGGER();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
static bool dc_link_construct_phy(struct dc_link *link,
|
||||
const struct link_init_data *init_params)
|
||||
{
|
||||
uint8_t i;
|
||||
struct ddc_service_init_data ddc_service_init_data = { 0 };
|
||||
struct dc_context *dc_ctx = init_params->ctx;
|
||||
struct encoder_init_data enc_init_data = { 0 };
|
||||
struct panel_cntl_init_data panel_cntl_init_data = { 0 };
|
||||
struct integrated_info info = { 0 };
|
||||
struct dc_bios *bios = init_params->dc->ctx->dc_bios;
|
||||
const struct dc_vbios_funcs *bp_funcs = bios->funcs;
|
||||
struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 };
|
||||
|
||||
DC_LOGGER_INIT(dc_ctx->logger);
|
||||
|
||||
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
|
||||
link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
|
||||
link->link_status.dpcd_caps = &link->dpcd_caps;
|
||||
|
||||
link->dc = init_params->dc;
|
||||
link->ctx = dc_ctx;
|
||||
link->link_index = init_params->link_index;
|
||||
|
||||
memset(&link->preferred_training_settings, 0,
|
||||
sizeof(struct dc_link_training_overrides));
|
||||
memset(&link->preferred_link_setting, 0,
|
||||
sizeof(struct dc_link_settings));
|
||||
|
||||
link->link_id =
|
||||
bios->funcs->get_connector_id(bios, init_params->connector_index);
|
||||
|
||||
link->ep_type = DISPLAY_ENDPOINT_PHY;
|
||||
|
||||
DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);
|
||||
|
||||
if (bios->funcs->get_disp_connector_caps_info) {
|
||||
bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);
|
||||
link->is_internal_display = disp_connect_caps_info.INTERNAL_DISPLAY;
|
||||
DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);
|
||||
}
|
||||
|
||||
if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
|
||||
dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n",
|
||||
__func__, init_params->connector_index,
|
||||
link->link_id.type, OBJECT_TYPE_CONNECTOR);
|
||||
goto create_fail;
|
||||
}
|
||||
|
||||
if (link->dc->res_pool->funcs->link_init)
|
||||
link->dc->res_pool->funcs->link_init(link);
|
||||
|
||||
link->hpd_gpio = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
|
||||
link->ctx->gpio_service);
|
||||
|
||||
if (link->hpd_gpio) {
|
||||
dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT);
|
||||
dal_gpio_unlock_pin(link->hpd_gpio);
|
||||
link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio);
|
||||
|
||||
DC_LOG_DC("BIOS object table - hpd_gpio id: %d", link->hpd_gpio->id);
|
||||
DC_LOG_DC("BIOS object table - hpd_gpio en: %d", link->hpd_gpio->en);
|
||||
}
|
||||
|
||||
switch (link->link_id.id) {
|
||||
case CONNECTOR_ID_HDMI_TYPE_A:
|
||||
link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
|
||||
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_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:
|
||||
link->connector_signal = SIGNAL_TYPE_EDP;
|
||||
|
||||
if (link->hpd_gpio) {
|
||||
if (!link->dc->config.allow_edp_hotplug_detection)
|
||||
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
|
||||
|
||||
switch (link->dc->config.allow_edp_hotplug_detection) {
|
||||
case 1: // only the 1st eDP handles hotplug
|
||||
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 2: // only the 2nd eDP handles hotplug
|
||||
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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case CONNECTOR_ID_LVDS:
|
||||
link->connector_signal = SIGNAL_TYPE_LVDS;
|
||||
break;
|
||||
default:
|
||||
DC_LOG_WARNING("Unsupported Connector type:%d!\n",
|
||||
link->link_id.id);
|
||||
goto create_fail;
|
||||
}
|
||||
|
||||
/* TODO: #DAL3 Implement id to str function.*/
|
||||
LINK_INFO("Connector[%d] description:"
|
||||
"signal %d\n",
|
||||
init_params->connector_index,
|
||||
link->connector_signal);
|
||||
|
||||
ddc_service_init_data.ctx = link->ctx;
|
||||
ddc_service_init_data.id = link->link_id;
|
||||
ddc_service_init_data.link = link;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!link->ddc->ddc_pin) {
|
||||
DC_ERROR("Failed to get I2C info for connector!\n");
|
||||
goto ddc_create_fail;
|
||||
}
|
||||
|
||||
link->ddc_hw_inst =
|
||||
dal_ddc_get_line(get_ddc_pin(link->ddc));
|
||||
|
||||
|
||||
if (link->dc->res_pool->funcs->panel_cntl_create &&
|
||||
(link->link_id.id == CONNECTOR_ID_EDP ||
|
||||
link->link_id.id == CONNECTOR_ID_LVDS)) {
|
||||
panel_cntl_init_data.ctx = dc_ctx;
|
||||
panel_cntl_init_data.inst =
|
||||
panel_cntl_init_data.ctx->dc_edp_id_count;
|
||||
link->panel_cntl =
|
||||
link->dc->res_pool->funcs->panel_cntl_create(
|
||||
&panel_cntl_init_data);
|
||||
panel_cntl_init_data.ctx->dc_edp_id_count++;
|
||||
|
||||
if (link->panel_cntl == NULL) {
|
||||
DC_ERROR("Failed to create link panel_cntl!\n");
|
||||
goto panel_cntl_create_fail;
|
||||
}
|
||||
}
|
||||
|
||||
enc_init_data.ctx = dc_ctx;
|
||||
bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0,
|
||||
&enc_init_data.encoder);
|
||||
enc_init_data.connector = link->link_id;
|
||||
enc_init_data.channel = get_ddc_line(link);
|
||||
enc_init_data.hpd_source = get_hpd_line(link);
|
||||
|
||||
link->hpd_src = enc_init_data.hpd_source;
|
||||
|
||||
enc_init_data.transmitter =
|
||||
translate_encoder_to_transmitter(enc_init_data.encoder);
|
||||
link->link_enc =
|
||||
link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);
|
||||
|
||||
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);
|
||||
|
||||
if (!link->link_enc) {
|
||||
DC_ERROR("Failed to create link encoder!\n");
|
||||
goto link_enc_create_fail;
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
|
||||
link->link_enc_hw_inst = link->link_enc->transmitter;
|
||||
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 tyes
|
||||
*/
|
||||
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;
|
||||
|
||||
DC_LOG_DC("BIOS object table - device_tag.acpi_device: %d", link->device_tag.acpi_device);
|
||||
DC_LOG_DC("BIOS object table - device_tag.dev_id.device_type: %d", link->device_tag.dev_id.device_type);
|
||||
DC_LOG_DC("BIOS object table - device_tag.dev_id.enum_id: %d", link->device_tag.dev_id.enum_id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bios->integrated_info)
|
||||
info = *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 =
|
||||
&info.ext_disp_conn_info.path[i];
|
||||
|
||||
if (path->device_connector_id.enum_id == link->link_id.enum_id &&
|
||||
path->device_connector_id.id == link->link_id.id &&
|
||||
path->device_connector_id.type == link->link_id.type) {
|
||||
if (link->device_tag.acpi_device != 0 &&
|
||||
path->device_acpi_enum == link->device_tag.acpi_device) {
|
||||
link->ddi_channel_mapping = path->channel_mapping;
|
||||
link->chip_caps = path->caps;
|
||||
DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
|
||||
DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
|
||||
} else if (path->device_tag ==
|
||||
link->device_tag.dev_id.raw_device_tag) {
|
||||
link->ddi_channel_mapping = path->channel_mapping;
|
||||
link->chip_caps = path->caps;
|
||||
DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
|
||||
DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
|
||||
}
|
||||
|
||||
if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) {
|
||||
link->bios_forced_drive_settings.VOLTAGE_SWING =
|
||||
(info.ext_disp_conn_info.fixdpvoltageswing & 0x3);
|
||||
link->bios_forced_drive_settings.PRE_EMPHASIS =
|
||||
((info.ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
link->psr_settings.psr_vtotal_control_support = false;
|
||||
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
|
||||
|
||||
DC_LOG_DC("BIOS object table - dc_link_contruct finished successfully.\n");
|
||||
return true;
|
||||
device_tag_fail:
|
||||
link->link_enc->funcs->destroy(&link->link_enc);
|
||||
link_enc_create_fail:
|
||||
if (link->panel_cntl != NULL)
|
||||
link->panel_cntl->funcs->destroy(&link->panel_cntl);
|
||||
panel_cntl_create_fail:
|
||||
link_destroy_ddc_service(&link->ddc);
|
||||
ddc_create_fail:
|
||||
create_fail:
|
||||
|
||||
if (link->hpd_gpio) {
|
||||
dal_gpio_destroy_irq(&link->hpd_gpio);
|
||||
link->hpd_gpio = NULL;
|
||||
}
|
||||
|
||||
DC_LOG_DC("BIOS object table - dc_link_contruct failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool dc_link_construct_dpia(struct dc_link *link,
|
||||
const struct link_init_data *init_params)
|
||||
{
|
||||
struct ddc_service_init_data ddc_service_init_data = { 0 };
|
||||
struct dc_context *dc_ctx = init_params->ctx;
|
||||
|
||||
DC_LOGGER_INIT(dc_ctx->logger);
|
||||
|
||||
/* Initialized irq source for hpd and hpd rx */
|
||||
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
|
||||
link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
|
||||
link->link_status.dpcd_caps = &link->dpcd_caps;
|
||||
|
||||
link->dc = init_params->dc;
|
||||
link->ctx = dc_ctx;
|
||||
link->link_index = init_params->link_index;
|
||||
|
||||
memset(&link->preferred_training_settings, 0,
|
||||
sizeof(struct dc_link_training_overrides));
|
||||
memset(&link->preferred_link_setting, 0,
|
||||
sizeof(struct dc_link_settings));
|
||||
|
||||
/* Dummy Init for linkid */
|
||||
link->link_id.type = OBJECT_TYPE_CONNECTOR;
|
||||
link->link_id.id = CONNECTOR_ID_DISPLAY_PORT;
|
||||
link->link_id.enum_id = ENUM_ID_1 + init_params->connector_index;
|
||||
link->is_internal_display = false;
|
||||
link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
|
||||
LINK_INFO("Connector[%d] description:signal %d\n",
|
||||
init_params->connector_index,
|
||||
link->connector_signal);
|
||||
|
||||
link->ep_type = DISPLAY_ENDPOINT_USB4_DPIA;
|
||||
link->is_dig_mapping_flexible = true;
|
||||
|
||||
/* TODO: Initialize link : funcs->link_init */
|
||||
|
||||
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;
|
||||
|
||||
/* TODO: Create link encoder */
|
||||
|
||||
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
|
||||
|
||||
/* Some docks seem to NAK I2C writes to segment pointer with mot=0. */
|
||||
link->wa_flags.dp_mot_reset_segment = true;
|
||||
|
||||
return true;
|
||||
|
||||
ddc_create_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool link_construct(struct dc_link *link,
|
||||
const struct link_init_data *init_params)
|
||||
{
|
||||
/* Handle dpia case */
|
||||
if (init_params->is_dpia_link == true)
|
||||
return dc_link_construct_dpia(link, init_params);
|
||||
else
|
||||
return dc_link_construct_phy(link, init_params);
|
||||
}
|
||||
|
||||
struct dc_link *link_create(const struct link_init_data *init_params)
|
||||
{
|
||||
struct dc_link *link =
|
||||
kzalloc(sizeof(*link), GFP_KERNEL);
|
||||
|
||||
if (NULL == link)
|
||||
goto alloc_fail;
|
||||
|
||||
if (false == link_construct(link, init_params))
|
||||
goto construct_fail;
|
||||
|
||||
return link;
|
||||
|
||||
construct_fail:
|
||||
kfree(link);
|
||||
|
||||
alloc_fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void link_destroy(struct dc_link **link)
|
||||
{
|
||||
link_destruct(*link);
|
||||
kfree(*link);
|
||||
*link = NULL;
|
||||
}
|
||||
|
29
drivers/gpu/drm/amd/display/dc/link/link_factory.h
Normal file
29
drivers/gpu/drm/amd/display/dc/link/link_factory.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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_FACTORY_H__
|
||||
#define __LINK_FACTORY_H__
|
||||
#include "link.h"
|
||||
|
||||
#endif /* __LINK_FACTORY_H__ */
|
149
drivers/gpu/drm/amd/display/dc/link/link_resource.c
Normal file
149
drivers/gpu/drm/amd/display/dc/link/link_resource.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 implements accessors to link resource.
|
||||
*/
|
||||
|
||||
#include "link_resource.h"
|
||||
#include "protocols/link_dp_capability.h"
|
||||
|
||||
void dc_link_get_cur_link_res(const struct dc_link *link,
|
||||
struct link_resource *link_res)
|
||||
{
|
||||
int i;
|
||||
struct pipe_ctx *pipe = NULL;
|
||||
|
||||
memset(link_res, 0, sizeof(*link_res));
|
||||
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe->stream && pipe->stream->link && pipe->top_pipe == NULL) {
|
||||
if (pipe->stream->link == link) {
|
||||
*link_res = pipe->link_res;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_get_cur_link_res_map() - take a snapshot of current link resource allocation state
|
||||
* @dc: pointer to dc of the dm calling this
|
||||
* @map: a dc link resource snapshot defined internally to dc.
|
||||
*
|
||||
* DM needs to capture a snapshot of current link resource allocation mapping
|
||||
* and store it in its persistent storage.
|
||||
*
|
||||
* Some of the link resource is using first come first serve policy.
|
||||
* The allocation mapping depends on original hotplug order. This information
|
||||
* is lost after driver is loaded next time. The snapshot is used in order to
|
||||
* restore link resource to its previous state so user will get consistent
|
||||
* link capability allocation across reboot.
|
||||
*
|
||||
* Return: none (void function)
|
||||
*
|
||||
*/
|
||||
void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
|
||||
{
|
||||
struct dc_link *link;
|
||||
uint32_t i;
|
||||
uint32_t hpo_dp_recycle_map = 0;
|
||||
|
||||
*map = 0;
|
||||
|
||||
if (dc->caps.dp_hpo) {
|
||||
for (i = 0; i < dc->caps.max_links; i++) {
|
||||
link = dc->links[i];
|
||||
if (link->link_status.link_active &&
|
||||
link_dp_get_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING &&
|
||||
link_dp_get_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING)
|
||||
/* hpo dp link encoder is considered as recycled, when RX reports 128b/132b encoding capability
|
||||
* but current link doesn't use it.
|
||||
*/
|
||||
hpo_dp_recycle_map |= (1 << i);
|
||||
}
|
||||
*map |= (hpo_dp_recycle_map << LINK_RES_HPO_DP_REC_MAP__SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_restore_link_res_map() - restore link resource allocation state from a snapshot
|
||||
* @dc: pointer to dc of the dm calling this
|
||||
* @map: a dc link resource snapshot defined internally to dc.
|
||||
*
|
||||
* DM needs to call this function after initial link detection on boot and
|
||||
* before first commit streams to restore link resource allocation state
|
||||
* from previous boot session.
|
||||
*
|
||||
* Some of the link resource is using first come first serve policy.
|
||||
* The allocation mapping depends on original hotplug order. This information
|
||||
* is lost after driver is loaded next time. The snapshot is used in order to
|
||||
* restore link resource to its previous state so user will get consistent
|
||||
* link capability allocation across reboot.
|
||||
*
|
||||
* Return: none (void function)
|
||||
*
|
||||
*/
|
||||
void dc_restore_link_res_map(const struct dc *dc, uint32_t *map)
|
||||
{
|
||||
struct dc_link *link;
|
||||
uint32_t i;
|
||||
unsigned int available_hpo_dp_count;
|
||||
uint32_t hpo_dp_recycle_map = (*map & LINK_RES_HPO_DP_REC_MAP__MASK)
|
||||
>> LINK_RES_HPO_DP_REC_MAP__SHIFT;
|
||||
|
||||
if (dc->caps.dp_hpo) {
|
||||
available_hpo_dp_count = dc->res_pool->hpo_dp_link_enc_count;
|
||||
/* remove excess 128b/132b encoding support for not recycled links */
|
||||
for (i = 0; i < dc->caps.max_links; i++) {
|
||||
if ((hpo_dp_recycle_map & (1 << i)) == 0) {
|
||||
link = dc->links[i];
|
||||
if (link->type != dc_connection_none &&
|
||||
link_dp_get_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) {
|
||||
if (available_hpo_dp_count > 0)
|
||||
available_hpo_dp_count--;
|
||||
else
|
||||
/* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */
|
||||
link->verified_link_cap.link_rate = LINK_RATE_HIGH3;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* remove excess 128b/132b encoding support for recycled links */
|
||||
for (i = 0; i < dc->caps.max_links; i++) {
|
||||
if ((hpo_dp_recycle_map & (1 << i)) != 0) {
|
||||
link = dc->links[i];
|
||||
if (link->type != dc_connection_none &&
|
||||
link_dp_get_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) {
|
||||
if (available_hpo_dp_count > 0)
|
||||
available_hpo_dp_count--;
|
||||
else
|
||||
/* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */
|
||||
link->verified_link_cap.link_rate = LINK_RATE_HIGH3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
drivers/gpu/drm/amd/display/dc/link/link_resource.h
Normal file
29
drivers/gpu/drm/amd/display/dc/link/link_resource.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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_RESOURCE_H__
|
||||
#define __LINK_RESOURCE_H__
|
||||
#include "link.h"
|
||||
|
||||
#endif /* __LINK_RESOURCE_H__ */
|
396
drivers/gpu/drm/amd/display/dc/link/link_validation.c
Normal file
396
drivers/gpu/drm/amd/display/dc/link/link_validation.c
Normal file
@ -0,0 +1,396 @@
|
||||
/*
|
||||
* 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 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.
|
||||
*/
|
||||
#include "link_validation.h"
|
||||
#include "resource.h"
|
||||
|
||||
#define DC_LOGGER_INIT(logger)
|
||||
|
||||
static uint32_t get_tmds_output_pixel_clock_100hz(const struct dc_crtc_timing *timing)
|
||||
{
|
||||
|
||||
uint32_t pxl_clk = timing->pix_clk_100hz;
|
||||
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
|
||||
pxl_clk /= 2;
|
||||
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
|
||||
pxl_clk = pxl_clk * 2 / 3;
|
||||
|
||||
if (timing->display_color_depth == COLOR_DEPTH_101010)
|
||||
pxl_clk = pxl_clk * 10 / 8;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_121212)
|
||||
pxl_clk = pxl_clk * 12 / 8;
|
||||
|
||||
return pxl_clk;
|
||||
}
|
||||
|
||||
static bool dp_active_dongle_validate_timing(
|
||||
const struct dc_crtc_timing *timing,
|
||||
const struct dpcd_caps *dpcd_caps)
|
||||
{
|
||||
const struct dc_dongle_caps *dongle_caps = &dpcd_caps->dongle_caps;
|
||||
|
||||
switch (dpcd_caps->dongle_type) {
|
||||
case DISPLAY_DONGLE_DP_VGA_CONVERTER:
|
||||
case DISPLAY_DONGLE_DP_DVI_CONVERTER:
|
||||
case DISPLAY_DONGLE_DP_DVI_DONGLE:
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_RGB)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER &&
|
||||
dongle_caps->extendedCapValid == true) {
|
||||
/* Check Pixel Encoding */
|
||||
switch (timing->pixel_encoding) {
|
||||
case PIXEL_ENCODING_RGB:
|
||||
case PIXEL_ENCODING_YCBCR444:
|
||||
break;
|
||||
case PIXEL_ENCODING_YCBCR422:
|
||||
if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through)
|
||||
return false;
|
||||
break;
|
||||
case PIXEL_ENCODING_YCBCR420:
|
||||
if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
/* Invalid Pixel Encoding*/
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (timing->display_color_depth) {
|
||||
case COLOR_DEPTH_666:
|
||||
case COLOR_DEPTH_888:
|
||||
/*888 and 666 should always be supported*/
|
||||
break;
|
||||
case COLOR_DEPTH_101010:
|
||||
if (dongle_caps->dp_hdmi_max_bpc < 10)
|
||||
return false;
|
||||
break;
|
||||
case COLOR_DEPTH_121212:
|
||||
if (dongle_caps->dp_hdmi_max_bpc < 12)
|
||||
return false;
|
||||
break;
|
||||
case COLOR_DEPTH_141414:
|
||||
case COLOR_DEPTH_161616:
|
||||
default:
|
||||
/* These color depths are currently not supported */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check 3D format */
|
||||
switch (timing->timing_3d_format) {
|
||||
case TIMING_3D_FORMAT_NONE:
|
||||
case TIMING_3D_FORMAT_FRAME_ALTERNATE:
|
||||
/*Only frame alternate 3D is supported on active dongle*/
|
||||
break;
|
||||
default:
|
||||
/*other 3D formats are not supported due to bad infoframe translation */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter
|
||||
struct dc_crtc_timing outputTiming = *timing;
|
||||
|
||||
if (timing->flags.DSC && !timing->dsc_cfg.is_frl)
|
||||
/* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */
|
||||
outputTiming.flags.DSC = 0;
|
||||
if (dc_bandwidth_in_kbps_from_timing(&outputTiming) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps)
|
||||
return false;
|
||||
} else { // DP to HDMI TMDS converter
|
||||
if (get_tmds_output_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dpcd_caps->channel_coding_cap.bits.DP_128b_132b_SUPPORTED == 0 &&
|
||||
dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT == 0 &&
|
||||
dongle_caps->dfp_cap_ext.supported) {
|
||||
|
||||
if (dongle_caps->dfp_cap_ext.max_pixel_rate_in_mps < (timing->pix_clk_100hz / 10000))
|
||||
return false;
|
||||
|
||||
if (dongle_caps->dfp_cap_ext.max_video_h_active_width < timing->h_addressable)
|
||||
return false;
|
||||
|
||||
if (dongle_caps->dfp_cap_ext.max_video_v_active_height < timing->v_addressable)
|
||||
return false;
|
||||
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_RGB) {
|
||||
if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
|
||||
return false;
|
||||
if (timing->display_color_depth == COLOR_DEPTH_666 &&
|
||||
!dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_6bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_888 &&
|
||||
!dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_8bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
|
||||
!dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_10bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
|
||||
!dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_12bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
|
||||
!dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_16bpc)
|
||||
return false;
|
||||
} else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
|
||||
if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
|
||||
return false;
|
||||
if (timing->display_color_depth == COLOR_DEPTH_888 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_8bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_10bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_12bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_16bpc)
|
||||
return false;
|
||||
} else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
|
||||
if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
|
||||
return false;
|
||||
if (timing->display_color_depth == COLOR_DEPTH_888 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_8bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_10bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_12bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_16bpc)
|
||||
return false;
|
||||
} else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
|
||||
if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
|
||||
return false;
|
||||
if (timing->display_color_depth == COLOR_DEPTH_888 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_8bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_10bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_12bpc)
|
||||
return false;
|
||||
else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
|
||||
!dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_16bpc)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t dc_link_bandwidth_kbps(
|
||||
const struct dc_link *link,
|
||||
const struct dc_link_settings *link_setting)
|
||||
{
|
||||
uint32_t total_data_bw_efficiency_x10000 = 0;
|
||||
uint32_t link_rate_per_lane_kbps = 0;
|
||||
|
||||
switch (link_dp_get_encoding_format(link_setting)) {
|
||||
case DP_8b_10b_ENCODING:
|
||||
/* For 8b/10b encoding:
|
||||
* link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane.
|
||||
* data bandwidth efficiency is 80% with additional 3% overhead if FEC is supported.
|
||||
*/
|
||||
link_rate_per_lane_kbps = link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE;
|
||||
total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000;
|
||||
if (dc_link_should_enable_fec(link)) {
|
||||
total_data_bw_efficiency_x10000 /= 100;
|
||||
total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100;
|
||||
}
|
||||
break;
|
||||
case DP_128b_132b_ENCODING:
|
||||
/* For 128b/132b encoding:
|
||||
* link rate is defined in the unit of 10mbps per lane.
|
||||
* total data bandwidth efficiency is always 96.71%.
|
||||
*/
|
||||
link_rate_per_lane_kbps = link_setting->link_rate * 10000;
|
||||
total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_128b_132b_x10000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */
|
||||
return link_rate_per_lane_kbps * link_setting->lane_count / 10000 * total_data_bw_efficiency_x10000;
|
||||
}
|
||||
|
||||
uint32_t dc_bandwidth_in_kbps_from_timing(
|
||||
const struct dc_crtc_timing *timing)
|
||||
{
|
||||
uint32_t bits_per_channel = 0;
|
||||
uint32_t kbps;
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
if (timing->flags.DSC)
|
||||
return dc_dsc_stream_bandwidth_in_kbps(timing,
|
||||
timing->dsc_cfg.bits_per_pixel,
|
||||
timing->dsc_cfg.num_slices_h,
|
||||
timing->dsc_cfg.is_dp);
|
||||
#endif /* CONFIG_DRM_AMD_DC_DCN */
|
||||
|
||||
switch (timing->display_color_depth) {
|
||||
case COLOR_DEPTH_666:
|
||||
bits_per_channel = 6;
|
||||
break;
|
||||
case COLOR_DEPTH_888:
|
||||
bits_per_channel = 8;
|
||||
break;
|
||||
case COLOR_DEPTH_101010:
|
||||
bits_per_channel = 10;
|
||||
break;
|
||||
case COLOR_DEPTH_121212:
|
||||
bits_per_channel = 12;
|
||||
break;
|
||||
case COLOR_DEPTH_141414:
|
||||
bits_per_channel = 14;
|
||||
break;
|
||||
case COLOR_DEPTH_161616:
|
||||
bits_per_channel = 16;
|
||||
break;
|
||||
default:
|
||||
ASSERT(bits_per_channel != 0);
|
||||
bits_per_channel = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
kbps = timing->pix_clk_100hz / 10;
|
||||
kbps *= bits_per_channel;
|
||||
|
||||
if (timing->flags.Y_ONLY != 1) {
|
||||
/*Only YOnly make reduce bandwidth by 1/3 compares to RGB*/
|
||||
kbps *= 3;
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
|
||||
kbps /= 2;
|
||||
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
|
||||
kbps = kbps * 2 / 3;
|
||||
}
|
||||
|
||||
return kbps;
|
||||
}
|
||||
|
||||
static bool dp_validate_mode_timing(
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing)
|
||||
{
|
||||
uint32_t req_bw;
|
||||
uint32_t max_bw;
|
||||
|
||||
const struct dc_link_settings *link_setting;
|
||||
|
||||
/* According to spec, VSC SDP should be used if pixel format is YCbCr420 */
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 &&
|
||||
!link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED &&
|
||||
dal_graphics_object_id_get_connector_id(link->link_id) != CONNECTOR_ID_VIRTUAL)
|
||||
return false;
|
||||
|
||||
/*always DP fail safe mode*/
|
||||
if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 &&
|
||||
timing->h_addressable == (uint32_t) 640 &&
|
||||
timing->v_addressable == (uint32_t) 480)
|
||||
return true;
|
||||
|
||||
link_setting = dc_link_get_link_cap(link);
|
||||
|
||||
/* TODO: DYNAMIC_VALIDATION needs to be implemented */
|
||||
/*if (flags.DYNAMIC_VALIDATION == 1 &&
|
||||
link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN)
|
||||
link_setting = &link->verified_link_cap;
|
||||
*/
|
||||
|
||||
req_bw = dc_bandwidth_in_kbps_from_timing(timing);
|
||||
max_bw = dc_link_bandwidth_kbps(link, link_setting);
|
||||
|
||||
if (req_bw <= max_bw) {
|
||||
/* 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
|
||||
return false;
|
||||
}
|
||||
|
||||
enum dc_status link_validate_mode_timing(
|
||||
const struct dc_stream_state *stream,
|
||||
struct dc_link *link,
|
||||
const struct dc_crtc_timing *timing)
|
||||
{
|
||||
uint32_t max_pix_clk = stream->link->dongle_max_pix_clk * 10;
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
|
||||
/* A hack to avoid failing any modes for EDID override feature on
|
||||
* topology change such as lower quality cable for DP or different dongle
|
||||
*/
|
||||
if (link->remote_sinks[0] && link->remote_sinks[0]->sink_signal == SIGNAL_TYPE_VIRTUAL)
|
||||
return DC_OK;
|
||||
|
||||
/* Passive Dongle */
|
||||
if (max_pix_clk != 0 && get_tmds_output_pixel_clock_100hz(timing) > max_pix_clk)
|
||||
return DC_EXCEED_DONGLE_CAP;
|
||||
|
||||
/* Active Dongle*/
|
||||
if (!dp_active_dongle_validate_timing(timing, dpcd_caps))
|
||||
return DC_EXCEED_DONGLE_CAP;
|
||||
|
||||
switch (stream->signal) {
|
||||
case SIGNAL_TYPE_EDP:
|
||||
case SIGNAL_TYPE_DISPLAY_PORT:
|
||||
if (!dp_validate_mode_timing(
|
||||
link,
|
||||
timing))
|
||||
return DC_NO_DP_LINK_BANDWIDTH;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DC_OK;
|
||||
}
|
28
drivers/gpu/drm/amd/display/dc/link/link_validation.h
Normal file
28
drivers/gpu/drm/amd/display/dc/link/link_validation.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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_VALIDATION_H__
|
||||
#define __LINK_VALIDATION_H__
|
||||
#include "link.h"
|
||||
#endif /* __LINK_VALIDATION_H__ */
|
@ -47,6 +47,7 @@
|
||||
#include "resource.h"
|
||||
#include "link_enc_cfg.h"
|
||||
#include "dc_dmub_srv.h"
|
||||
#include "gpio_service_interface.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
@ -2127,7 +2128,7 @@ static bool dp_verify_link_cap(
|
||||
if (status == LINK_TRAINING_SUCCESS) {
|
||||
success = true;
|
||||
udelay(1000);
|
||||
if (dp_read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
|
||||
if (dc_link_dp_read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
|
||||
dc_link_check_link_loss_status(
|
||||
link,
|
||||
&irq_data))
|
||||
@ -2168,7 +2169,7 @@ bool dp_verify_link_cap_with_retries(
|
||||
|
||||
memset(&link->verified_link_cap, 0,
|
||||
sizeof(struct dc_link_settings));
|
||||
if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) {
|
||||
if (!dc_link_detect_connection_type(link, &type) || type == dc_connection_none) {
|
||||
link->verified_link_cap = fail_safe_link_settings;
|
||||
break;
|
||||
} else if (dp_verify_link_cap(link, known_limit_link_setting,
|
||||
@ -2184,3 +2185,66 @@ bool dp_verify_link_cap_with_retries(
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_link_is_dp_sink_present() - Check if there is a native DP
|
||||
* or passive DP-HDMI dongle connected
|
||||
*/
|
||||
bool dc_link_is_dp_sink_present(struct dc_link *link)
|
||||
{
|
||||
enum gpio_result gpio_result;
|
||||
uint32_t clock_pin = 0;
|
||||
uint8_t retry = 0;
|
||||
struct ddc *ddc;
|
||||
|
||||
enum connector_id connector_id =
|
||||
dal_graphics_object_id_get_connector_id(link->link_id);
|
||||
|
||||
bool present =
|
||||
((connector_id == CONNECTOR_ID_DISPLAY_PORT) ||
|
||||
(connector_id == CONNECTOR_ID_EDP) ||
|
||||
(connector_id == CONNECTOR_ID_USBC));
|
||||
|
||||
ddc = get_ddc_pin(link->ddc);
|
||||
|
||||
if (!ddc) {
|
||||
BREAK_TO_DEBUGGER();
|
||||
return present;
|
||||
}
|
||||
|
||||
/* Open GPIO and set it to I2C mode */
|
||||
/* Note: this GpioMode_Input will be converted
|
||||
* to GpioConfigType_I2cAuxDualMode in GPIO component,
|
||||
* which indicates we need additional delay
|
||||
*/
|
||||
|
||||
if (dal_ddc_open(ddc, GPIO_MODE_INPUT,
|
||||
GPIO_DDC_CONFIG_TYPE_MODE_I2C) != GPIO_RESULT_OK) {
|
||||
dal_ddc_close(ddc);
|
||||
|
||||
return present;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read GPIO: DP sink is present if both clock and data pins are zero
|
||||
*
|
||||
* [W/A] plug-unplug DP cable, sometimes customer board has
|
||||
* one short pulse on clk_pin(1V, < 1ms). DP will be config to HDMI/DVI
|
||||
* then monitor can't br light up. Add retry 3 times
|
||||
* But in real passive dongle, it need additional 3ms to detect
|
||||
*/
|
||||
do {
|
||||
gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin);
|
||||
ASSERT(gpio_result == GPIO_RESULT_OK);
|
||||
if (clock_pin)
|
||||
udelay(1000);
|
||||
else
|
||||
break;
|
||||
} while (retry++ < 3);
|
||||
|
||||
present = (gpio_result == GPIO_RESULT_OK) && !clock_pin;
|
||||
|
||||
dal_ddc_close(ddc);
|
||||
|
||||
return present;
|
||||
}
|
||||
|
@ -103,3 +103,4 @@ bool dc_link_dpia_query_hpd_status(struct dc_link *link)
|
||||
|
||||
return is_hpd_high;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,8 @@
|
||||
*/
|
||||
|
||||
/* FILE POLICY AND INTENDED USAGE:
|
||||
*
|
||||
* This file implements DP HPD short pulse handling sequence according to DP
|
||||
* specifications
|
||||
*
|
||||
*/
|
||||
|
||||
@ -190,7 +191,7 @@ void dc_link_dp_handle_link_loss(struct dc_link *link)
|
||||
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
|
||||
pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
|
||||
core_link_disable_stream(pipe_ctx);
|
||||
link_set_dpms_off(pipe_ctx);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
@ -206,12 +207,12 @@ void dc_link_dp_handle_link_loss(struct dc_link *link)
|
||||
pipe_ctx->link_config.dp_link_settings.link_spread =
|
||||
link->verified_link_cap.link_spread;
|
||||
}
|
||||
core_link_enable_stream(link->dc->current_state, pipe_ctx);
|
||||
link_set_dpms_on(link->dc->current_state, pipe_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum dc_status dp_read_hpd_rx_irq_data(
|
||||
enum dc_status dc_link_dp_read_hpd_rx_irq_data(
|
||||
struct dc_link *link,
|
||||
union hpd_irq_data *irq_data)
|
||||
{
|
||||
@ -299,7 +300,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
|
||||
* dal_dpsst_ls_read_hpd_irq_data
|
||||
* Order of calls is important too
|
||||
*/
|
||||
result = dp_read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
|
||||
result = dc_link_dp_read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
|
||||
if (out_hpd_irq_dpcd_data)
|
||||
*out_hpd_irq_dpcd_data = hpd_irq_dpcd_data;
|
||||
|
||||
@ -398,4 +399,3 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
|
||||
*/
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,4 @@
|
||||
|
||||
#include "link.h"
|
||||
|
||||
enum dc_status dp_read_hpd_rx_irq_data(
|
||||
struct dc_link *link,
|
||||
union hpd_irq_data *irq_data);
|
||||
|
||||
#endif /* __DC_LINK_DP_IRQ_HANDLER_H__ */
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include "link_dp_capability.h"
|
||||
#include "clk_mgr.h"
|
||||
#include "resource.h"
|
||||
|
||||
#include "link_enc_cfg.h"
|
||||
#define DC_LOGGER \
|
||||
link->ctx->logger
|
||||
|
||||
@ -94,9 +94,6 @@ void dp_disable_link_phy_mst(struct dc_link *link,
|
||||
return;
|
||||
|
||||
dp_disable_link_phy(link, link_res, signal);
|
||||
|
||||
/* set the sink to SST mode after disabling the link */
|
||||
dp_enable_mst_on_sink(link, false);
|
||||
}
|
||||
|
||||
static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
|
||||
@ -142,3 +139,81 @@ void dp_set_drive_settings(
|
||||
/* Notify DP sink the PHY settings from source */
|
||||
dpcd_set_lane_settings(link, lt_settings, DPRX);
|
||||
}
|
||||
|
||||
enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready)
|
||||
{
|
||||
/* FEC has to be "set ready" before the link training.
|
||||
* The policy is to always train with FEC
|
||||
* if the sink supports it and leave it enabled on link.
|
||||
* If FEC is not supported, disable it.
|
||||
*/
|
||||
struct link_encoder *link_enc = NULL;
|
||||
enum dc_status status = DC_OK;
|
||||
uint8_t fec_config = 0;
|
||||
|
||||
link_enc = link_enc_cfg_get_link_enc(link);
|
||||
ASSERT(link_enc);
|
||||
|
||||
if (!dc_link_should_enable_fec(link))
|
||||
return status;
|
||||
|
||||
if (link_enc->funcs->fec_set_ready &&
|
||||
link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
|
||||
if (ready) {
|
||||
fec_config = 1;
|
||||
status = core_link_write_dpcd(link,
|
||||
DP_FEC_CONFIGURATION,
|
||||
&fec_config,
|
||||
sizeof(fec_config));
|
||||
if (status == DC_OK) {
|
||||
link_enc->funcs->fec_set_ready(link_enc, true);
|
||||
link->fec_state = dc_link_fec_ready;
|
||||
} else {
|
||||
link_enc->funcs->fec_set_ready(link_enc, false);
|
||||
link->fec_state = dc_link_fec_not_ready;
|
||||
dm_error("dpcd write failed to set fec_ready");
|
||||
}
|
||||
} else if (link->fec_state == dc_link_fec_ready) {
|
||||
fec_config = 0;
|
||||
status = core_link_write_dpcd(link,
|
||||
DP_FEC_CONFIGURATION,
|
||||
&fec_config,
|
||||
sizeof(fec_config));
|
||||
link_enc->funcs->fec_set_ready(link_enc, false);
|
||||
link->fec_state = dc_link_fec_not_ready;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void dp_set_fec_enable(struct dc_link *link, bool enable)
|
||||
{
|
||||
struct link_encoder *link_enc = NULL;
|
||||
|
||||
link_enc = link_enc_cfg_get_link_enc(link);
|
||||
ASSERT(link_enc);
|
||||
|
||||
if (!dc_link_should_enable_fec(link))
|
||||
return;
|
||||
|
||||
if (link_enc->funcs->fec_set_enable &&
|
||||
link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
|
||||
if (link->fec_state == dc_link_fec_ready && enable) {
|
||||
/* Accord to DP spec, FEC enable sequence can first
|
||||
* be transmitted anytime after 1000 LL codes have
|
||||
* been transmitted on the link after link training
|
||||
* completion. Using 1 lane RBR should have the maximum
|
||||
* time for transmitting 1000 LL codes which is 6.173 us.
|
||||
* So use 7 microseconds delay instead.
|
||||
*/
|
||||
udelay(7);
|
||||
link_enc->funcs->fec_set_enable(link_enc, true);
|
||||
link->fec_state = dc_link_fec_enabled;
|
||||
} else if (link->fec_state == dc_link_fec_enabled && !enable) {
|
||||
link_enc->funcs->fec_set_enable(link_enc, false);
|
||||
link->fec_state = dc_link_fec_ready;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,4 +53,8 @@ void dp_set_drive_settings(
|
||||
const struct link_resource *link_res,
|
||||
struct link_training_settings *lt_settings);
|
||||
|
||||
enum dc_status dp_set_fec_ready(struct dc_link *link,
|
||||
const struct link_resource *link_res, bool ready);
|
||||
void dp_set_fec_enable(struct dc_link *link, bool enable);
|
||||
|
||||
#endif /* __DC_LINK_DP_PHY_H__ */
|
||||
|
@ -51,6 +51,7 @@
|
||||
|
||||
#define POST_LT_ADJ_REQ_LIMIT 6
|
||||
#define POST_LT_ADJ_REQ_TIMEOUT 200
|
||||
#define LINK_TRAINING_RETRY_DELAY 50 /* ms */
|
||||
|
||||
void dp_log_training_result(
|
||||
struct dc_link *link,
|
||||
@ -1648,7 +1649,7 @@ bool perform_link_training_with_retries(
|
||||
if (status == LINK_TRAINING_ABORT) {
|
||||
enum dc_connection_type type = dc_connection_none;
|
||||
|
||||
dc_link_detect_sink(link, &type);
|
||||
dc_link_detect_connection_type(link, &type);
|
||||
if (type == dc_connection_none) {
|
||||
DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
|
||||
break;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "dm_helpers.h"
|
||||
#include "dmub/inc/dmub_cmd.h"
|
||||
#include "link_dpcd.h"
|
||||
#include "link_dp_phy.h"
|
||||
#include "link_dp_training_8b_10b.h"
|
||||
#include "link_dp_capability.h"
|
||||
#include "dc_dmub_srv.h"
|
||||
@ -49,6 +50,8 @@
|
||||
/* Extend interval between training status checks for manual testing. */
|
||||
#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000
|
||||
|
||||
#define TRAINING_AUX_RD_INTERVAL 100 //us
|
||||
|
||||
/* SET_CONFIG message types sent by driver. */
|
||||
enum dpia_set_config_type {
|
||||
DPIA_SET_CFG_SET_LINK = 0x01,
|
||||
|
Loading…
x
Reference in New Issue
Block a user