Merge tag 'amd-drm-next-6.3-2023-01-27' of https://gitlab.freedesktop.org/agd5f/linux...
authorDave Airlie <airlied@redhat.com>
Mon, 30 Jan 2023 05:37:55 +0000 (15:37 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 30 Jan 2023 05:37:57 +0000 (15:37 +1000)
amd-drm-next-6.3-2023-01-27:

amdgpu:
- GC11 fixes
- SMU13 fixes
- Freesync fixes
- DP MST fixes
- DP MST code rework and cleanup
- AV1 fixes for VCN4
- DCN 3.2.x fixes
- PSR fixes
- DML optimizations
- DC link code rework

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230127225917.2419162-1-alexander.deucher@amd.com
144 files changed:
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/imu_v11_0.c
drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
drivers/gpu/drm/amd/amdgpu/soc21.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
drivers/gpu/drm/amd/display/dc/Makefile
drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c [deleted file]
drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
drivers/gpu/drm/amd/display/dc/dm_helpers.h
drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c
drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h [deleted file]
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
drivers/gpu/drm/amd/display/dc/inc/link.h
drivers/gpu/drm/amd/display/dc/link/Makefile
drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/link_ddc.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_ddc.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_capability.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_capability.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_phy.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_phy.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dpcd.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_dpcd.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hpd.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hpd.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h [deleted file]
drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.h
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/display/drm_dp_mst_topology.c
include/drm/drm_print.h

index 1257745..5bee3ff 100644 (file)
@@ -3038,6 +3038,18 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
                    (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA))
                        continue;
 
+               /* Once swPSP provides the IMU, RLC FW binaries to TOS during cold-boot.
+                * These are in TMR, hence are expected to be reused by PSP-TOS to reload
+                * from this location and RLC Autoload automatically also gets loaded
+                * from here based on PMFW -> PSP message during re-init sequence.
+                * Therefore, the psp suspend & resume should be skipped to avoid destroy
+                * the TMR and reload FWs again for IMU enabled APU ASICs.
+                */
+               if (amdgpu_in_reset(adev) &&
+                   (adev->flags & AMD_IS_APU) && adev->gfx.imu.funcs &&
+                   adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)
+                       continue;
+
                /* XXX handle errors */
                r = adev->ip_blocks[i].version->funcs->suspend(adev);
                /* XXX handle errors */
index 44c57f4..32fe05c 100644 (file)
@@ -549,8 +549,8 @@ struct amdgpu_mst_connector {
 
        struct drm_dp_mst_topology_mgr mst_mgr;
        struct amdgpu_dm_dp_aux dm_dp_aux;
-       struct drm_dp_mst_port *port;
-       struct amdgpu_connector *mst_port;
+       struct drm_dp_mst_port *mst_output_port;
+       struct amdgpu_connector *mst_root;
        bool is_mst_connector;
        struct amdgpu_encoder *mst_encoder;
 };
index ed0d368..4ab90c7 100644 (file)
@@ -35,6 +35,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_0_imu.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_1_imu.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_2_imu.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_3_imu.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_imu.bin");
 
 static int imu_v11_0_init_microcode(struct amdgpu_device *adev)
 {
index bfa3050..62cdd21 100644 (file)
@@ -40,6 +40,8 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes1.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes1.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes1.bin");
 
 static int mes_v11_0_hw_fini(void *handle);
 static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev);
@@ -196,7 +198,6 @@ static int mes_v11_0_add_hw_queue(struct amdgpu_mes *mes,
        mes_add_queue_pkt.trap_handler_addr = input->tba_addr;
        mes_add_queue_pkt.tma_addr = input->tma_addr;
        mes_add_queue_pkt.is_kfd_process = input->is_kfd_process;
-       mes_add_queue_pkt.trap_en = 1;
 
        /* For KFD, gds_size is re-used for queue size (needed in MES for AQL queues) */
        mes_add_queue_pkt.is_aql_queue = input->is_aql_queue;
index 9c4a29d..e03cf7f 100644 (file)
@@ -52,6 +52,7 @@ static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_
 {
        {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)},
        {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)},
+       {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
 };
 
 static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] =
index efb22d0..22a4176 100644 (file)
@@ -1710,7 +1710,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
 
                create = ptr + addr + offset - start;
 
-               /* H246, HEVC and VP9 can run on any instance */
+               /* H264, HEVC and VP9 can run on any instance */
                if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11)
                        continue;
 
@@ -1724,7 +1724,29 @@ out:
        return r;
 }
 
-#define RADEON_VCN_ENGINE_TYPE_DECODE                                 (0x00000003)
+#define RADEON_VCN_ENGINE_TYPE_ENCODE                  (0x00000002)
+#define RADEON_VCN_ENGINE_TYPE_DECODE                  (0x00000003)
+
+#define RADEON_VCN_ENGINE_INFO                         (0x30000001)
+#define RADEON_VCN_ENGINE_INFO_MAX_OFFSET              16
+
+#define RENCODE_ENCODE_STANDARD_AV1                    2
+#define RENCODE_IB_PARAM_SESSION_INIT                  0x00000003
+#define RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET       64
+
+/* return the offset in ib if id is found, -1 otherwise
+ * to speed up the searching we only search upto max_offset
+ */
+static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int max_offset)
+{
+       int i;
+
+       for (i = 0; i < ib->length_dw && i < max_offset && ib->ptr[i] >= 8; i += ib->ptr[i]/4) {
+               if (ib->ptr[i + 1] == id)
+                       return i;
+       }
+       return -1;
+}
 
 static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
                                           struct amdgpu_job *job,
@@ -1734,27 +1756,35 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
        struct amdgpu_vcn_decode_buffer *decode_buffer;
        uint64_t addr;
        uint32_t val;
+       int idx;
 
        /* The first instance can decode anything */
        if (!ring->me)
                return 0;
 
-       /* unified queue ib header has 8 double words. */
-       if (ib->length_dw < 8)
-               return 0;
-
-       val = amdgpu_ib_get_value(ib, 6); //RADEON_VCN_ENGINE_TYPE
-       if (val != RADEON_VCN_ENGINE_TYPE_DECODE)
-               return 0;
-
-       decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[10];
-
-       if (!(decode_buffer->valid_buf_flag  & 0x1))
+       /* RADEON_VCN_ENGINE_INFO is at the top of ib block */
+       idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO,
+                       RADEON_VCN_ENGINE_INFO_MAX_OFFSET);
+       if (idx < 0) /* engine info is missing */
                return 0;
 
-       addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
-               decode_buffer->msg_buffer_address_lo;
-       return vcn_v4_0_dec_msg(p, job, addr);
+       val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
+       if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
+               decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
+
+               if (!(decode_buffer->valid_buf_flag  & 0x1))
+                       return 0;
+
+               addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
+                       decode_buffer->msg_buffer_address_lo;
+               return vcn_v4_0_dec_msg(p, job, addr);
+       } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
+               idx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT,
+                       RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET);
+               if (idx >= 0 && ib->ptr[idx + 2] == RENCODE_ENCODE_STANDARD_AV1)
+                       return vcn_v4_0_limit_sched(p, job);
+       }
+       return 0;
 }
 
 static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
index 8e4b668..e1d6382 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "dm_services_types.h"
 #include "dc.h"
-#include "dc_link_dp.h"
 #include "link_enc_cfg.h"
 #include "dc/inc/core_types.h"
 #include "dal_asic_id.h"
@@ -39,6 +38,9 @@
 #include "dc/dc_edid_parser.h"
 #include "dc/dc_stat.h"
 #include "amdgpu_dm_trace.h"
+#include "dpcd_defs.h"
+#include "link/protocols/link_dpcd.h"
+#include "link_service_types.h"
 
 #include "vid.h"
 #include "amdgpu.h"
@@ -1225,10 +1227,25 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
        pa_config->gart_config.page_table_end_addr = page_table_end.quad_part << 12;
        pa_config->gart_config.page_table_base_addr = page_table_base.quad_part;
 
-       pa_config->is_hvm_enabled = 0;
+       pa_config->is_hvm_enabled = adev->mode_info.gpu_vm_support;
 
 }
 
+static void force_connector_state(
+       struct amdgpu_dm_connector *aconnector,
+       enum drm_connector_force force_state)
+{
+       struct drm_connector *connector = &aconnector->base;
+
+       mutex_lock(&connector->dev->mode_config.mutex);
+       aconnector->base.force = force_state;
+       mutex_unlock(&connector->dev->mode_config.mutex);
+
+       mutex_lock(&aconnector->hpd_lock);
+       drm_kms_helper_connector_hotplug_event(connector);
+       mutex_unlock(&aconnector->hpd_lock);
+}
+
 static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
 {
        struct hpd_rx_irq_offload_work *offload_work;
@@ -1237,6 +1254,9 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
        struct amdgpu_device *adev;
        enum dc_connection_type new_connection_type = dc_connection_none;
        unsigned long flags;
+       union test_response test_response;
+
+       memset(&test_response, 0, sizeof(test_response));
 
        offload_work = container_of(work, struct hpd_rx_irq_offload_work, work);
        aconnector = offload_work->offload_wq->aconnector;
@@ -1261,10 +1281,26 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
                goto skip;
 
        mutex_lock(&adev->dm.dc_lock);
-       if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST)
+       if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
                dc_link_dp_handle_automated_test(dc_link);
+
+               if (aconnector->timing_changed) {
+                       /* force connector disconnect and reconnect */
+                       force_connector_state(aconnector, DRM_FORCE_OFF);
+                       msleep(100);
+                       force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED);
+               }
+
+               test_response.bits.ACK = 1;
+
+               core_link_write_dpcd(
+               dc_link,
+               DP_TEST_RESPONSE,
+               &test_response.raw,
+               sizeof(test_response));
+       }
        else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
-                       hpd_rx_irq_check_link_loss_status(dc_link, &offload_work->data) &&
+                       dc_link_check_link_loss_status(dc_link, &offload_work->data) &&
                        dc_link_dp_allow_hpd_rx_irq(dc_link)) {
                dc_link_dp_handle_link_loss(dc_link);
                spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
@@ -2197,7 +2233,7 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
        drm_for_each_connector_iter(connector, &iter) {
                aconnector = to_amdgpu_dm_connector(connector);
                if (aconnector->dc_link->type != dc_connection_mst_branch ||
-                   aconnector->mst_port)
+                   aconnector->mst_root)
                        continue;
 
                mgr = &aconnector->mst_mgr;
@@ -2987,6 +3023,10 @@ void amdgpu_dm_update_connector_after_detect(
                                                    aconnector->edid);
                }
 
+               aconnector->timing_requested = kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL);
+               if (!aconnector->timing_requested)
+                       dm_error("%s: failed to create aconnector->requested_timing\n", __func__);
+
                drm_connector_update_edid_property(connector, aconnector->edid);
                amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
                update_connector_ext_caps(aconnector);
@@ -2998,6 +3038,8 @@ void amdgpu_dm_update_connector_after_detect(
                dc_sink_release(aconnector->dc_sink);
                aconnector->dc_sink = NULL;
                aconnector->edid = NULL;
+               kfree(aconnector->timing_requested);
+               aconnector->timing_requested = NULL;
 #ifdef CONFIG_DRM_AMD_DC_HDCP
                /* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
                if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
@@ -3042,6 +3084,8 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
        if (aconnector->fake_enable)
                aconnector->fake_enable = false;
 
+       aconnector->timing_changed = false;
+
        if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
                DRM_ERROR("KMS: Failed to detect connector\n");
 
@@ -5888,6 +5932,14 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                        stream, &mode, &aconnector->base, con_state, old_stream,
                        requested_bpc);
 
+       if (aconnector->timing_changed) {
+               DC_LOG_DEBUG("%s: overriding timing for automated test, bpc %d, changing to %d\n",
+                               __func__,
+                               stream->timing.display_color_depth,
+                               aconnector->timing_requested->display_color_depth);
+               stream->timing = *aconnector->timing_requested;
+       }
+
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        /* SST DSC determination policy */
        update_dsc_caps(aconnector, sink, stream, &dsc_caps);
@@ -6580,11 +6632,11 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
        int clock, bpp = 0;
        bool is_y420 = false;
 
-       if (!aconnector->port || !aconnector->dc_sink)
+       if (!aconnector->mst_output_port || !aconnector->dc_sink)
                return 0;
 
-       mst_port = aconnector->port;
-       mst_mgr = &aconnector->mst_port->mst_mgr;
+       mst_port = aconnector->mst_output_port;
+       mst_mgr = &aconnector->mst_root->mst_mgr;
 
        if (!crtc_state->connectors_changed && !crtc_state->mode_changed)
                return 0;
@@ -6594,7 +6646,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
                return PTR_ERR(mst_state);
 
        if (!mst_state->pbn_div)
-               mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_port->dc_link);
+               mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link);
 
        if (!state->duplicated) {
                int max_bpc = conn_state->max_requested_bpc;
@@ -6640,7 +6692,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
 
                aconnector = to_amdgpu_dm_connector(connector);
 
-               if (!aconnector->port)
+               if (!aconnector->mst_output_port)
                        continue;
 
                if (!new_con_state || !new_con_state->crtc)
@@ -6680,7 +6732,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
                        dm_conn_state->pbn = pbn;
                        dm_conn_state->vcpi_slots = slot_num;
 
-                       ret = drm_dp_mst_atomic_enable_dsc(state, aconnector->port,
+                       ret = drm_dp_mst_atomic_enable_dsc(state, aconnector->mst_output_port,
                                                           dm_conn_state->pbn, false);
                        if (ret < 0)
                                return ret;
@@ -6688,7 +6740,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
                        continue;
                }
 
-               vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->port, pbn, true);
+               vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->mst_output_port, pbn, true);
                if (vcpi < 0)
                        return vcpi;
 
@@ -7102,7 +7154,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                adev->mode_info.underscan_vborder_property,
                                0);
 
-       if (!aconnector->mst_port)
+       if (!aconnector->mst_root)
                drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
 
        /* This defaults to the max in the range, but we want 8bpc for non-edp. */
@@ -7120,7 +7172,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
            connector_type == DRM_MODE_CONNECTOR_eDP) {
                drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
 
-               if (!aconnector->mst_port)
+               if (!aconnector->mst_root)
                        drm_connector_attach_vrr_capable_property(&aconnector->base);
 
 #ifdef CONFIG_DRM_AMD_DC_HDCP
@@ -7604,6 +7656,7 @@ static void update_freesync_state_on_stream(
        new_crtc_state->vrr_infopacket = vrr_infopacket;
 
        new_stream->vrr_infopacket = vrr_infopacket;
+       new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
 
        if (new_crtc_state->freesync_vrr_info_changed)
                DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d",
@@ -8818,22 +8871,15 @@ static void get_freesync_config_for_crtc(
        struct drm_display_mode *mode = &new_crtc_state->base.mode;
        int vrefresh = drm_mode_vrefresh(mode);
        bool fs_vid_mode = false;
-       bool drr_active = false;
 
        new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
                                        vrefresh >= aconnector->min_vfreq &&
                                        vrefresh <= aconnector->max_vfreq;
 
-       drr_active = new_crtc_state->vrr_supported &&
-               new_crtc_state->freesync_config.state != VRR_STATE_DISABLED &&
-               new_crtc_state->freesync_config.state != VRR_STATE_INACTIVE &&
-               new_crtc_state->freesync_config.state != VRR_STATE_UNSUPPORTED;
-
-       if (drr_active)
-               new_crtc_state->stream->ignore_msa_timing_param = true;
-
        if (new_crtc_state->vrr_supported) {
+               new_crtc_state->stream->ignore_msa_timing_param = true;
                fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
+
                config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000;
                config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000;
                config.vsif_supported = true;
@@ -9032,6 +9078,13 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                if (!dm_old_crtc_state->stream)
                        goto skip_modeset;
 
+               /* Unset freesync video if it was active before */
+               if (dm_old_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED) {
+                       dm_new_crtc_state->freesync_config.state = VRR_STATE_INACTIVE;
+                       dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = 0;
+               }
+
+               /* Now check if we should set freesync video mode */
                if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
                    is_timing_unchanged_for_freesync(new_crtc_state,
                                                     old_crtc_state)) {
@@ -9593,7 +9646,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
                        continue;
 
                aconnector = to_amdgpu_dm_connector(connector);
-               if (!aconnector->port || !aconnector->mst_port)
+               if (!aconnector->mst_output_port || !aconnector->mst_root)
                        aconnector = NULL;
                else
                        break;
@@ -9602,7 +9655,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
        if (!aconnector)
                return 0;
 
-       return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_port->mst_mgr);
+       return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_root->mst_mgr);
 }
 #endif
 
@@ -9648,6 +9701,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
        bool lock_and_validation_needed = false;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
+       struct drm_dp_mst_topology_mgr *mgr;
+       struct drm_dp_mst_topology_state *mst_state;
        struct dsc_mst_fairness_vars vars[MAX_PIPES];
 #endif
 
@@ -9896,6 +9951,28 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                lock_and_validation_needed = true;
        }
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       /* set the slot info for each mst_state based on the link encoding format */
+       for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) {
+               struct amdgpu_dm_connector *aconnector;
+               struct drm_connector *connector;
+               struct drm_connector_list_iter iter;
+               u8 link_coding_cap;
+
+               drm_connector_list_iter_begin(dev, &iter);
+               drm_for_each_connector_iter(connector, &iter) {
+                       if (connector->index == mst_state->mgr->conn_base_id) {
+                               aconnector = to_amdgpu_dm_connector(connector);
+                               link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link);
+                               drm_dp_mst_update_slots(mst_state, link_coding_cap);
+
+                               break;
+                       }
+               }
+               drm_connector_list_iter_end(&iter);
+       }
+#endif
+
        /**
         * Streams and planes are reset when there are changes that affect
         * bandwidth. Anything that affects bandwidth needs to go through
@@ -10165,11 +10242,15 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
                struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
        struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
+       bool ret;
 
+       mutex_lock(&adev->dm.dc_lock);
        if (adev->dm.dmub_srv)
-               return parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
+               ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
        else
-               return parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
+               ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
+       mutex_unlock(&adev->dm.dc_lock);
+       return ret;
 }
 
 static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
@@ -10445,6 +10526,7 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(
        ret = p_notify->aux_reply.length;
        *operation_result = p_notify->result;
 out:
+       reinit_completion(&adev->dm.dmub_aux_transfer_done);
        mutex_unlock(&adev->dm.dpia_aux_lock);
        return ret;
 }
@@ -10472,6 +10554,8 @@ int amdgpu_dm_process_dmub_set_config_sync(
                *operation_result = SET_CONFIG_UNKNOWN_ERROR;
        }
 
+       if (!is_cmd_complete)
+               reinit_completion(&adev->dm.dmub_aux_transfer_done);
        mutex_unlock(&adev->dm.dpia_aux_lock);
        return ret;
 }
index abbbb38..d89f2ea 100644 (file)
@@ -31,6 +31,7 @@
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_plane.h>
+#include "link_service_types.h"
 
 /*
  * This file contains the definition for amdgpu_display_manager
@@ -604,8 +605,8 @@ struct amdgpu_dm_connector {
        /* DM only */
        struct drm_dp_mst_topology_mgr mst_mgr;
        struct amdgpu_dm_dp_aux dm_dp_aux;
-       struct drm_dp_mst_port *port;
-       struct amdgpu_dm_connector *mst_port;
+       struct drm_dp_mst_port *mst_output_port;
+       struct amdgpu_dm_connector *mst_root;
        struct drm_dp_aux *dsc_aux;
        /* TODO see if we can merge with ddc_bus or make a dm_connector */
        struct amdgpu_i2c_adapter *i2c;
@@ -644,6 +645,10 @@ struct amdgpu_dm_connector {
 
        /* Record progress status of mst*/
        uint8_t mst_status;
+
+       /* Automated testing */
+       bool timing_changed;
+       struct dc_crtc_timing *timing_requested;
 };
 
 static inline void amdgpu_dm_set_mst_status(uint8_t *status,
index 8873eca..2771174 100644 (file)
@@ -344,7 +344,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
                        goto cleanup;
                }
 
-               aux = (aconn->port) ? &aconn->port->aux : &aconn->dm_dp_aux.aux;
+               aux = (aconn->mst_output_port) ? &aconn->mst_output_port->aux : &aconn->dm_dp_aux.aux;
 
                if (!aux) {
                        DRM_DEBUG_DRIVER("No dp aux for amd connector\n");
index 704860e..e783082 100644 (file)
@@ -34,8 +34,6 @@
 #include "dmub/dmub_srv.h"
 #include "resource.h"
 #include "dsc.h"
-#include "dc_link_dp.h"
-#include "dc_link.h"
 #include "link_hwss.h"
 #include "dc/dc_dmub_srv.h"
 
@@ -1193,7 +1191,7 @@ static int dp_dsc_fec_support_show(struct seq_file *m, void *data)
                        break;
                }
                dpcd_caps = aconnector->dc_link->dpcd_caps;
-               if (aconnector->port) {
+               if (aconnector->mst_output_port) {
                        /* aconnector sets dsc_aux during get_modes call
                         * if MST connector has it means it can either
                         * enable DSC on the sink device or on MST branch
@@ -1280,7 +1278,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
        mutex_lock(&aconnector->hpd_lock);
 
        /* Don't support for mst end device*/
-       if (aconnector->mst_port) {
+       if (aconnector->mst_root) {
                mutex_unlock(&aconnector->hpd_lock);
                return -EINVAL;
        }
@@ -2539,13 +2537,13 @@ static int dp_is_mst_connector_show(struct seq_file *m, void *unused)
 
        if (aconnector->mst_mgr.mst_state) {
                role = "root";
-       } else if (aconnector->mst_port &&
-               aconnector->mst_port->mst_mgr.mst_state) {
+       } else if (aconnector->mst_root &&
+               aconnector->mst_root->mst_mgr.mst_state) {
 
                role = "end";
 
-               mgr = &aconnector->mst_port->mst_mgr;
-               port = aconnector->port;
+               mgr = &aconnector->mst_root->mst_mgr;
+               port = aconnector->mst_output_port;
 
                drm_modeset_lock(&mgr->base.lock, NULL);
                if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
@@ -3392,12 +3390,12 @@ static int trigger_hpd_mst_set(void *data, u64 val)
                        if (!aconnector->dc_link)
                                continue;
 
-                       if (!aconnector->mst_port)
+                       if (!aconnector->mst_root)
                                continue;
 
                        link = aconnector->dc_link;
                        dc_link_dp_receiver_power_ctrl(link, false);
-                       drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_port->mst_mgr, false);
+                       drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_root->mst_mgr, false);
                        link->mst_stream_alloc_table.stream_count = 0;
                        memset(link->mst_stream_alloc_table.stream_allocations, 0,
                                        sizeof(link->mst_stream_alloc_table.stream_allocations));
index 6994c9a..a50319f 100644 (file)
@@ -38,6 +38,8 @@
 #include "amdgpu_dm.h"
 #include "amdgpu_dm_irq.h"
 #include "amdgpu_dm_mst_types.h"
+#include "dpcd_defs.h"
+#include "dc/inc/core_types.h"
 
 #include "dm_helpers.h"
 #include "ddc_service_types.h"
@@ -120,23 +122,50 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 }
 
 static void
-fill_dc_mst_payload_table_from_drm(struct drm_dp_mst_topology_state *mst_state,
-                                  struct amdgpu_dm_connector *aconnector,
+fill_dc_mst_payload_table_from_drm(struct dc_link *link,
+                                  bool enable,
+                                  struct drm_dp_mst_atomic_payload *target_payload,
                                   struct dc_dp_mst_stream_allocation_table *table)
 {
        struct dc_dp_mst_stream_allocation_table new_table = { 0 };
        struct dc_dp_mst_stream_allocation *sa;
-       struct drm_dp_mst_atomic_payload *payload;
+       struct link_mst_stream_allocation_table copy_of_link_table =
+                                                                               link->mst_stream_alloc_table;
 
-       /* Fill payload info*/
-       list_for_each_entry(payload, &mst_state->payloads, next) {
-               if (payload->delete)
-                       continue;
+       int i;
+       int current_hw_table_stream_cnt = copy_of_link_table.stream_count;
+       struct link_mst_stream_allocation *dc_alloc;
 
-               sa = &new_table.stream_allocations[new_table.stream_count];
-               sa->slot_count = payload->time_slots;
-               sa->vcp_id = payload->vcpi;
-               new_table.stream_count++;
+       /* TODO: refactor to set link->mst_stream_alloc_table directly if possible.*/
+       if (enable) {
+               dc_alloc =
+               &copy_of_link_table.stream_allocations[current_hw_table_stream_cnt];
+               dc_alloc->vcp_id = target_payload->vcpi;
+               dc_alloc->slot_count = target_payload->time_slots;
+       } else {
+               for (i = 0; i < copy_of_link_table.stream_count; i++) {
+                       dc_alloc =
+                       &copy_of_link_table.stream_allocations[i];
+
+                       if (dc_alloc->vcp_id == target_payload->vcpi) {
+                               dc_alloc->vcp_id = 0;
+                               dc_alloc->slot_count = 0;
+                               break;
+                       }
+               }
+               ASSERT(i != copy_of_link_table.stream_count);
+       }
+
+       /* Fill payload info*/
+       for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+               dc_alloc =
+                       &copy_of_link_table.stream_allocations[i];
+               if (dc_alloc->vcp_id > 0 && dc_alloc->slot_count > 0) {
+                       sa = &new_table.stream_allocations[new_table.stream_count];
+                       sa->slot_count = dc_alloc->slot_count;
+                       sa->vcp_id = dc_alloc->vcp_id;
+                       new_table.stream_count++;
+               }
        }
 
        /* Overwrite the old table */
@@ -168,14 +197,14 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
         * that blocks before commit guaranteeing that the state
         * is not gonna be swapped while still in use in commit tail */
 
-       if (!aconnector || !aconnector->mst_port)
+       if (!aconnector || !aconnector->mst_root)
                return false;
 
-       mst_mgr = &aconnector->mst_port->mst_mgr;
+       mst_mgr = &aconnector->mst_root->mst_mgr;
        mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
 
        /* It's OK for this to fail */
-       payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port);
+       payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
        if (enable)
                drm_dp_add_payload_part1(mst_mgr, mst_state, payload);
        else
@@ -185,7 +214,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
         * AUX message. The sequence is slot 1-63 allocated sequence for each
         * stream. AMD ASIC stream slot allocation should follow the same
         * sequence. copy DRM MST allocation to dc */
-       fill_dc_mst_payload_table_from_drm(mst_state, aconnector, proposed_table);
+       fill_dc_mst_payload_table_from_drm(stream->link, enable, payload, proposed_table);
 
        return true;
 }
@@ -220,10 +249,10 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger(
 
        aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 
-       if (!aconnector || !aconnector->mst_port)
+       if (!aconnector || !aconnector->mst_root)
                return ACT_FAILED;
 
-       mst_mgr = &aconnector->mst_port->mst_mgr;
+       mst_mgr = &aconnector->mst_root->mst_mgr;
 
        if (!mst_mgr->mst_state)
                return ACT_FAILED;
@@ -247,22 +276,27 @@ bool dm_helpers_dp_mst_send_payload_allocation(
        struct drm_dp_mst_atomic_payload *payload;
        enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD;
        enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
+       int ret = 0;
 
        aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 
-       if (!aconnector || !aconnector->mst_port)
+       if (!aconnector || !aconnector->mst_root)
                return false;
 
-       mst_mgr = &aconnector->mst_port->mst_mgr;
+       mst_mgr = &aconnector->mst_root->mst_mgr;
        mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
 
-       payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port);
+       payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
+
        if (!enable) {
                set_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
                clr_flag = MST_ALLOCATE_NEW_PAYLOAD;
        }
 
-       if (enable && drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload)) {
+       if (enable)
+               ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload);
+
+       if (ret) {
                amdgpu_dm_set_mst_status(&aconnector->mst_status,
                        set_flag, false);
        } else {
@@ -683,7 +717,7 @@ bool dm_helpers_dp_write_dsc_enable(
                                aconnector->dsc_aux, stream, enable_dsc);
 #endif
 
-               port = aconnector->port;
+               port = aconnector->mst_output_port;
 
                if (enable) {
                        if (port->passthrough_aux) {
@@ -960,6 +994,128 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
                                         sizeof(new_downspread));
 }
 
+bool dm_helpers_dp_handle_test_pattern_request(
+               struct dc_context *ctx,
+               const struct dc_link *link,
+               union link_test_pattern dpcd_test_pattern,
+               union test_misc dpcd_test_params)
+{
+       enum dp_test_pattern test_pattern;
+       enum dp_test_pattern_color_space test_pattern_color_space =
+                       DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
+       enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
+       enum dc_pixel_encoding requestPixelEncoding = PIXEL_ENCODING_UNDEFINED;
+       struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+       struct pipe_ctx *pipe_ctx = NULL;
+       struct amdgpu_dm_connector *aconnector = link->priv;
+       int i;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (pipes[i].stream == NULL)
+                       continue;
+
+               if (pipes[i].stream->link == link && !pipes[i].top_pipe &&
+                       !pipes[i].prev_odm_pipe) {
+                       pipe_ctx = &pipes[i];
+                       break;
+               }
+       }
+
+       if (pipe_ctx == NULL)
+               return false;
+
+       switch (dpcd_test_pattern.bits.PATTERN) {
+       case LINK_TEST_PATTERN_COLOR_RAMP:
+               test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
+       break;
+       case LINK_TEST_PATTERN_VERTICAL_BARS:
+               test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
+       break; /* black and white */
+       case LINK_TEST_PATTERN_COLOR_SQUARES:
+               test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
+                               TEST_DYN_RANGE_VESA ?
+                               DP_TEST_PATTERN_COLOR_SQUARES :
+                               DP_TEST_PATTERN_COLOR_SQUARES_CEA);
+       break;
+       default:
+               test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
+       break;
+       }
+
+       if (dpcd_test_params.bits.CLR_FORMAT == 0)
+               test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
+       else
+               test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
+                               DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
+                               DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
+
+       switch (dpcd_test_params.bits.BPC) {
+       case 0: // 6 bits
+               requestColorDepth = COLOR_DEPTH_666;
+               break;
+       case 1: // 8 bits
+               requestColorDepth = COLOR_DEPTH_888;
+               break;
+       case 2: // 10 bits
+               requestColorDepth = COLOR_DEPTH_101010;
+               break;
+       case 3: // 12 bits
+               requestColorDepth = COLOR_DEPTH_121212;
+               break;
+       default:
+               break;
+       }
+
+       switch (dpcd_test_params.bits.CLR_FORMAT) {
+       case 0:
+               requestPixelEncoding = PIXEL_ENCODING_RGB;
+               break;
+       case 1:
+               requestPixelEncoding = PIXEL_ENCODING_YCBCR422;
+               break;
+       case 2:
+               requestPixelEncoding = PIXEL_ENCODING_YCBCR444;
+               break;
+       default:
+               requestPixelEncoding = PIXEL_ENCODING_RGB;
+               break;
+       }
+
+       if ((requestColorDepth != COLOR_DEPTH_UNDEFINED
+               && pipe_ctx->stream->timing.display_color_depth != requestColorDepth)
+               || (requestPixelEncoding != PIXEL_ENCODING_UNDEFINED
+               && pipe_ctx->stream->timing.pixel_encoding != requestPixelEncoding)) {
+               DC_LOG_DEBUG("%s: original bpc %d pix encoding %d, changing to %d  %d\n",
+                               __func__,
+                               pipe_ctx->stream->timing.display_color_depth,
+                               pipe_ctx->stream->timing.pixel_encoding,
+                               requestColorDepth,
+                               requestPixelEncoding);
+               pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
+               pipe_ctx->stream->timing.pixel_encoding = requestPixelEncoding;
+
+               dp_update_dsc_config(pipe_ctx);
+
+               aconnector->timing_changed = true;
+               /* store current timing */
+               if (aconnector->timing_requested)
+                       *aconnector->timing_requested = pipe_ctx->stream->timing;
+               else
+                       DC_LOG_ERROR("%s: timing storage failed\n", __func__);
+
+       }
+
+       dc_link_dp_set_test_pattern(
+               (struct dc_link *) link,
+               test_pattern,
+               test_pattern_color_space,
+               NULL,
+               NULL,
+               0);
+
+       return false;
+}
+
 void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
 {
        // TODO
index 5fa9bab..0bff2cc 100644 (file)
@@ -39,7 +39,6 @@
 #include "dc.h"
 #include "dm_helpers.h"
 
-#include "dc_link_dp.h"
 #include "ddc_service_types.h"
 #include "dpcd_defs.h"
 
@@ -134,7 +133,7 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector)
        kfree(aconnector->edid);
 
        drm_connector_cleanup(connector);
-       drm_dp_mst_put_port_malloc(aconnector->port);
+       drm_dp_mst_put_port_malloc(aconnector->mst_output_port);
        kfree(aconnector);
 }
 
@@ -146,7 +145,7 @@ amdgpu_dm_mst_connector_late_register(struct drm_connector *connector)
        int r;
 
        r = drm_dp_mst_connector_late_register(connector,
-                                              amdgpu_dm_connector->port);
+                                              amdgpu_dm_connector->mst_output_port);
        if (r < 0)
                return r;
 
@@ -162,8 +161,8 @@ amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector)
 {
        struct amdgpu_dm_connector *aconnector =
                to_amdgpu_dm_connector(connector);
-       struct drm_dp_mst_port *port = aconnector->port;
-       struct amdgpu_dm_connector *root = aconnector->mst_port;
+       struct drm_dp_mst_port *port = aconnector->mst_output_port;
+       struct amdgpu_dm_connector *root = aconnector->mst_root;
        struct dc_link *dc_link = aconnector->dc_link;
        struct dc_sink *dc_sink = aconnector->dc_sink;
 
@@ -213,7 +212,7 @@ bool needs_dsc_aux_workaround(struct dc_link *link)
 static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
 {
        struct dc_sink *dc_sink = aconnector->dc_sink;
-       struct drm_dp_mst_port *port = aconnector->port;
+       struct drm_dp_mst_port *port = aconnector->mst_output_port;
        u8 dsc_caps[16] = { 0 };
        u8 dsc_branch_dec_caps_raw[3] = { 0 };  // DSC branch decoder caps 0xA0 ~ 0xA2
        u8 *dsc_branch_dec_caps = NULL;
@@ -231,7 +230,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
         */
        if (!aconnector->dsc_aux && !port->parent->port_parent &&
            needs_dsc_aux_workaround(aconnector->dc_link))
-               aconnector->dsc_aux = &aconnector->mst_port->dm_dp_aux.aux;
+               aconnector->dsc_aux = &aconnector->mst_root->dm_dp_aux.aux;
 
        if (!aconnector->dsc_aux)
                return false;
@@ -281,7 +280,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
 
        if (!aconnector->edid) {
                struct edid *edid;
-               edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
+               edid = drm_dp_mst_get_edid(connector, &aconnector->mst_root->mst_mgr, aconnector->mst_output_port);
 
                if (!edid) {
                        amdgpu_dm_set_mst_status(&aconnector->mst_status,
@@ -410,15 +409,15 @@ dm_dp_mst_detect(struct drm_connector *connector,
                 struct drm_modeset_acquire_ctx *ctx, bool force)
 {
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
-       struct amdgpu_dm_connector *master = aconnector->mst_port;
-       struct drm_dp_mst_port *port = aconnector->port;
+       struct amdgpu_dm_connector *master = aconnector->mst_root;
+       struct drm_dp_mst_port *port = aconnector->mst_output_port;
        int connection_status;
 
        if (drm_connector_is_unregistered(connector))
                return connector_status_disconnected;
 
        connection_status = drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr,
-                                                       aconnector->port);
+                                                       aconnector->mst_output_port);
 
        if (port->pdt != DP_PEER_DEVICE_NONE && !port->dpcd_rev) {
                uint8_t dpcd_rev;
@@ -475,8 +474,8 @@ static int dm_dp_mst_atomic_check(struct drm_connector *connector,
                                  struct drm_atomic_state *state)
 {
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
-       struct drm_dp_mst_topology_mgr *mst_mgr = &aconnector->mst_port->mst_mgr;
-       struct drm_dp_mst_port *mst_port = aconnector->port;
+       struct drm_dp_mst_topology_mgr *mst_mgr = &aconnector->mst_root->mst_mgr;
+       struct drm_dp_mst_port *mst_port = aconnector->mst_output_port;
 
        return drm_dp_atomic_release_time_slots(state, mst_mgr, mst_port);
 }
@@ -538,8 +537,8 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
                return NULL;
 
        connector = &aconnector->base;
-       aconnector->port = port;
-       aconnector->mst_port = master;
+       aconnector->mst_output_port = port;
+       aconnector->mst_root = master;
        amdgpu_dm_set_mst_status(&aconnector->mst_status,
                        MST_PROBE, true);
 
@@ -927,11 +926,6 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
        if (IS_ERR(mst_state))
                return PTR_ERR(mst_state);
 
-       mst_state->pbn_div = dm_mst_get_pbn_divider(dc_link);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       drm_dp_mst_update_slots(mst_state, dc_link_dp_mst_decide_link_encoding_format(dc_link));
-#endif
-
        /* Set up params */
        for (i = 0; i < dc_state->stream_count; i++) {
                struct dc_dsc_policy dsc_policy = {0};
@@ -945,7 +939,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
                if (!aconnector)
                        continue;
 
-               if (!aconnector->port)
+               if (!aconnector->mst_output_port)
                        continue;
 
                stream->timing.flags.DSC = 0;
@@ -953,7 +947,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
                params[count].timing = &stream->timing;
                params[count].sink = stream->sink;
                params[count].aconnector = aconnector;
-               params[count].port = aconnector->port;
+               params[count].port = aconnector->mst_output_port;
                params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable;
                if (params[count].clock_force_enable == DSC_CLK_FORCE_ENABLE)
                        debugfs_overwrite = true;
@@ -1162,7 +1156,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
 
                aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 
-               if (!aconnector || !aconnector->dc_sink || !aconnector->port)
+               if (!aconnector || !aconnector->dc_sink || !aconnector->mst_output_port)
                        continue;
 
                if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
@@ -1177,7 +1171,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
                if (!is_dsc_need_re_compute(state, dc_state, stream->link))
                        continue;
 
-               mst_mgr = aconnector->port->mgr;
+               mst_mgr = aconnector->mst_output_port->mgr;
                ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr,
                                                       &link_vars_start_index);
                if (ret != 0)
@@ -1223,7 +1217,7 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
 
                aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 
-               if (!aconnector || !aconnector->dc_sink || !aconnector->port)
+               if (!aconnector || !aconnector->dc_sink || !aconnector->mst_output_port)
                        continue;
 
                if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
@@ -1235,7 +1229,7 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
                if (!is_dsc_need_re_compute(state, dc_state, stream->link))
                        continue;
 
-               mst_mgr = aconnector->port->mgr;
+               mst_mgr = aconnector->mst_output_port->mgr;
                ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr,
                                                       &link_vars_start_index);
                if (ret != 0)
@@ -1450,8 +1444,8 @@ enum dc_status dm_dp_mst_is_port_support_mode(
         * with DSC enabled.
         */
        if (is_dsc_common_config_possible(stream, &bw_range) &&
-           aconnector->port->passthrough_aux) {
-               mst_mgr = aconnector->port->mgr;
+           aconnector->mst_output_port->passthrough_aux) {
+               mst_mgr = aconnector->mst_output_port->mgr;
                mutex_lock(&mst_mgr->lock);
 
                cur_link_settings = stream->link->verified_link_cap;
@@ -1459,7 +1453,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
                upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
                                                               &cur_link_settings
                                                               );
-               down_link_bw_in_kbps = kbps_from_pbn(aconnector->port->full_pbn);
+               down_link_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn);
 
                /* pick the bottleneck */
                end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps,
@@ -1483,7 +1477,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
                bpp = convert_dc_color_depth_into_bpc(stream->timing.display_color_depth) * 3;
                pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp, false);
 
-               if (pbn > aconnector->port->full_pbn)
+               if (pbn > aconnector->mst_output_port->full_pbn)
                        return DC_FAIL_BANDWIDTH_VALIDATE;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        }
index 872d06f..d647f68 100644 (file)
@@ -122,7 +122,7 @@ bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream)
                psr_config.allow_multi_disp_optimizations =
                        (amdgpu_dc_feature_mask & DC_PSR_ALLOW_MULTI_DISP_OPT);
 
-               if (!psr_su_set_y_granularity(dc, link, stream, &psr_config))
+               if (!psr_su_set_dsc_slice_height(dc, link, stream, &psr_config))
                        return false;
 
                ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context);
index 98c5083..fec32e2 100644 (file)
@@ -65,8 +65,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 \
-dc_surface.o dc_link_dp.o dc_debug.o dc_stream.o \
-dc_link_enc_cfg.o
+dc_surface.o dc_debug.o dc_stream.o dc_link_enc_cfg.o
 
 DISPLAY_CORE += dc_vm_helper.o
 
index f276abb..69691da 100644 (file)
@@ -29,6 +29,7 @@
 #include "dc_types.h"
 #include "dccg.h"
 #include "clk_mgr_internal.h"
+#include "link.h"
 
 #include "dce100/dce_clk_mgr.h"
 #include "dce110/dce110_clk_mgr.h"
index 1c0569b..f9e2e0c 100644 (file)
@@ -47,6 +47,7 @@
 #include "dcn30/dcn30_clk_mgr.h"
 
 #include "dc_dmub_srv.h"
+#include "link.h"
 
 #include "logger_types.h"
 #undef DC_LOGGER
index 20a06c0..89df724 100644 (file)
@@ -48,7 +48,7 @@
 #include "dcn31/dcn31_clk_mgr.h"
 
 #include "dc_dmub_srv.h"
-#include "dc_link_dp.h"
+#include "link.h"
 #include "dcn314_smu.h"
 
 
index 07edd97..8c368bc 100644 (file)
@@ -46,7 +46,7 @@
 #define DC_LOGGER \
        clk_mgr->base.base.ctx->logger
 
-#include "dc_link_dp.h"
+#include "link.h"
 
 #define TO_CLK_MGR_DCN315(clk_mgr)\
        container_of(clk_mgr, struct clk_mgr_dcn315, base)
@@ -87,6 +87,16 @@ static int dcn315_get_active_display_cnt_wa(
        return display_count;
 }
 
+bool should_disable_otg(struct pipe_ctx *pipe)
+{
+       bool ret = true;
+
+       if (pipe->stream->link->link_enc && pipe->stream->link->link_enc->funcs->is_dig_enabled &&
+                       pipe->stream->link->link_enc->funcs->is_dig_enabled(pipe->stream->link->link_enc))
+               ret = false;
+       return ret;
+}
+
 static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
 {
        struct dc *dc = clk_mgr_base->ctx->dc;
@@ -98,12 +108,16 @@ static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state
                if (pipe->top_pipe || pipe->prev_odm_pipe)
                        continue;
                if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
-                                    dc_is_virtual_signal(pipe->stream->signal))) {
-                       if (disable) {
-                               pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
-                               reset_sync_context_for_pipe(dc, context, i);
-                       } else
-                               pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
+                                       dc_is_virtual_signal(pipe->stream->signal))) {
+
+                       /* This w/a should not trigger when we have a dig active */
+                       if (should_disable_otg(pipe)) {
+                               if (disable) {
+                                       pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
+                                       reset_sync_context_for_pipe(dc, context, i);
+                               } else
+                                       pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
+                       }
                }
        }
 }
index 3edc81e..93db4db 100644 (file)
@@ -39,7 +39,7 @@
 #include "dcn316_smu.h"
 #include "dm_helpers.h"
 #include "dc_dmub_srv.h"
-#include "dc_link_dp.h"
+#include "link.h"
 
 // DCN316 this is CLK1 instance
 #define MAX_INSTANCE                                        7
index 352c977..61768bf 100644 (file)
@@ -33,7 +33,6 @@
 #include "reg_helper.h"
 #include "core_types.h"
 #include "dm_helpers.h"
-#include "dc_link_dp.h"
 #include "link.h"
 
 #include "atomfirmware.h"
index 53e586f..f11bc8d 100644 (file)
@@ -58,7 +58,6 @@
 #include "dm_helpers.h"
 #include "mem_input.h"
 
-#include "dc_link_dp.h"
 #include "dc_dmub_srv.h"
 
 #include "dsc.h"
@@ -1659,7 +1658,7 @@ bool dc_validate_boot_timing(const struct dc *dc,
                return false;
        }
 
-       if (is_edp_ilr_optimization_required(link, crtc_timing)) {
+       if (link_is_edp_ilr_optimization_required(link, crtc_timing)) {
                DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n");
                return false;
        }
@@ -2960,6 +2959,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
        if (update->vsp_infopacket)
                stream->vsp_infopacket = *update->vsp_infopacket;
 
+       if (update->adaptive_sync_infopacket)
+               stream->adaptive_sync_infopacket = *update->adaptive_sync_infopacket;
+
        if (update->dither_option)
                stream->dither_option = *update->dither_option;
 
@@ -3165,6 +3167,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
                                        stream_update->vsc_infopacket ||
                                        stream_update->vsp_infopacket ||
                                        stream_update->hfvsif_infopacket ||
+                                       stream_update->adaptive_sync_infopacket ||
                                        stream_update->vtem_infopacket) {
                                resource_build_info_frame(pipe_ctx);
                                dc->hwss.update_info_frame(pipe_ctx);
index d9e490e..6475664 100644 (file)
@@ -32,9 +32,8 @@
 #include "grph_object_id.h"
 #include "gpio_service_interface.h"
 #include "core_status.h"
-#include "dc_link_dp.h"
-#include "link/link_dp_dpia.h"
-#include "link/link_ddc.h"
+#include "link/protocols/link_dp_dpia.h"
+#include "link/protocols/link_ddc.h"
 #include "link_hwss.h"
 #include "link.h"
 #include "opp.h"
 #include "fixed31_32.h"
 #include "dpcd_defs.h"
 #include "dmcu.h"
+#include "dsc.h"
+#include "opp.h"
 #include "hw/clk_mgr.h"
 #include "dce/dmub_psr.h"
 #include "dmub/dmub_srv.h"
 #include "inc/hw/panel_cntl.h"
 #include "inc/link_enc_cfg.h"
-#include "link/link_dpcd.h"
-#include "link/link_dp_trace.h"
-#include "link/link_hpd.h"
-#include "link/link_dp_training.h"
-#include "link/link_dp_phy.h"
-#include "link/link_dp_capability.h"
+#include "link/protocols/link_dpcd.h"
+#include "link/accessories/link_dp_trace.h"
+#include "link/protocols/link_hpd.h"
+#include "link/protocols/link_dp_training.h"
+#include "link/protocols/link_dp_phy.h"
+#include "link/protocols/link_dp_capability.h"
+#include "link/protocols/link_edp_panel_control.h"
 
 #include "dc/dcn30/dcn30_vpg.h"
 
@@ -107,17 +109,6 @@ static void dc_link_destruct(struct dc_link *link)
                dc_sink_release(link->remote_sinks[i]);
 }
 
-bool dc_link_wait_for_t12(struct dc_link *link)
-{
-       if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
-               link->dc->hwss.edp_wait_for_T12(link);
-
-               return true;
-       }
-
-       return false;
-}
-
 /**
  * dc_link_detect_sink() - Determine if there is a sink connected
  *
@@ -1094,7 +1085,7 @@ static bool detect_link_and_local_sink(struct dc_link *link,
                        (link->dpcd_sink_ext_caps.bits.oled == 1)) {
                        dpcd_set_source_specific_data(link);
                        msleep(post_oui_delay);
-                       dc_link_set_default_brightness_aux(link);
+                       set_default_brightness_aux(link);
                        //TODO: use cached
                }
 
@@ -2067,10 +2058,10 @@ static enum dc_status enable_link_dp(struct dc_state *state,
        if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
                link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 ||
                link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) {
-               dc_link_set_default_brightness_aux(link); // TODO: use cached if known
+               set_default_brightness_aux(link); // TODO: use cached if known
                if (link->dpcd_sink_ext_caps.bits.oled == 1)
                        msleep(bl_oled_enable_delay);
-               dc_link_backlight_enable_aux(link, true);
+               link_backlight_enable_aux(link, true);
        }
 
        return status;
@@ -2740,22 +2731,6 @@ static void enable_link_lvds(struct pipe_ctx *pipe_ctx)
 
 }
 
-bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable)
-{
-       bool ret = false;
-       union dpcd_alpm_configuration alpm_config;
-
-       if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
-               memset(&alpm_config, 0, sizeof(alpm_config));
-
-               alpm_config.bits.ENABLE = (enable ? true : false);
-               ret = dm_helpers_dp_write_dpcd(link->ctx, link,
-                               DP_RECEIVER_ALPM_CONFIG, &alpm_config.raw,
-                               sizeof(alpm_config.raw));
-       }
-       return ret;
-}
-
 /****************************enable_link***********************************/
 static enum dc_status enable_link(
                struct dc_state *state,
@@ -3035,436 +3010,6 @@ enum dc_status dc_link_validate_mode_timing(
        return DC_OK;
 }
 
-static struct abm *get_abm_from_stream_res(const struct dc_link *link)
-{
-       int i;
-       struct dc *dc = NULL;
-       struct abm *abm = NULL;
-
-       if (!link || !link->ctx)
-               return NULL;
-
-       dc = link->ctx->dc;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
-               struct dc_stream_state *stream = pipe_ctx.stream;
-
-               if (stream && stream->link == link) {
-                       abm = pipe_ctx.stream_res.abm;
-                       break;
-               }
-       }
-       return abm;
-}
-
-int dc_link_get_backlight_level(const struct dc_link *link)
-{
-       struct abm *abm = get_abm_from_stream_res(link);
-       struct panel_cntl *panel_cntl = link->panel_cntl;
-       struct dc  *dc = link->ctx->dc;
-       struct dmcu *dmcu = dc->res_pool->dmcu;
-       bool fw_set_brightness = true;
-
-       if (dmcu)
-               fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
-
-       if (!fw_set_brightness && panel_cntl->funcs->get_current_backlight)
-               return panel_cntl->funcs->get_current_backlight(panel_cntl);
-       else if (abm != NULL && abm->funcs->get_current_backlight != NULL)
-               return (int) abm->funcs->get_current_backlight(abm);
-       else
-               return DC_ERROR_UNEXPECTED;
-}
-
-int dc_link_get_target_backlight_pwm(const struct dc_link *link)
-{
-       struct abm *abm = get_abm_from_stream_res(link);
-
-       if (abm == NULL || abm->funcs->get_target_backlight == NULL)
-               return DC_ERROR_UNEXPECTED;
-
-       return (int) abm->funcs->get_target_backlight(abm);
-}
-
-static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link)
-{
-       int i;
-       struct dc *dc = link->ctx->dc;
-       struct pipe_ctx *pipe_ctx = NULL;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               if (dc->current_state->res_ctx.pipe_ctx[i].stream) {
-                       if (dc->current_state->res_ctx.pipe_ctx[i].stream->link == link) {
-                               pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
-                               break;
-                       }
-               }
-       }
-
-       return pipe_ctx;
-}
-
-bool dc_link_set_backlight_level(const struct dc_link *link,
-               uint32_t backlight_pwm_u16_16,
-               uint32_t frame_ramp)
-{
-       struct dc  *dc = link->ctx->dc;
-
-       DC_LOGGER_INIT(link->ctx->logger);
-       DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
-                       backlight_pwm_u16_16, backlight_pwm_u16_16);
-
-       if (dc_is_embedded_signal(link->connector_signal)) {
-               struct pipe_ctx *pipe_ctx = get_pipe_from_link(link);
-
-               if (pipe_ctx) {
-                       /* Disable brightness ramping when the display is blanked
-                        * as it can hang the DMCU
-                        */
-                       if (pipe_ctx->plane_state == NULL)
-                               frame_ramp = 0;
-               } else {
-                       return false;
-               }
-
-               dc->hwss.set_backlight_level(
-                               pipe_ctx,
-                               backlight_pwm_u16_16,
-                               frame_ramp);
-       }
-       return true;
-}
-
-bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active,
-               bool wait, bool force_static, const unsigned int *power_opts)
-{
-       struct dc  *dc = link->ctx->dc;
-       struct dmcu *dmcu = dc->res_pool->dmcu;
-       struct dmub_psr *psr = dc->res_pool->psr;
-       unsigned int panel_inst;
-
-       if (psr == NULL && force_static)
-               return false;
-
-       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
-               return false;
-
-       if ((allow_active != NULL) && (*allow_active == true) && (link->type == dc_connection_none)) {
-               // Don't enter PSR if panel is not connected
-               return false;
-       }
-
-       /* Set power optimization flag */
-       if (power_opts && link->psr_settings.psr_power_opt != *power_opts) {
-               link->psr_settings.psr_power_opt = *power_opts;
-
-               if (psr != NULL && link->psr_settings.psr_feature_enabled && psr->funcs->psr_set_power_opt)
-                       psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt, panel_inst);
-       }
-
-       if (psr != NULL && link->psr_settings.psr_feature_enabled &&
-                       force_static && psr->funcs->psr_force_static)
-               psr->funcs->psr_force_static(psr, panel_inst);
-
-       /* Enable or Disable PSR */
-       if (allow_active && link->psr_settings.psr_allow_active != *allow_active) {
-               link->psr_settings.psr_allow_active = *allow_active;
-
-               if (!link->psr_settings.psr_allow_active)
-                       dc_z10_restore(dc);
-
-               if (psr != NULL && link->psr_settings.psr_feature_enabled) {
-                       psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst);
-               } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) &&
-                       link->psr_settings.psr_feature_enabled)
-                       dmcu->funcs->set_psr_enable(dmcu, link->psr_settings.psr_allow_active, wait);
-               else
-                       return false;
-       }
-
-       return true;
-}
-
-bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state)
-{
-       struct dc  *dc = link->ctx->dc;
-       struct dmcu *dmcu = dc->res_pool->dmcu;
-       struct dmub_psr *psr = dc->res_pool->psr;
-       unsigned int panel_inst;
-
-       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
-               return false;
-
-       if (psr != NULL && link->psr_settings.psr_feature_enabled)
-               psr->funcs->psr_get_state(psr, state, panel_inst);
-       else if (dmcu != NULL && link->psr_settings.psr_feature_enabled)
-               dmcu->funcs->get_psr_state(dmcu, state);
-
-       return true;
-}
-
-static inline enum physical_phy_id
-transmitter_to_phy_id(enum transmitter transmitter_value)
-{
-       switch (transmitter_value) {
-       case TRANSMITTER_UNIPHY_A:
-               return PHYLD_0;
-       case TRANSMITTER_UNIPHY_B:
-               return PHYLD_1;
-       case TRANSMITTER_UNIPHY_C:
-               return PHYLD_2;
-       case TRANSMITTER_UNIPHY_D:
-               return PHYLD_3;
-       case TRANSMITTER_UNIPHY_E:
-               return PHYLD_4;
-       case TRANSMITTER_UNIPHY_F:
-               return PHYLD_5;
-       case TRANSMITTER_NUTMEG_CRT:
-               return PHYLD_6;
-       case TRANSMITTER_TRAVIS_CRT:
-               return PHYLD_7;
-       case TRANSMITTER_TRAVIS_LCD:
-               return PHYLD_8;
-       case TRANSMITTER_UNIPHY_G:
-               return PHYLD_9;
-       case TRANSMITTER_COUNT:
-               return PHYLD_COUNT;
-       case TRANSMITTER_UNKNOWN:
-               return PHYLD_UNKNOWN;
-       default:
-               WARN_ONCE(1, "Unknown transmitter value %d\n",
-                         transmitter_value);
-               return PHYLD_UNKNOWN;
-       }
-}
-
-bool dc_link_setup_psr(struct dc_link *link,
-               const struct dc_stream_state *stream, struct psr_config *psr_config,
-               struct psr_context *psr_context)
-{
-       struct dc *dc;
-       struct dmcu *dmcu;
-       struct dmub_psr *psr;
-       int i;
-       unsigned int panel_inst;
-       /* updateSinkPsrDpcdConfig*/
-       union dpcd_psr_configuration psr_configuration;
-       union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};
-
-       psr_context->controllerId = CONTROLLER_ID_UNDEFINED;
-
-       if (!link)
-               return false;
-
-       dc = link->ctx->dc;
-       dmcu = dc->res_pool->dmcu;
-       psr = dc->res_pool->psr;
-
-       if (!dmcu && !psr)
-               return false;
-
-       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
-               return false;
-
-
-       memset(&psr_configuration, 0, sizeof(psr_configuration));
-
-       psr_configuration.bits.ENABLE                    = 1;
-       psr_configuration.bits.CRC_VERIFICATION          = 1;
-       psr_configuration.bits.FRAME_CAPTURE_INDICATION  =
-                       psr_config->psr_frame_capture_indication_req;
-
-       /* Check for PSR v2*/
-       if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
-               /* For PSR v2 selective update.
-                * Indicates whether sink should start capturing
-                * immediately following active scan line,
-                * or starting with the 2nd active scan line.
-                */
-               psr_configuration.bits.LINE_CAPTURE_INDICATION = 0;
-               /*For PSR v2, determines whether Sink should generate
-                * IRQ_HPD when CRC mismatch is detected.
-                */
-               psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR    = 1;
-               /* For PSR v2, set the bit when the Source device will
-                * be enabling PSR2 operation.
-                */
-               psr_configuration.bits.ENABLE_PSR2    = 1;
-               /* For PSR v2, the Sink device must be able to receive
-                * SU region updates early in the frame time.
-                */
-               psr_configuration.bits.EARLY_TRANSPORT_ENABLE    = 1;
-       }
-
-       dm_helpers_dp_write_dpcd(
-               link->ctx,
-               link,
-               368,
-               &psr_configuration.raw,
-               sizeof(psr_configuration.raw));
-
-       if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
-               dc_power_alpm_dpcd_enable(link, true);
-               psr_context->su_granularity_required =
-                       psr_config->su_granularity_required;
-               psr_context->su_y_granularity =
-                       psr_config->su_y_granularity;
-               psr_context->line_time_in_us =
-                       psr_config->line_time_in_us;
-
-               if (link->psr_settings.psr_vtotal_control_support) {
-                       psr_context->rate_control_caps = psr_config->rate_control_caps;
-                       vtotal_control.bits.ENABLE = true;
-                       core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
-                                                       &vtotal_control.raw, sizeof(vtotal_control.raw));
-               }
-       }
-
-       psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
-       psr_context->transmitterId = link->link_enc->transmitter;
-       psr_context->engineId = link->link_enc->preferred_engine;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               if (dc->current_state->res_ctx.pipe_ctx[i].stream
-                               == stream) {
-                       /* dmcu -1 for all controller id values,
-                        * therefore +1 here
-                        */
-                       psr_context->controllerId =
-                               dc->current_state->res_ctx.
-                               pipe_ctx[i].stream_res.tg->inst + 1;
-                       break;
-               }
-       }
-
-       /* Hardcoded for now.  Can be Pcie or Uniphy (or Unknown)*/
-       psr_context->phyType = PHY_TYPE_UNIPHY;
-       /*PhyId is associated with the transmitter id*/
-       psr_context->smuPhyId =
-               transmitter_to_phy_id(link->link_enc->transmitter);
-
-       psr_context->crtcTimingVerticalTotal = stream->timing.v_total;
-       psr_context->vsync_rate_hz = div64_u64(div64_u64((stream->
-                                       timing.pix_clk_100hz * 100),
-                                       stream->timing.v_total),
-                                       stream->timing.h_total);
-
-       psr_context->psrSupportedDisplayConfig = true;
-       psr_context->psrExitLinkTrainingRequired =
-               psr_config->psr_exit_link_training_required;
-       psr_context->sdpTransmitLineNumDeadline =
-               psr_config->psr_sdp_transmit_line_num_deadline;
-       psr_context->psrFrameCaptureIndicationReq =
-               psr_config->psr_frame_capture_indication_req;
-
-       psr_context->skipPsrWaitForPllLock = 0; /* only = 1 in KV */
-
-       psr_context->numberOfControllers =
-                       link->dc->res_pool->timing_generator_count;
-
-       psr_context->rfb_update_auto_en = true;
-
-       /* 2 frames before enter PSR. */
-       psr_context->timehyst_frames = 2;
-       /* half a frame
-        * (units in 100 lines, i.e. a value of 1 represents 100 lines)
-        */
-       psr_context->hyst_lines = stream->timing.v_total / 2 / 100;
-       psr_context->aux_repeats = 10;
-
-       psr_context->psr_level.u32all = 0;
-
-       /*skip power down the single pipe since it blocks the cstate*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       if (link->ctx->asic_id.chip_family >= FAMILY_RV) {
-               switch(link->ctx->asic_id.chip_family) {
-               case FAMILY_YELLOW_CARP:
-               case AMDGPU_FAMILY_GC_10_3_6:
-               case AMDGPU_FAMILY_GC_11_0_1:
-                       if (dc->debug.disable_z10 || dc->debug.psr_skip_crtc_disable)
-                               psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
-                       break;
-               default:
-                       psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
-                       break;
-               }
-       }
-#else
-       if (link->ctx->asic_id.chip_family >= FAMILY_RV)
-               psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
-#endif
-
-       /* SMU will perform additional powerdown sequence.
-        * For unsupported ASICs, set psr_level flag to skip PSR
-        *  static screen notification to SMU.
-        *  (Always set for DAL2, did not check ASIC)
-        */
-       psr_context->allow_smu_optimizations = psr_config->allow_smu_optimizations;
-       psr_context->allow_multi_disp_optimizations = psr_config->allow_multi_disp_optimizations;
-
-       /* Complete PSR entry before aborting to prevent intermittent
-        * freezes on certain eDPs
-        */
-       psr_context->psr_level.bits.DISABLE_PSR_ENTRY_ABORT = 1;
-
-       /* enable ALPM */
-       psr_context->psr_level.bits.DISABLE_ALPM = 0;
-       psr_context->psr_level.bits.ALPM_DEFAULT_PD_MODE = 1;
-
-       /* Controls additional delay after remote frame capture before
-        * continuing power down, default = 0
-        */
-       psr_context->frame_delay = 0;
-
-       if (psr) {
-               link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr,
-                       link, psr_context, panel_inst);
-               link->psr_settings.psr_power_opt = 0;
-               link->psr_settings.psr_allow_active = 0;
-       }
-       else
-               link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context);
-
-       /* psr_enabled == 0 indicates setup_psr did not succeed, but this
-        * should not happen since firmware should be running at this point
-        */
-       if (link->psr_settings.psr_feature_enabled == 0)
-               ASSERT(0);
-
-       return true;
-
-}
-
-void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
-{
-       struct dc  *dc = link->ctx->dc;
-       struct dmub_psr *psr = dc->res_pool->psr;
-       unsigned int panel_inst;
-
-       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
-               return;
-
-       /* PSR residency measurements only supported on DMCUB */
-       if (psr != NULL && link->psr_settings.psr_feature_enabled)
-               psr->funcs->psr_get_residency(psr, residency, panel_inst);
-       else
-               *residency = 0;
-}
-
-bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
-{
-       struct dc *dc = link->ctx->dc;
-       struct dmub_psr *psr = dc->res_pool->psr;
-
-       if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
-               return false;
-
-       psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);
-
-       return true;
-}
-
 const struct dc_link_status *dc_link_get_status(const struct dc_link *link)
 {
        return &link->link_status;
@@ -3999,10 +3544,13 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
        struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
        int i;
        bool mst_mode = (link->type == dc_connection_mst_branch);
+       /* adjust for drm changes*/
+       bool update_drm_mst_state = true;
        const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
        const struct dc_link_settings empty_link_settings = {0};
        DC_LOGGER_INIT(link->ctx->logger);
 
+
        /* deallocate_mst_payload is called before disable link. When mode or
         * disable/enable monitor, new stream is created which is not in link
         * stream[] yet. For this, payload is not allocated yet, so de-alloc
@@ -4018,7 +3566,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                                &empty_link_settings,
                                avg_time_slots_per_mtp);
 
-       if (mst_mode) {
+       if (mst_mode || update_drm_mst_state) {
                /* when link is in mst mode, reply on mst manager to remove
                 * payload
                 */
@@ -4081,11 +3629,18 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                        stream->ctx,
                        stream);
 
+               if (!update_drm_mst_state)
+                       dm_helpers_dp_mst_send_payload_allocation(
+                               stream->ctx,
+                               stream,
+                               false);
+       }
+
+       if (update_drm_mst_state)
                dm_helpers_dp_mst_send_payload_allocation(
                        stream->ctx,
                        stream,
                        false);
-       }
 
        return DC_OK;
 }
@@ -4541,110 +4096,6 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
        dc->hwss.set_avmute(pipe_ctx, enable);
 }
 
-void dc_link_set_drive_settings(struct dc *dc,
-                               struct link_training_settings *lt_settings,
-                               const struct dc_link *link)
-{
-
-       int i;
-       struct link_resource link_res;
-
-       for (i = 0; i < dc->link_count; i++)
-               if (dc->links[i] == link)
-                       break;
-
-       if (i >= dc->link_count)
-               ASSERT_CRITICAL(false);
-
-       dc_link_get_cur_link_res(link, &link_res);
-       dc_link_dp_set_drive_settings(dc->links[i], &link_res, lt_settings);
-}
-
-void dc_link_set_preferred_link_settings(struct dc *dc,
-                                        struct dc_link_settings *link_setting,
-                                        struct dc_link *link)
-{
-       int i;
-       struct pipe_ctx *pipe;
-       struct dc_stream_state *link_stream;
-       struct dc_link_settings store_settings = *link_setting;
-
-       link->preferred_link_setting = store_settings;
-
-       /* Retrain with preferred link settings only relevant for
-        * DP signal type
-        * Check for non-DP signal or if passive dongle present
-        */
-       if (!dc_is_dp_signal(link->connector_signal) ||
-               link->dongle_max_pix_clk > 0)
-               return;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-               if (pipe->stream && pipe->stream->link) {
-                       if (pipe->stream->link == link) {
-                               link_stream = pipe->stream;
-                               break;
-                       }
-               }
-       }
-
-       /* Stream not found */
-       if (i == MAX_PIPES)
-               return;
-
-       /* Cannot retrain link if backend is off */
-       if (link_stream->dpms_off)
-               return;
-
-       if (link_decide_link_settings(link_stream, &store_settings))
-               dp_retrain_link_dp_test(link, &store_settings, false);
-}
-
-void dc_link_set_preferred_training_settings(struct dc *dc,
-                                                struct dc_link_settings *link_setting,
-                                                struct dc_link_training_overrides *lt_overrides,
-                                                struct dc_link *link,
-                                                bool skip_immediate_retrain)
-{
-       if (lt_overrides != NULL)
-               link->preferred_training_settings = *lt_overrides;
-       else
-               memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
-
-       if (link_setting != NULL) {
-               link->preferred_link_setting = *link_setting;
-       } else {
-               link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
-               link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
-       }
-
-       if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
-                       link->type == dc_connection_mst_branch)
-               dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link);
-
-       /* Retrain now, or wait until next stream update to apply */
-       if (skip_immediate_retrain == false)
-               dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
-}
-
-void dc_link_set_test_pattern(struct dc_link *link,
-                             enum dp_test_pattern test_pattern,
-                             enum dp_test_pattern_color_space test_pattern_color_space,
-                             const struct link_training_settings *p_link_settings,
-                             const unsigned char *p_custom_pattern,
-                             unsigned int cust_pattern_size)
-{
-       if (link != NULL)
-               dc_link_dp_set_test_pattern(
-                       link,
-                       test_pattern,
-                       test_pattern_color_space,
-                       p_link_settings,
-                       p_custom_pattern,
-                       cust_pattern_size);
-}
-
 uint32_t dc_link_bandwidth_kbps(
        const struct dc_link *link,
        const struct dc_link_settings *link_setting)
@@ -4854,3 +4305,591 @@ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map)
                }
        }
 }
+
+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;
+}
+
+void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
+{
+       unsigned char mstmCntl;
+
+       core_link_read_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
+       if (enable)
+               mstmCntl |= DP_MST_EN;
+       else
+               mstmCntl &= (~DP_MST_EN);
+
+       core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
+}
+
+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;
+               }
+       }
+}
+
+// TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST)
+static void get_lane_status(
+       struct dc_link *link,
+       uint32_t lane_count,
+       union lane_status *status,
+       union lane_align_status_updated *status_updated)
+{
+       unsigned int lane;
+       uint8_t dpcd_buf[3] = {0};
+
+       if (status == NULL || status_updated == NULL) {
+               return;
+       }
+
+       core_link_read_dpcd(
+                       link,
+                       DP_LANE0_1_STATUS,
+                       dpcd_buf,
+                       sizeof(dpcd_buf));
+
+       for (lane = 0; lane < lane_count; lane++) {
+               status[lane].raw = dp_get_nibble_at_index(&dpcd_buf[0], lane);
+       }
+
+       status_updated->raw = dpcd_buf[2];
+}
+
+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)
+{
+       const uint8_t vc_id = 1; /// VC ID always 1 for SST
+       const uint8_t start_time_slot = 0; /// Always start at time slot 0 for SST
+       bool result = false;
+       uint8_t req_slot_count = 0;
+       struct fixed31_32 avg_time_slots_per_mtp = { 0 };
+       union payload_table_update_status update_status = { 0 };
+       const uint32_t max_retries = 30;
+       uint32_t retries = 0;
+       DC_LOGGER_INIT(link->ctx->logger);
+
+       if (allocate)   {
+               avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
+               req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
+               /// Validation should filter out modes that exceed link BW
+               ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT);
+               if (req_slot_count > MAX_MTP_SLOT_COUNT)
+                       return false;
+       } else {
+               /// Leave req_slot_count = 0 if allocate is false.
+       }
+
+       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;
+
+       if (link->aux_access_disabled)
+               return true;
+
+       /// Write DPCD 2C0 = 1 to start updating
+       update_status.bits.VC_PAYLOAD_TABLE_UPDATED = 1;
+       core_link_write_dpcd(
+                       link,
+                       DP_PAYLOAD_TABLE_UPDATE_STATUS,
+                       &update_status.raw,
+                       1);
+
+       /// Program the changes in DPCD 1C0 - 1C2
+       ASSERT(vc_id == 1);
+       core_link_write_dpcd(
+                       link,
+                       DP_PAYLOAD_ALLOCATE_SET,
+                       &vc_id,
+                       1);
+
+       ASSERT(start_time_slot == 0);
+       core_link_write_dpcd(
+                       link,
+                       DP_PAYLOAD_ALLOCATE_START_TIME_SLOT,
+                       &start_time_slot,
+                       1);
+
+       core_link_write_dpcd(
+                       link,
+                       DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT,
+                       &req_slot_count,
+                       1);
+
+       /// Poll till DPCD 2C0 read 1
+       /// Try for at least 150ms (30 retries, with 5ms delay after each attempt)
+
+       while (retries < max_retries) {
+               if (core_link_read_dpcd(
+                               link,
+                               DP_PAYLOAD_TABLE_UPDATE_STATUS,
+                               &update_status.raw,
+                               1) == DC_OK) {
+                       if (update_status.bits.VC_PAYLOAD_TABLE_UPDATED == 1) {
+                               DC_LOG_DP2("SST Update Payload: downstream payload table updated.");
+                               result = true;
+                               break;
+                       }
+               } else {
+                       union dpcd_rev dpcdRev;
+
+                       if (core_link_read_dpcd(
+                                       link,
+                                       DP_DPCD_REV,
+                                       &dpcdRev.raw,
+                                       1) != DC_OK) {
+                               DC_LOG_ERROR("SST Update Payload: Unable to read DPCD revision "
+                                               "of sink while polling payload table "
+                                               "updated status bit.");
+                               break;
+                       }
+               }
+               retries++;
+               msleep(5);
+       }
+
+       if (!result && retries == max_retries) {
+               DC_LOG_ERROR("SST Update Payload: Payload table not updated after retries, "
+                               "continue on. Something is wrong with the branch.");
+               // TODO - DP2.0 Payload: Read and log the payload table from downstream branch
+       }
+
+       return result;
+}
+
+bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link)
+{
+       /*
+        * wait for ACT handled
+        */
+       int i;
+       const int act_retries = 30;
+       enum act_return_status result = ACT_FAILED;
+       union payload_table_update_status update_status = {0};
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+       union lane_align_status_updated lane_status_updated;
+       DC_LOGGER_INIT(link->ctx->logger);
+
+       if (link->aux_access_disabled)
+               return true;
+       for (i = 0; i < act_retries; i++) {
+               get_lane_status(link, link->cur_link_settings.lane_count, dpcd_lane_status, &lane_status_updated);
+
+               if (!dp_is_cr_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
+                               !dp_is_ch_eq_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
+                               !dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) ||
+                               !dp_is_interlane_aligned(lane_status_updated)) {
+                       DC_LOG_ERROR("SST Update Payload: Link loss occurred while "
+                                       "polling for ACT handled.");
+                       result = ACT_LINK_LOST;
+                       break;
+               }
+               core_link_read_dpcd(
+                               link,
+                               DP_PAYLOAD_TABLE_UPDATE_STATUS,
+                               &update_status.raw,
+                               1);
+
+               if (update_status.bits.ACT_HANDLED == 1) {
+                       DC_LOG_DP2("SST Update Payload: ACT handled by downstream.");
+                       result = ACT_SUCCESS;
+                       break;
+               }
+
+               msleep(5);
+       }
+
+       if (result == ACT_FAILED) {
+               DC_LOG_ERROR("SST Update Payload: ACT still not handled after retries, "
+                               "continue on. Something is wrong with the branch.");
+       }
+
+       return (result == ACT_SUCCESS);
+}
+
+struct fixed31_32 calculate_sst_avg_time_slots_per_mtp(
+               const struct dc_stream_state *stream,
+               const struct dc_link *link)
+{
+       struct fixed31_32 link_bw_effective =
+                       dc_fixpt_from_int(
+                                       dc_link_bandwidth_kbps(link, &link->cur_link_settings));
+       struct fixed31_32 timeslot_bw_effective =
+                       dc_fixpt_div_int(link_bw_effective, MAX_MTP_SLOT_COUNT);
+       struct fixed31_32 timing_bw =
+                       dc_fixpt_from_int(
+                                       dc_bandwidth_in_kbps_from_timing(&stream->timing));
+       struct fixed31_32 avg_time_slots_per_mtp =
+                       dc_fixpt_div(timing_bw, timeslot_bw_effective);
+
+       return avg_time_slots_per_mtp;
+}
+
+void dc_link_clear_dprx_states(struct dc_link *link)
+{
+       memset(&link->dprx_states, 0, sizeof(link->dprx_states));
+}
+
+void 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));
+}
+
+static void dsc_optc_config_log(struct display_stream_compressor *dsc,
+               struct dsc_optc_config *config)
+{
+       uint32_t precision = 1 << 28;
+       uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
+       uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
+       uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
+       DC_LOGGER_INIT(dsc->ctx->logger);
+
+       /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
+        * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
+        * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
+        */
+       ll_bytes_per_pix_fraq *= 10000000;
+       ll_bytes_per_pix_fraq /= precision;
+
+       DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
+                       config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
+       DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
+       DC_LOG_DSC("\tslice_width %d", config->slice_width);
+}
+
+bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
+{
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       bool result = false;
+
+       if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+               result = true;
+       else
+               result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
+       return result;
+}
+
+/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
+ * i.e. after dp_enable_dsc_on_rx() had been called
+ */
+void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+{
+       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+       struct dc *dc = pipe_ctx->stream->ctx->dc;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct pipe_ctx *odm_pipe;
+       int opp_cnt = 1;
+       DC_LOGGER_INIT(dsc->ctx->logger);
+
+       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+               opp_cnt++;
+
+       if (enable) {
+               struct dsc_config dsc_cfg;
+               struct dsc_optc_config dsc_optc_cfg;
+               enum optc_dsc_mode optc_dsc_mode;
+
+               /* Enable DSC hw block */
+               dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
+               dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+               dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+               dsc_cfg.color_depth = stream->timing.display_color_depth;
+               dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+               dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+               ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
+               dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
+
+               dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
+               dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+               for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+                       struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
+
+                       odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
+                       odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
+               }
+               dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
+               dsc_cfg.pic_width *= opp_cnt;
+
+               optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+
+               /* Enable DSC in encoder */
+               if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
+                               && !link_is_dp_128b_132b_signal(pipe_ctx)) {
+                       DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
+                       dsc_optc_config_log(dsc, &dsc_optc_cfg);
+                       pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
+                                                                       optc_dsc_mode,
+                                                                       dsc_optc_cfg.bytes_per_pixel,
+                                                                       dsc_optc_cfg.slice_width);
+
+                       /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
+               }
+
+               /* Enable DSC in OPTC */
+               DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
+               dsc_optc_config_log(dsc, &dsc_optc_cfg);
+               pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
+                                                       optc_dsc_mode,
+                                                       dsc_optc_cfg.bytes_per_pixel,
+                                                       dsc_optc_cfg.slice_width);
+       } else {
+               /* disable DSC in OPTC */
+               pipe_ctx->stream_res.tg->funcs->set_dsc_config(
+                               pipe_ctx->stream_res.tg,
+                               OPTC_DSC_DISABLED, 0, 0);
+
+               /* disable DSC in stream encoder */
+               if (dc_is_dp_signal(stream->signal)) {
+                       if (link_is_dp_128b_132b_signal(pipe_ctx))
+                               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+                                                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                                                                               false,
+                                                                               NULL,
+                                                                               true);
+                       else if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
+                                               pipe_ctx->stream_res.stream_enc,
+                                               OPTC_DSC_DISABLED, 0, 0);
+                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+                                                       pipe_ctx->stream_res.stream_enc, false, NULL, true);
+                       }
+               }
+
+               /* disable DSC block */
+               pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
+               for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+                       odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+       }
+}
+
+bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
+{
+       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+       bool result = false;
+
+       if (!pipe_ctx->stream->timing.flags.DSC)
+               goto out;
+       if (!dsc)
+               goto out;
+
+       if (enable) {
+               {
+                       dp_set_dsc_on_stream(pipe_ctx, true);
+                       result = true;
+               }
+       } else {
+               dp_set_dsc_on_rx(pipe_ctx, false);
+               dp_set_dsc_on_stream(pipe_ctx, false);
+               result = true;
+       }
+out:
+       return result;
+}
+
+/*
+ * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled;
+ * hence PPS info packet update need to use frame update instead of immediate update.
+ * Added parameter immediate_update for this purpose.
+ * The decision to use frame update is hard-coded in function dp_update_dsc_config(),
+ * which is the only place where a "false" would be passed in for param immediate_update.
+ *
+ * immediate_update is only applicable when DSC is enabled.
+ */
+bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update)
+{
+       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       DC_LOGGER_INIT(dsc->ctx->logger);
+
+       if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
+               return false;
+
+       if (enable) {
+               struct dsc_config dsc_cfg;
+               uint8_t dsc_packed_pps[128];
+
+               memset(&dsc_cfg, 0, sizeof(dsc_cfg));
+               memset(dsc_packed_pps, 0, 128);
+
+               /* Enable DSC hw block */
+               dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
+               dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+               dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+               dsc_cfg.color_depth = stream->timing.display_color_depth;
+               dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+               dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+
+               dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
+               memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps));
+               if (dc_is_dp_signal(stream->signal)) {
+                       DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
+                       if (link_is_dp_128b_132b_signal(pipe_ctx))
+                               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+                                                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                                                                               true,
+                                                                               &dsc_packed_pps[0],
+                                                                               immediate_update);
+                       else
+                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+                                               pipe_ctx->stream_res.stream_enc,
+                                               true,
+                                               &dsc_packed_pps[0],
+                                               immediate_update);
+               }
+       } else {
+               /* disable DSC PPS in stream encoder */
+               memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps));
+               if (dc_is_dp_signal(stream->signal)) {
+                       if (link_is_dp_128b_132b_signal(pipe_ctx))
+                               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+                                                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
+                                                                               false,
+                                                                               NULL,
+                                                                               true);
+                       else
+                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+                                               pipe_ctx->stream_res.stream_enc, false, NULL, true);
+               }
+       }
+
+       return true;
+}
+
+
+bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
+{
+       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+
+       if (!pipe_ctx->stream->timing.flags.DSC)
+               return false;
+       if (!dsc)
+               return false;
+
+       dp_set_dsc_on_stream(pipe_ctx, true);
+       dp_set_dsc_pps_sdp(pipe_ctx, true, false);
+       return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
deleted file mode 100644 (file)
index 6747e4b..0000000
+++ /dev/null
@@ -1,2375 +0,0 @@
-/*
- * Copyright 2015 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 "dm_services.h"
-#include "dc.h"
-#include "dc_link_dp.h"
-#include "dm_helpers.h"
-#include "opp.h"
-#include "dsc.h"
-#include "resource.h"
-
-#include "inc/core_types.h"
-#include "link_hwss.h"
-#include "link/link_ddc.h"
-#include "core_status.h"
-#include "dpcd_defs.h"
-
-#include "dc_dmub_srv.h"
-#include "dce/dmub_hw_lock_mgr.h"
-#include "link/link_dp_dpia.h"
-#include "inc/link_enc_cfg.h"
-#include "clk_mgr.h"
-#include "link/link_dp_trace.h"
-#include "link/link_dp_training.h"
-#include "link/link_dp_training_fixed_vs_pe_retimer.h"
-#include "link/link_dp_training_dpia.h"
-#include "link/link_dp_training_auxless.h"
-#include "link/link_dp_phy.h"
-#include "link/link_dp_capability.h"
-#define DC_LOGGER \
-       link->ctx->logger
-
-#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
-#include "link/link_dpcd.h"
-
-static uint8_t get_nibble_at_index(const uint8_t *buf,
-       uint32_t index)
-{
-       uint8_t nibble;
-       nibble = buf[index / 2];
-
-       if (index % 2)
-               nibble >>= 4;
-       else
-               nibble &= 0x0F;
-
-       return nibble;
-}
-
-enum dc_status read_hpd_rx_irq_data(
-       struct dc_link *link,
-       union hpd_irq_data *irq_data)
-{
-       static enum dc_status retval;
-
-       /* The HW reads 16 bytes from 200h on HPD,
-        * but if we get an AUX_DEFER, the HW cannot retry
-        * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
-        * fail, so we now explicitly read 6 bytes which is
-        * the req from the above mentioned test cases.
-        *
-        * For DP 1.4 we need to read those from 2002h range.
-        */
-       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
-               retval = core_link_read_dpcd(
-                       link,
-                       DP_SINK_COUNT,
-                       irq_data->raw,
-                       sizeof(union hpd_irq_data));
-       else {
-               /* Read 14 bytes in a single read and then copy only the required fields.
-                * This is more efficient than doing it in two separate AUX reads. */
-
-               uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
-
-               retval = core_link_read_dpcd(
-                       link,
-                       DP_SINK_COUNT_ESI,
-                       tmp,
-                       sizeof(tmp));
-
-               if (retval != DC_OK)
-                       return retval;
-
-               irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
-               irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
-               irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
-       }
-
-       return retval;
-}
-
-bool hpd_rx_irq_check_link_loss_status(
-       struct dc_link *link,
-       union hpd_irq_data *hpd_irq_dpcd_data)
-{
-       uint8_t irq_reg_rx_power_state = 0;
-       enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
-       union lane_status lane_status;
-       uint32_t lane;
-       bool sink_status_changed;
-       bool return_code;
-
-       sink_status_changed = false;
-       return_code = false;
-
-       if (link->cur_link_settings.lane_count == 0)
-               return return_code;
-
-       /*1. Check that Link Status changed, before re-training.*/
-
-       /*parse lane status*/
-       for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
-               /* check status of lanes 0,1
-                * changed DpcdAddress_Lane01Status (0x202)
-                */
-               lane_status.raw = get_nibble_at_index(
-                       &hpd_irq_dpcd_data->bytes.lane01_status.raw,
-                       lane);
-
-               if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
-                       !lane_status.bits.CR_DONE_0 ||
-                       !lane_status.bits.SYMBOL_LOCKED_0) {
-                       /* if one of the channel equalization, clock
-                        * recovery or symbol lock is dropped
-                        * consider it as (link has been
-                        * dropped) dp sink status has changed
-                        */
-                       sink_status_changed = true;
-                       break;
-               }
-       }
-
-       /* Check interlane align.*/
-       if (sink_status_changed ||
-               !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
-
-               DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
-
-               return_code = true;
-
-               /*2. Check that we can handle interrupt: Not in FS DOS,
-                *  Not in "Display Timeout" state, Link is trained.
-                */
-               dpcd_result = core_link_read_dpcd(link,
-                       DP_SET_POWER,
-                       &irq_reg_rx_power_state,
-                       sizeof(irq_reg_rx_power_state));
-
-               if (dpcd_result != DC_OK) {
-                       DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
-                               __func__);
-               } else {
-                       if (irq_reg_rx_power_state != DP_SET_POWER_D0)
-                               return_code = false;
-               }
-       }
-
-       return return_code;
-}
-
-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;
-}
-
-/*************************Short Pulse IRQ***************************/
-bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link)
-{
-       /*
-        * Don't handle RX IRQ unless one of following is met:
-        * 1) The link is established (cur_link_settings != unknown)
-        * 2) We know we're dealing with a branch device, SST or MST
-        */
-
-       if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
-               is_dp_branch_device(link))
-               return true;
-
-       return false;
-}
-
-static bool handle_hpd_irq_psr_sink(struct dc_link *link)
-{
-       union dpcd_psr_configuration psr_configuration;
-
-       if (!link->psr_settings.psr_feature_enabled)
-               return false;
-
-       dm_helpers_dp_read_dpcd(
-               link->ctx,
-               link,
-               368,/*DpcdAddress_PSR_Enable_Cfg*/
-               &psr_configuration.raw,
-               sizeof(psr_configuration.raw));
-
-       if (psr_configuration.bits.ENABLE) {
-               unsigned char dpcdbuf[3] = {0};
-               union psr_error_status psr_error_status;
-               union psr_sink_psr_status psr_sink_psr_status;
-
-               dm_helpers_dp_read_dpcd(
-                       link->ctx,
-                       link,
-                       0x2006, /*DpcdAddress_PSR_Error_Status*/
-                       (unsigned char *) dpcdbuf,
-                       sizeof(dpcdbuf));
-
-               /*DPCD 2006h   ERROR STATUS*/
-               psr_error_status.raw = dpcdbuf[0];
-               /*DPCD 2008h   SINK PANEL SELF REFRESH STATUS*/
-               psr_sink_psr_status.raw = dpcdbuf[2];
-
-               if (psr_error_status.bits.LINK_CRC_ERROR ||
-                               psr_error_status.bits.RFB_STORAGE_ERROR ||
-                               psr_error_status.bits.VSC_SDP_ERROR) {
-                       bool allow_active;
-
-                       /* Acknowledge and clear error bits */
-                       dm_helpers_dp_write_dpcd(
-                               link->ctx,
-                               link,
-                               8198,/*DpcdAddress_PSR_Error_Status*/
-                               &psr_error_status.raw,
-                               sizeof(psr_error_status.raw));
-
-                       /* PSR error, disable and re-enable PSR */
-                       if (link->psr_settings.psr_allow_active) {
-                               allow_active = false;
-                               dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
-                               allow_active = true;
-                               dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
-                       }
-
-                       return true;
-               } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS ==
-                               PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){
-                       /* No error is detect, PSR is active.
-                        * We should return with IRQ_HPD handled without
-                        * checking for loss of sync since PSR would have
-                        * powered down main link.
-                        */
-                       return true;
-               }
-       }
-       return false;
-}
-
-static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate)
-{
-       switch (test_rate) {
-       case DP_TEST_LINK_RATE_RBR:
-               return LINK_RATE_LOW;
-       case DP_TEST_LINK_RATE_HBR:
-               return LINK_RATE_HIGH;
-       case DP_TEST_LINK_RATE_HBR2:
-               return LINK_RATE_HIGH2;
-       case DP_TEST_LINK_RATE_HBR3:
-               return LINK_RATE_HIGH3;
-       case DP_TEST_LINK_RATE_UHBR10:
-               return LINK_RATE_UHBR10;
-       case DP_TEST_LINK_RATE_UHBR20:
-               return LINK_RATE_UHBR20;
-       case DP_TEST_LINK_RATE_UHBR13_5:
-               return LINK_RATE_UHBR13_5;
-       default:
-               return LINK_RATE_UNKNOWN;
-       }
-}
-
-static void dp_test_send_link_training(struct dc_link *link)
-{
-       struct dc_link_settings link_settings = {0};
-       uint8_t test_rate = 0;
-
-       core_link_read_dpcd(
-                       link,
-                       DP_TEST_LANE_COUNT,
-                       (unsigned char *)(&link_settings.lane_count),
-                       1);
-       core_link_read_dpcd(
-                       link,
-                       DP_TEST_LINK_RATE,
-                       &test_rate,
-                       1);
-       link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate);
-
-       /* Set preferred link settings */
-       link->verified_link_cap.lane_count = link_settings.lane_count;
-       link->verified_link_cap.link_rate = link_settings.link_rate;
-
-       dp_retrain_link_dp_test(link, &link_settings, false);
-}
-
-static bool is_dp_phy_sqaure_pattern(enum dp_test_pattern test_pattern)
-{
-       return (DP_TEST_PATTERN_SQUARE_BEGIN <= test_pattern &&
-                       test_pattern <= DP_TEST_PATTERN_SQUARE_END);
-}
-
-/* TODO Raven hbr2 compliance eye output is unstable
- * (toggling on and off) with debugger break
- * This caueses intermittent PHY automation failure
- * Need to look into the root cause */
-static void dp_test_send_phy_test_pattern(struct dc_link *link)
-{
-       union phy_test_pattern dpcd_test_pattern;
-       union lane_adjust dpcd_lane_adjustment[2];
-       unsigned char dpcd_post_cursor_2_adjustment = 0;
-       unsigned char test_pattern_buffer[
-                       (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
-                       DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
-       unsigned int test_pattern_size = 0;
-       enum dp_test_pattern test_pattern;
-       union lane_adjust dpcd_lane_adjust;
-       unsigned int lane;
-       struct link_training_settings link_training_settings;
-       unsigned char no_preshoot = 0;
-       unsigned char no_deemphasis = 0;
-
-       dpcd_test_pattern.raw = 0;
-       memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment));
-       memset(&link_training_settings, 0, sizeof(link_training_settings));
-
-       /* get phy test pattern and pattern parameters from DP receiver */
-       core_link_read_dpcd(
-                       link,
-                       DP_PHY_TEST_PATTERN,
-                       &dpcd_test_pattern.raw,
-                       sizeof(dpcd_test_pattern));
-       core_link_read_dpcd(
-                       link,
-                       DP_ADJUST_REQUEST_LANE0_1,
-                       &dpcd_lane_adjustment[0].raw,
-                       sizeof(dpcd_lane_adjustment));
-
-       /* prepare link training settings */
-       link_training_settings.link_settings = link->cur_link_settings;
-
-       link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings);
-
-       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
-                       link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT)
-               dp_fixed_vs_pe_read_lane_adjust(
-                               link,
-                               link_training_settings.dpcd_lane_settings);
-
-       /*get post cursor 2 parameters
-        * For DP 1.1a or eariler, this DPCD register's value is 0
-        * For DP 1.2 or later:
-        * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1
-        * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3
-        */
-       core_link_read_dpcd(
-                       link,
-                       DP_ADJUST_REQUEST_POST_CURSOR2,
-                       &dpcd_post_cursor_2_adjustment,
-                       sizeof(dpcd_post_cursor_2_adjustment));
-
-       /* translate request */
-       switch (dpcd_test_pattern.bits.PATTERN) {
-       case PHY_TEST_PATTERN_D10_2:
-               test_pattern = DP_TEST_PATTERN_D102;
-               break;
-       case PHY_TEST_PATTERN_SYMBOL_ERROR:
-               test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR;
-               break;
-       case PHY_TEST_PATTERN_PRBS7:
-               test_pattern = DP_TEST_PATTERN_PRBS7;
-               break;
-       case PHY_TEST_PATTERN_80BIT_CUSTOM:
-               test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
-               break;
-       case PHY_TEST_PATTERN_CP2520_1:
-               /* CP2520 pattern is unstable, temporarily use TPS4 instead */
-               test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
-                               DP_TEST_PATTERN_TRAINING_PATTERN4 :
-                               DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
-               break;
-       case PHY_TEST_PATTERN_CP2520_2:
-               /* CP2520 pattern is unstable, temporarily use TPS4 instead */
-               test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
-                               DP_TEST_PATTERN_TRAINING_PATTERN4 :
-                               DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
-               break;
-       case PHY_TEST_PATTERN_CP2520_3:
-               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
-               break;
-       case PHY_TEST_PATTERN_128b_132b_TPS1:
-               test_pattern = DP_TEST_PATTERN_128b_132b_TPS1;
-               break;
-       case PHY_TEST_PATTERN_128b_132b_TPS2:
-               test_pattern = DP_TEST_PATTERN_128b_132b_TPS2;
-               break;
-       case PHY_TEST_PATTERN_PRBS9:
-               test_pattern = DP_TEST_PATTERN_PRBS9;
-               break;
-       case PHY_TEST_PATTERN_PRBS11:
-               test_pattern = DP_TEST_PATTERN_PRBS11;
-               break;
-       case PHY_TEST_PATTERN_PRBS15:
-               test_pattern = DP_TEST_PATTERN_PRBS15;
-               break;
-       case PHY_TEST_PATTERN_PRBS23:
-               test_pattern = DP_TEST_PATTERN_PRBS23;
-               break;
-       case PHY_TEST_PATTERN_PRBS31:
-               test_pattern = DP_TEST_PATTERN_PRBS31;
-               break;
-       case PHY_TEST_PATTERN_264BIT_CUSTOM:
-               test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM;
-               break;
-       case PHY_TEST_PATTERN_SQUARE:
-               test_pattern = DP_TEST_PATTERN_SQUARE;
-               break;
-       case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
-               test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
-               no_preshoot = 1;
-               break;
-       case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
-               test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
-               no_deemphasis = 1;
-               break;
-       case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
-               test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
-               no_preshoot = 1;
-               no_deemphasis = 1;
-               break;
-       default:
-               test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
-       break;
-       }
-
-       if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
-               test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
-                               DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1;
-               core_link_read_dpcd(
-                               link,
-                               DP_TEST_80BIT_CUSTOM_PATTERN_7_0,
-                               test_pattern_buffer,
-                               test_pattern_size);
-       }
-
-       if (is_dp_phy_sqaure_pattern(test_pattern)) {
-               test_pattern_size = 1; // Square pattern data is 1 byte (DP spec)
-               core_link_read_dpcd(
-                               link,
-                               DP_PHY_SQUARE_PATTERN,
-                               test_pattern_buffer,
-                               test_pattern_size);
-       }
-
-       if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) {
-               test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256-
-                               DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1;
-               core_link_read_dpcd(
-                               link,
-                               DP_TEST_264BIT_CUSTOM_PATTERN_7_0,
-                               test_pattern_buffer,
-                               test_pattern_size);
-       }
-
-       for (lane = 0; lane <
-               (unsigned int)(link->cur_link_settings.lane_count);
-               lane++) {
-               dpcd_lane_adjust.raw =
-                       get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
-               if (link_dp_get_encoding_format(&link->cur_link_settings) ==
-                               DP_8b_10b_ENCODING) {
-                       link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING =
-                               (enum dc_voltage_swing)
-                               (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
-                       link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS =
-                               (enum dc_pre_emphasis)
-                               (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
-                       link_training_settings.hw_lane_settings[lane].POST_CURSOR2 =
-                               (enum dc_post_cursor2)
-                               ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
-               } else if (link_dp_get_encoding_format(&link->cur_link_settings) ==
-                               DP_128b_132b_ENCODING) {
-                       link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level =
-                                       dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
-                       link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot;
-                       link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis;
-               }
-       }
-
-       dp_hw_to_dpcd_lane_settings(&link_training_settings,
-                       link_training_settings.hw_lane_settings,
-                       link_training_settings.dpcd_lane_settings);
-       /*Usage: Measure DP physical lane signal
-        * by DP SI test equipment automatically.
-        * PHY test pattern request is generated by equipment via HPD interrupt.
-        * HPD needs to be active all the time. HPD should be active
-        * all the time. Do not touch it.
-        * forward request to DS
-        */
-       dc_link_dp_set_test_pattern(
-               link,
-               test_pattern,
-               DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED,
-               &link_training_settings,
-               test_pattern_buffer,
-               test_pattern_size);
-}
-
-static void dp_test_send_link_test_pattern(struct dc_link *link)
-{
-       union link_test_pattern dpcd_test_pattern;
-       union test_misc dpcd_test_params;
-       enum dp_test_pattern test_pattern;
-       enum dp_test_pattern_color_space test_pattern_color_space =
-                       DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
-       enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
-       struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
-       struct pipe_ctx *pipe_ctx = NULL;
-       int i;
-
-       memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
-       memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               if (pipes[i].stream == NULL)
-                       continue;
-
-               if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
-                       pipe_ctx = &pipes[i];
-                       break;
-               }
-       }
-
-       if (pipe_ctx == NULL)
-               return;
-
-       /* get link test pattern and pattern parameters */
-       core_link_read_dpcd(
-                       link,
-                       DP_TEST_PATTERN,
-                       &dpcd_test_pattern.raw,
-                       sizeof(dpcd_test_pattern));
-       core_link_read_dpcd(
-                       link,
-                       DP_TEST_MISC0,
-                       &dpcd_test_params.raw,
-                       sizeof(dpcd_test_params));
-
-       switch (dpcd_test_pattern.bits.PATTERN) {
-       case LINK_TEST_PATTERN_COLOR_RAMP:
-               test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
-       break;
-       case LINK_TEST_PATTERN_VERTICAL_BARS:
-               test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
-       break; /* black and white */
-       case LINK_TEST_PATTERN_COLOR_SQUARES:
-               test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
-                               TEST_DYN_RANGE_VESA ?
-                               DP_TEST_PATTERN_COLOR_SQUARES :
-                               DP_TEST_PATTERN_COLOR_SQUARES_CEA);
-       break;
-       default:
-               test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
-       break;
-       }
-
-       if (dpcd_test_params.bits.CLR_FORMAT == 0)
-               test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
-       else
-               test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
-                               DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
-                               DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
-
-       switch (dpcd_test_params.bits.BPC) {
-       case 0: // 6 bits
-               requestColorDepth = COLOR_DEPTH_666;
-               break;
-       case 1: // 8 bits
-               requestColorDepth = COLOR_DEPTH_888;
-               break;
-       case 2: // 10 bits
-               requestColorDepth = COLOR_DEPTH_101010;
-               break;
-       case 3: // 12 bits
-               requestColorDepth = COLOR_DEPTH_121212;
-               break;
-       default:
-               break;
-       }
-
-       switch (dpcd_test_params.bits.CLR_FORMAT) {
-       case 0:
-               pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
-               break;
-       case 1:
-               pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR422;
-               break;
-       case 2:
-               pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR444;
-               break;
-       default:
-               pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
-               break;
-       }
-
-
-       if (requestColorDepth != COLOR_DEPTH_UNDEFINED
-                       && pipe_ctx->stream->timing.display_color_depth != requestColorDepth) {
-               DC_LOG_DEBUG("%s: original bpc %d, changing to %d\n",
-                               __func__,
-                               pipe_ctx->stream->timing.display_color_depth,
-                               requestColorDepth);
-               pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
-       }
-
-       dp_update_dsc_config(pipe_ctx);
-
-       dc_link_dp_set_test_pattern(
-                       link,
-                       test_pattern,
-                       test_pattern_color_space,
-                       NULL,
-                       NULL,
-                       0);
-}
-
-static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
-{
-       union audio_test_mode            dpcd_test_mode = {0};
-       struct audio_test_pattern_type   dpcd_pattern_type = {0};
-       union audio_test_pattern_period  dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0};
-       enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
-
-       struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
-       struct pipe_ctx *pipe_ctx = &pipes[0];
-       unsigned int channel_count;
-       unsigned int channel = 0;
-       unsigned int modes = 0;
-       unsigned int sampling_rate_in_hz = 0;
-
-       // get audio test mode and test pattern parameters
-       core_link_read_dpcd(
-               link,
-               DP_TEST_AUDIO_MODE,
-               &dpcd_test_mode.raw,
-               sizeof(dpcd_test_mode));
-
-       core_link_read_dpcd(
-               link,
-               DP_TEST_AUDIO_PATTERN_TYPE,
-               &dpcd_pattern_type.value,
-               sizeof(dpcd_pattern_type));
-
-       channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT);
-
-       // read pattern periods for requested channels when sawTooth pattern is requested
-       if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
-                       dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) {
-
-               test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ?
-                               DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
-               // read period for each channel
-               for (channel = 0; channel < channel_count; channel++) {
-                       core_link_read_dpcd(
-                                                       link,
-                                                       DP_TEST_AUDIO_PERIOD_CH1 + channel,
-                                                       &dpcd_pattern_period[channel].raw,
-                                                       sizeof(dpcd_pattern_period[channel]));
-               }
-       }
-
-       // translate sampling rate
-       switch (dpcd_test_mode.bits.sampling_rate) {
-       case AUDIO_SAMPLING_RATE_32KHZ:
-               sampling_rate_in_hz = 32000;
-               break;
-       case AUDIO_SAMPLING_RATE_44_1KHZ:
-               sampling_rate_in_hz = 44100;
-               break;
-       case AUDIO_SAMPLING_RATE_48KHZ:
-               sampling_rate_in_hz = 48000;
-               break;
-       case AUDIO_SAMPLING_RATE_88_2KHZ:
-               sampling_rate_in_hz = 88200;
-               break;
-       case AUDIO_SAMPLING_RATE_96KHZ:
-               sampling_rate_in_hz = 96000;
-               break;
-       case AUDIO_SAMPLING_RATE_176_4KHZ:
-               sampling_rate_in_hz = 176400;
-               break;
-       case AUDIO_SAMPLING_RATE_192KHZ:
-               sampling_rate_in_hz = 192000;
-               break;
-       default:
-               sampling_rate_in_hz = 0;
-               break;
-       }
-
-       link->audio_test_data.flags.test_requested = 1;
-       link->audio_test_data.flags.disable_video = disable_video;
-       link->audio_test_data.sampling_rate = sampling_rate_in_hz;
-       link->audio_test_data.channel_count = channel_count;
-       link->audio_test_data.pattern_type = test_pattern;
-
-       if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) {
-               for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) {
-                       link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period;
-               }
-       }
-}
-
-void dc_link_dp_handle_automated_test(struct dc_link *link)
-{
-       union test_request test_request;
-       union test_response test_response;
-
-       memset(&test_request, 0, sizeof(test_request));
-       memset(&test_response, 0, sizeof(test_response));
-
-       core_link_read_dpcd(
-               link,
-               DP_TEST_REQUEST,
-               &test_request.raw,
-               sizeof(union test_request));
-       if (test_request.bits.LINK_TRAINING) {
-               /* ACK first to let DP RX test box monitor LT sequence */
-               test_response.bits.ACK = 1;
-               core_link_write_dpcd(
-                       link,
-                       DP_TEST_RESPONSE,
-                       &test_response.raw,
-                       sizeof(test_response));
-               dp_test_send_link_training(link);
-               /* no acknowledge request is needed again */
-               test_response.bits.ACK = 0;
-       }
-       if (test_request.bits.LINK_TEST_PATTRN) {
-               dp_test_send_link_test_pattern(link);
-               test_response.bits.ACK = 1;
-       }
-
-       if (test_request.bits.AUDIO_TEST_PATTERN) {
-               dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO);
-               test_response.bits.ACK = 1;
-       }
-
-       if (test_request.bits.PHY_TEST_PATTERN) {
-               dp_test_send_phy_test_pattern(link);
-               test_response.bits.ACK = 1;
-       }
-
-       /* send request acknowledgment */
-       if (test_response.bits.ACK)
-               core_link_write_dpcd(
-                       link,
-                       DP_TEST_RESPONSE,
-                       &test_response.raw,
-                       sizeof(test_response));
-}
-
-void dc_link_dp_handle_link_loss(struct dc_link *link)
-{
-       int i;
-       struct pipe_ctx *pipe_ctx;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
-               if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
-                       break;
-       }
-
-       if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
-               return;
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               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);
-       }
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               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) {
-                       // Always use max settings here for DP 1.4a LL Compliance CTS
-                       if (link->is_automated) {
-                               pipe_ctx->link_config.dp_link_settings.lane_count =
-                                               link->verified_link_cap.lane_count;
-                               pipe_ctx->link_config.dp_link_settings.link_rate =
-                                               link->verified_link_cap.link_rate;
-                               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);
-               }
-       }
-}
-
-bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
-                                                       bool defer_handling, bool *has_left_work)
-{
-       union hpd_irq_data hpd_irq_dpcd_data = {0};
-       union device_service_irq device_service_clear = {0};
-       enum dc_status result;
-       bool status = false;
-
-       if (out_link_loss)
-               *out_link_loss = false;
-
-       if (has_left_work)
-               *has_left_work = false;
-       /* For use cases related to down stream connection status change,
-        * PSR and device auto test, refer to function handle_sst_hpd_irq
-        * in DAL2.1*/
-
-       DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
-               __func__, link->link_index);
-
-
-        /* All the "handle_hpd_irq_xxx()" methods
-                * should be called only after
-                * dal_dpsst_ls_read_hpd_irq_data
-                * Order of calls is important too
-                */
-       result = 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;
-
-       if (result != DC_OK) {
-               DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",
-                       __func__);
-               return false;
-       }
-
-       if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
-               // Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC
-               link->is_automated = true;
-               device_service_clear.bits.AUTOMATED_TEST = 1;
-               core_link_write_dpcd(
-                       link,
-                       DP_DEVICE_SERVICE_IRQ_VECTOR,
-                       &device_service_clear.raw,
-                       sizeof(device_service_clear.raw));
-               device_service_clear.raw = 0;
-               if (defer_handling && has_left_work)
-                       *has_left_work = true;
-               else
-                       dc_link_dp_handle_automated_test(link);
-               return false;
-       }
-
-       if (!dc_link_dp_allow_hpd_rx_irq(link)) {
-               DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
-                       __func__, link->link_index);
-               return false;
-       }
-
-       if (handle_hpd_irq_psr_sink(link))
-               /* PSR-related error was detected and handled */
-               return true;
-
-       /* If PSR-related error handled, Main link may be off,
-        * so do not handle as a normal sink status change interrupt.
-        */
-
-       if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) {
-               if (defer_handling && has_left_work)
-                       *has_left_work = true;
-               return true;
-       }
-
-       /* check if we have MST msg and return since we poll for it */
-       if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
-               if (defer_handling && has_left_work)
-                       *has_left_work = true;
-               return false;
-       }
-
-       /* For now we only handle 'Downstream port status' case.
-        * If we got sink count changed it means
-        * Downstream port status changed,
-        * then DM should call DC to do the detection.
-        * NOTE: Do not handle link loss on eDP since it is internal link*/
-       if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
-               hpd_rx_irq_check_link_loss_status(
-                       link,
-                       &hpd_irq_dpcd_data)) {
-               /* Connectivity log: link loss */
-               CONN_DATA_LINK_LOSS(link,
-                                       hpd_irq_dpcd_data.raw,
-                                       sizeof(hpd_irq_dpcd_data),
-                                       "Status: ");
-
-               if (defer_handling && has_left_work)
-                       *has_left_work = true;
-               else
-                       dc_link_dp_handle_link_loss(link);
-
-               status = false;
-               if (out_link_loss)
-                       *out_link_loss = true;
-
-               dp_trace_link_loss_increment(link);
-       }
-
-       if (link->type == dc_connection_sst_branch &&
-               hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
-                       != link->dpcd_sink_count)
-               status = true;
-
-       /* reasons for HPD RX:
-        * 1. Link Loss - ie Re-train the Link
-        * 2. MST sideband message
-        * 3. Automated Test - ie. Internal Commit
-        * 4. CP (copy protection) - (not interesting for DM???)
-        * 5. DRR
-        * 6. Downstream Port status changed
-        * -ie. Detect - this the only one
-        * which is interesting for DM because
-        * it must call dc_link_detect.
-        */
-       return status;
-}
-
-static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern)
-{
-       if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern &&
-                       test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) ||
-                       test_pattern == DP_TEST_PATTERN_VIDEO_MODE)
-               return true;
-       else
-               return false;
-}
-
-static void set_crtc_test_pattern(struct dc_link *link,
-                               struct pipe_ctx *pipe_ctx,
-                               enum dp_test_pattern test_pattern,
-                               enum dp_test_pattern_color_space test_pattern_color_space)
-{
-       enum controller_dp_test_pattern controller_test_pattern;
-       enum dc_color_depth color_depth = pipe_ctx->
-               stream->timing.display_color_depth;
-       struct bit_depth_reduction_params params;
-       struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
-       int width = pipe_ctx->stream->timing.h_addressable +
-               pipe_ctx->stream->timing.h_border_left +
-               pipe_ctx->stream->timing.h_border_right;
-       int height = pipe_ctx->stream->timing.v_addressable +
-               pipe_ctx->stream->timing.v_border_bottom +
-               pipe_ctx->stream->timing.v_border_top;
-
-       memset(&params, 0, sizeof(params));
-
-       switch (test_pattern) {
-       case DP_TEST_PATTERN_COLOR_SQUARES:
-               controller_test_pattern =
-                               CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
-       break;
-       case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
-               controller_test_pattern =
-                               CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
-       break;
-       case DP_TEST_PATTERN_VERTICAL_BARS:
-               controller_test_pattern =
-                               CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
-       break;
-       case DP_TEST_PATTERN_HORIZONTAL_BARS:
-               controller_test_pattern =
-                               CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
-       break;
-       case DP_TEST_PATTERN_COLOR_RAMP:
-               controller_test_pattern =
-                               CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
-       break;
-       default:
-               controller_test_pattern =
-                               CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
-       break;
-       }
-
-       switch (test_pattern) {
-       case DP_TEST_PATTERN_COLOR_SQUARES:
-       case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
-       case DP_TEST_PATTERN_VERTICAL_BARS:
-       case DP_TEST_PATTERN_HORIZONTAL_BARS:
-       case DP_TEST_PATTERN_COLOR_RAMP:
-       {
-               /* disable bit depth reduction */
-               pipe_ctx->stream->bit_depth_params = params;
-               opp->funcs->opp_program_bit_depth_reduction(opp, &params);
-               if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
-                       pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
-                               controller_test_pattern, color_depth);
-               else if (link->dc->hwss.set_disp_pattern_generator) {
-                       struct pipe_ctx *odm_pipe;
-                       enum controller_dp_color_space controller_color_space;
-                       int opp_cnt = 1;
-                       int offset = 0;
-                       int dpg_width = width;
-
-                       switch (test_pattern_color_space) {
-                       case DP_TEST_PATTERN_COLOR_SPACE_RGB:
-                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
-                               break;
-                       case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
-                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
-                               break;
-                       case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
-                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
-                               break;
-                       case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
-                       default:
-                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
-                               DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__);
-                               ASSERT(0);
-                               break;
-                       }
-
-                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-                               opp_cnt++;
-                       dpg_width = width / opp_cnt;
-                       offset = dpg_width;
-
-                       link->dc->hwss.set_disp_pattern_generator(link->dc,
-                                       pipe_ctx,
-                                       controller_test_pattern,
-                                       controller_color_space,
-                                       color_depth,
-                                       NULL,
-                                       dpg_width,
-                                       height,
-                                       0);
-
-                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
-                               struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
-
-                               odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
-                               link->dc->hwss.set_disp_pattern_generator(link->dc,
-                                               odm_pipe,
-                                               controller_test_pattern,
-                                               controller_color_space,
-                                               color_depth,
-                                               NULL,
-                                               dpg_width,
-                                               height,
-                                               offset);
-                               offset += offset;
-                       }
-               }
-       }
-       break;
-       case DP_TEST_PATTERN_VIDEO_MODE:
-       {
-               /* restore bitdepth reduction */
-               resource_build_bit_depth_reduction_params(pipe_ctx->stream, &params);
-               pipe_ctx->stream->bit_depth_params = params;
-               opp->funcs->opp_program_bit_depth_reduction(opp, &params);
-               if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
-                       pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
-                               CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
-                               color_depth);
-               else if (link->dc->hwss.set_disp_pattern_generator) {
-                       struct pipe_ctx *odm_pipe;
-                       int opp_cnt = 1;
-                       int dpg_width;
-
-                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-                               opp_cnt++;
-
-                       dpg_width = width / opp_cnt;
-                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
-                               struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
-
-                               odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
-                               link->dc->hwss.set_disp_pattern_generator(link->dc,
-                                               odm_pipe,
-                                               CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
-                                               CONTROLLER_DP_COLOR_SPACE_UDEFINED,
-                                               color_depth,
-                                               NULL,
-                                               dpg_width,
-                                               height,
-                                               0);
-                       }
-                       link->dc->hwss.set_disp_pattern_generator(link->dc,
-                                       pipe_ctx,
-                                       CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
-                                       CONTROLLER_DP_COLOR_SPACE_UDEFINED,
-                                       color_depth,
-                                       NULL,
-                                       dpg_width,
-                                       height,
-                                       0);
-               }
-       }
-       break;
-
-       default:
-       break;
-       }
-}
-
-bool dc_link_dp_set_test_pattern(
-       struct dc_link *link,
-       enum dp_test_pattern test_pattern,
-       enum dp_test_pattern_color_space test_pattern_color_space,
-       const struct link_training_settings *p_link_settings,
-       const unsigned char *p_custom_pattern,
-       unsigned int cust_pattern_size)
-{
-       struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
-       struct pipe_ctx *pipe_ctx = NULL;
-       unsigned int lane;
-       unsigned int i;
-       unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0};
-       union dpcd_training_pattern training_pattern;
-       enum dpcd_phy_test_patterns pattern;
-
-       memset(&training_pattern, 0, sizeof(training_pattern));
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               if (pipes[i].stream == NULL)
-                       continue;
-
-               if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
-                       pipe_ctx = &pipes[i];
-                       break;
-               }
-       }
-
-       if (pipe_ctx == NULL)
-               return false;
-
-       /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */
-       if (link->test_pattern_enabled && test_pattern ==
-                       DP_TEST_PATTERN_VIDEO_MODE) {
-               /* Set CRTC Test Pattern */
-               set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
-               dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
-                               (uint8_t *)p_custom_pattern,
-                               (uint32_t)cust_pattern_size);
-
-               /* Unblank Stream */
-               link->dc->hwss.unblank_stream(
-                       pipe_ctx,
-                       &link->verified_link_cap);
-               /* TODO:m_pHwss->MuteAudioEndpoint
-                * (pPathMode->pDisplayPath, false);
-                */
-
-               /* Reset Test Pattern state */
-               link->test_pattern_enabled = false;
-
-               return true;
-       }
-
-       /* Check for PHY Test Patterns */
-       if (is_dp_phy_pattern(test_pattern)) {
-               /* Set DPCD Lane Settings before running test pattern */
-               if (p_link_settings != NULL) {
-                       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
-                                       p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
-                               dp_fixed_vs_pe_set_retimer_lane_settings(
-                                               link,
-                                               p_link_settings->dpcd_lane_settings,
-                                               p_link_settings->link_settings.lane_count);
-                       } else {
-                               dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX);
-                       }
-                       dpcd_set_lane_settings(link, p_link_settings, DPRX);
-               }
-
-               /* Blank stream if running test pattern */
-               if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
-                       /*TODO:
-                        * m_pHwss->
-                        * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
-                        */
-                       /* Blank stream */
-                       link->dc->hwss.blank_stream(pipe_ctx);
-               }
-
-               dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
-                               (uint8_t *)p_custom_pattern,
-                               (uint32_t)cust_pattern_size);
-
-               if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
-                       /* Set Test Pattern state */
-                       link->test_pattern_enabled = true;
-                       if (p_link_settings != NULL)
-                               dpcd_set_link_settings(link,
-                                               p_link_settings);
-               }
-
-               switch (test_pattern) {
-               case DP_TEST_PATTERN_VIDEO_MODE:
-                       pattern = PHY_TEST_PATTERN_NONE;
-                       break;
-               case DP_TEST_PATTERN_D102:
-                       pattern = PHY_TEST_PATTERN_D10_2;
-                       break;
-               case DP_TEST_PATTERN_SYMBOL_ERROR:
-                       pattern = PHY_TEST_PATTERN_SYMBOL_ERROR;
-                       break;
-               case DP_TEST_PATTERN_PRBS7:
-                       pattern = PHY_TEST_PATTERN_PRBS7;
-                       break;
-               case DP_TEST_PATTERN_80BIT_CUSTOM:
-                       pattern = PHY_TEST_PATTERN_80BIT_CUSTOM;
-                       break;
-               case DP_TEST_PATTERN_CP2520_1:
-                       pattern = PHY_TEST_PATTERN_CP2520_1;
-                       break;
-               case DP_TEST_PATTERN_CP2520_2:
-                       pattern = PHY_TEST_PATTERN_CP2520_2;
-                       break;
-               case DP_TEST_PATTERN_CP2520_3:
-                       pattern = PHY_TEST_PATTERN_CP2520_3;
-                       break;
-               case DP_TEST_PATTERN_128b_132b_TPS1:
-                       pattern = PHY_TEST_PATTERN_128b_132b_TPS1;
-                       break;
-               case DP_TEST_PATTERN_128b_132b_TPS2:
-                       pattern = PHY_TEST_PATTERN_128b_132b_TPS2;
-                       break;
-               case DP_TEST_PATTERN_PRBS9:
-                       pattern = PHY_TEST_PATTERN_PRBS9;
-                       break;
-               case DP_TEST_PATTERN_PRBS11:
-                       pattern = PHY_TEST_PATTERN_PRBS11;
-                       break;
-               case DP_TEST_PATTERN_PRBS15:
-                       pattern = PHY_TEST_PATTERN_PRBS15;
-                       break;
-               case DP_TEST_PATTERN_PRBS23:
-                       pattern = PHY_TEST_PATTERN_PRBS23;
-                       break;
-               case DP_TEST_PATTERN_PRBS31:
-                       pattern = PHY_TEST_PATTERN_PRBS31;
-                       break;
-               case DP_TEST_PATTERN_264BIT_CUSTOM:
-                       pattern = PHY_TEST_PATTERN_264BIT_CUSTOM;
-                       break;
-               case DP_TEST_PATTERN_SQUARE:
-                       pattern = PHY_TEST_PATTERN_SQUARE;
-                       break;
-               case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
-                       pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
-                       break;
-               case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
-                       pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
-                       break;
-               case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
-                       pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
-                       break;
-               default:
-                       return false;
-               }
-
-               if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE
-               /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/)
-                       return false;
-
-               if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
-                       if (is_dp_phy_sqaure_pattern(test_pattern))
-                               core_link_write_dpcd(link,
-                                               DP_LINK_SQUARE_PATTERN,
-                                               p_custom_pattern,
-                                               1);
-
-                       /* tell receiver that we are sending qualification
-                        * pattern DP 1.2 or later - DP receiver's link quality
-                        * pattern is set using DPCD LINK_QUAL_LANEx_SET
-                        * register (0x10B~0x10E)\
-                        */
-                       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++)
-                               link_qual_pattern[lane] =
-                                               (unsigned char)(pattern);
-
-                       core_link_write_dpcd(link,
-                                       DP_LINK_QUAL_LANE0_SET,
-                                       link_qual_pattern,
-                                       sizeof(link_qual_pattern));
-               } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 ||
-                          link->dpcd_caps.dpcd_rev.raw == 0) {
-                       /* tell receiver that we are sending qualification
-                        * pattern DP 1.1a or earlier - DP receiver's link
-                        * quality pattern is set using
-                        * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET
-                        * register (0x102). We will use v_1.3 when we are
-                        * setting test pattern for DP 1.1.
-                        */
-                       core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
-                                           &training_pattern.raw,
-                                           sizeof(training_pattern));
-                       training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
-                       core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
-                                            &training_pattern.raw,
-                                            sizeof(training_pattern));
-               }
-       } else {
-               enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
-
-               switch (test_pattern_color_space) {
-               case DP_TEST_PATTERN_COLOR_SPACE_RGB:
-                       color_space = COLOR_SPACE_SRGB;
-                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
-                               color_space = COLOR_SPACE_SRGB_LIMITED;
-                       break;
-
-               case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
-                       color_space = COLOR_SPACE_YCBCR601;
-                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
-                               color_space = COLOR_SPACE_YCBCR601_LIMITED;
-                       break;
-               case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
-                       color_space = COLOR_SPACE_YCBCR709;
-                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
-                               color_space = COLOR_SPACE_YCBCR709_LIMITED;
-                       break;
-               default:
-                       break;
-               }
-
-               if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) {
-                       if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
-                               union dmub_hw_lock_flags hw_locks = { 0 };
-                               struct dmub_hw_lock_inst_flags inst_flags = { 0 };
-
-                               hw_locks.bits.lock_dig = 1;
-                               inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
-
-                               dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
-                                                       true,
-                                                       &hw_locks,
-                                                       &inst_flags);
-                       } else
-                               pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable(
-                                               pipe_ctx->stream_res.tg);
-               }
-
-               pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
-               /* update MSA to requested color space */
-               pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc,
-                               &pipe_ctx->stream->timing,
-                               color_space,
-                               pipe_ctx->stream->use_vsc_sdp_for_colorimetry,
-                               link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
-
-               if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) {
-                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
-                               pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range
-                       else
-                               pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7);
-                       resource_build_info_frame(pipe_ctx);
-                       link->dc->hwss.update_info_frame(pipe_ctx);
-               }
-
-               /* CRTC Patterns */
-               set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
-               pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
-               pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
-                               CRTC_STATE_VACTIVE);
-               pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
-                               CRTC_STATE_VBLANK);
-               pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
-                               CRTC_STATE_VACTIVE);
-
-               if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) {
-                       if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
-                               union dmub_hw_lock_flags hw_locks = { 0 };
-                               struct dmub_hw_lock_inst_flags inst_flags = { 0 };
-
-                               hw_locks.bits.lock_dig = 1;
-                               inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
-
-                               dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
-                                                       false,
-                                                       &hw_locks,
-                                                       &inst_flags);
-                       } else
-                               pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable(
-                                               pipe_ctx->stream_res.tg);
-               }
-
-               /* Set Test Pattern state */
-               link->test_pattern_enabled = true;
-       }
-
-       return true;
-}
-
-void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
-{
-       unsigned char mstmCntl;
-
-       core_link_read_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
-       if (enable)
-               mstmCntl |= DP_MST_EN;
-       else
-               mstmCntl &= (~DP_MST_EN);
-
-       core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
-}
-
-void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
-{
-       union dpcd_edp_config edp_config_set;
-       bool panel_mode_edp = false;
-
-       memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
-
-       if (panel_mode != DP_PANEL_MODE_DEFAULT) {
-
-               switch (panel_mode) {
-               case DP_PANEL_MODE_EDP:
-               case DP_PANEL_MODE_SPECIAL:
-                       panel_mode_edp = true;
-                       break;
-
-               default:
-                               break;
-               }
-
-               /*set edp panel mode in receiver*/
-               core_link_read_dpcd(
-                       link,
-                       DP_EDP_CONFIGURATION_SET,
-                       &edp_config_set.raw,
-                       sizeof(edp_config_set.raw));
-
-               if (edp_config_set.bits.PANEL_MODE_EDP
-                       != panel_mode_edp) {
-                       enum dc_status result;
-
-                       edp_config_set.bits.PANEL_MODE_EDP =
-                       panel_mode_edp;
-                       result = core_link_write_dpcd(
-                               link,
-                               DP_EDP_CONFIGURATION_SET,
-                               &edp_config_set.raw,
-                               sizeof(edp_config_set.raw));
-
-                       ASSERT(result == DC_OK);
-               }
-       }
-       DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
-                "eDP panel mode enabled: %d \n",
-                link->link_index,
-                link->dpcd_caps.panel_mode_edp,
-                panel_mode_edp);
-}
-
-enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
-{
-       /* We need to explicitly check that connector
-        * is not DP. Some Travis_VGA get reported
-        * by video bios as DP.
-        */
-       if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
-
-               switch (link->dpcd_caps.branch_dev_id) {
-               case DP_BRANCH_DEVICE_ID_0022B9:
-                       /* alternate scrambler reset is required for Travis
-                        * for the case when external chip does not
-                        * provide sink device id, alternate scrambler
-                        * scheme will  be overriden later by querying
-                        * Encoder features
-                        */
-                       if (strncmp(
-                               link->dpcd_caps.branch_dev_name,
-                               DP_VGA_LVDS_CONVERTER_ID_2,
-                               sizeof(
-                               link->dpcd_caps.
-                               branch_dev_name)) == 0) {
-                                       return DP_PANEL_MODE_SPECIAL;
-                       }
-                       break;
-               case DP_BRANCH_DEVICE_ID_00001A:
-                       /* alternate scrambler reset is required for Travis
-                        * for the case when external chip does not provide
-                        * sink device id, alternate scrambler scheme will
-                        * be overriden later by querying Encoder feature
-                        */
-                       if (strncmp(link->dpcd_caps.branch_dev_name,
-                               DP_VGA_LVDS_CONVERTER_ID_3,
-                               sizeof(
-                               link->dpcd_caps.
-                               branch_dev_name)) == 0) {
-                                       return DP_PANEL_MODE_SPECIAL;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       if (link->dpcd_caps.panel_mode_edp &&
-               (link->connector_signal == SIGNAL_TYPE_EDP ||
-                (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
-                 link->is_internal_display))) {
-               return DP_PANEL_MODE_EDP;
-       }
-
-       return DP_PANEL_MODE_DEFAULT;
-}
-
-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;
-               }
-       }
-}
-
-bool dc_link_set_backlight_level_nits(struct dc_link *link,
-               bool isHDR,
-               uint32_t backlight_millinits,
-               uint32_t transition_time_in_ms)
-{
-       struct dpcd_source_backlight_set dpcd_backlight_set;
-       uint8_t backlight_control = isHDR ? 1 : 0;
-
-       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
-                       link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
-               return false;
-
-       // OLEDs have no PWM, they can only use AUX
-       if (link->dpcd_sink_ext_caps.bits.oled == 1)
-               backlight_control = 1;
-
-       *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
-       *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
-
-
-       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
-                       (uint8_t *)(&dpcd_backlight_set),
-                       sizeof(dpcd_backlight_set)) != DC_OK)
-               return false;
-
-       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL,
-                       &backlight_control, 1) != DC_OK)
-               return false;
-
-       return true;
-}
-
-bool dc_link_get_backlight_level_nits(struct dc_link *link,
-               uint32_t *backlight_millinits_avg,
-               uint32_t *backlight_millinits_peak)
-{
-       union dpcd_source_backlight_get dpcd_backlight_get;
-
-       memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get));
-
-       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
-                       link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
-               return false;
-
-       if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
-                       dpcd_backlight_get.raw,
-                       sizeof(union dpcd_source_backlight_get)))
-               return false;
-
-       *backlight_millinits_avg =
-               dpcd_backlight_get.bytes.backlight_millinits_avg;
-       *backlight_millinits_peak =
-               dpcd_backlight_get.bytes.backlight_millinits_peak;
-
-       /* On non-supported panels dpcd_read usually succeeds with 0 returned */
-       if (*backlight_millinits_avg == 0 ||
-                       *backlight_millinits_avg > *backlight_millinits_peak)
-               return false;
-
-       return true;
-}
-
-bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable)
-{
-       uint8_t backlight_enable = enable ? 1 : 0;
-
-       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
-               link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
-               return false;
-
-       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
-               &backlight_enable, 1) != DC_OK)
-               return false;
-
-       return true;
-}
-
-// we read default from 0x320 because we expect BIOS wrote it there
-// regular get_backlight_nit reads from panel set at 0x326
-bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits)
-{
-       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
-               link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
-               return false;
-
-       if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
-               (uint8_t *) backlight_millinits,
-               sizeof(uint32_t)))
-               return false;
-
-       return true;
-}
-
-bool dc_link_set_default_brightness_aux(struct dc_link *link)
-{
-       uint32_t default_backlight;
-
-       if (link && link->dpcd_sink_ext_caps.bits.oled == 1) {
-               if (!dc_link_read_default_bl_aux(link, &default_backlight))
-                       default_backlight = 150000;
-               // if < 5 nits or > 5000, it might be wrong readback
-               if (default_backlight < 5000 || default_backlight > 5000000)
-                       default_backlight = 150000; //
-
-               return dc_link_set_backlight_level_nits(link, true,
-                               default_backlight, 0);
-       }
-       return false;
-}
-
-bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing)
-{
-       struct dc_link_settings link_setting;
-       uint8_t link_bw_set;
-       uint8_t link_rate_set;
-       uint32_t req_bw;
-       union lane_count_set lane_count_set = {0};
-
-       ASSERT(link || crtc_timing); // invalid input
-
-       if (link->dpcd_caps.edp_supported_link_rates_count == 0 ||
-                       !link->panel_config.ilr.optimize_edp_link_rate)
-               return false;
-
-
-       // Read DPCD 00100h to find if standard link rates are set
-       core_link_read_dpcd(link, DP_LINK_BW_SET,
-                               &link_bw_set, sizeof(link_bw_set));
-
-       if (link_bw_set) {
-               DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS used link_bw_set\n");
-               return true;
-       }
-
-       // Read DPCD 00115h to find the edp link rate set used
-       core_link_read_dpcd(link, DP_LINK_RATE_SET,
-                           &link_rate_set, sizeof(link_rate_set));
-
-       // Read DPCD 00101h to find out the number of lanes currently set
-       core_link_read_dpcd(link, DP_LANE_COUNT_SET,
-                               &lane_count_set.raw, sizeof(lane_count_set));
-
-       req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing);
-
-       if (!crtc_timing->flags.DSC)
-               dc_link_decide_edp_link_settings(link, &link_setting, req_bw);
-       else
-               decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN);
-
-       if (link->dpcd_caps.edp_supported_link_rates[link_rate_set] != link_setting.link_rate ||
-                       lane_count_set.bits.LANE_COUNT_SET != link_setting.lane_count) {
-               DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n");
-               return true;
-       }
-
-       DC_LOG_EVENT_LINK_TRAINING("eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n");
-       return false;
-}
-
-
-// TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST)
-static void get_lane_status(
-       struct dc_link *link,
-       uint32_t lane_count,
-       union lane_status *status,
-       union lane_align_status_updated *status_updated)
-{
-       unsigned int lane;
-       uint8_t dpcd_buf[3] = {0};
-
-       if (status == NULL || status_updated == NULL) {
-               return;
-       }
-
-       core_link_read_dpcd(
-                       link,
-                       DP_LANE0_1_STATUS,
-                       dpcd_buf,
-                       sizeof(dpcd_buf));
-
-       for (lane = 0; lane < lane_count; lane++) {
-               status[lane].raw = get_nibble_at_index(&dpcd_buf[0], lane);
-       }
-
-       status_updated->raw = dpcd_buf[2];
-}
-
-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)
-{
-       const uint8_t vc_id = 1; /// VC ID always 1 for SST
-       const uint8_t start_time_slot = 0; /// Always start at time slot 0 for SST
-       bool result = false;
-       uint8_t req_slot_count = 0;
-       struct fixed31_32 avg_time_slots_per_mtp = { 0 };
-       union payload_table_update_status update_status = { 0 };
-       const uint32_t max_retries = 30;
-       uint32_t retries = 0;
-
-       if (allocate)   {
-               avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
-               req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
-               /// Validation should filter out modes that exceed link BW
-               ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT);
-               if (req_slot_count > MAX_MTP_SLOT_COUNT)
-                       return false;
-       } else {
-               /// Leave req_slot_count = 0 if allocate is false.
-       }
-
-       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;
-
-       if (link->aux_access_disabled)
-               return true;
-
-       /// Write DPCD 2C0 = 1 to start updating
-       update_status.bits.VC_PAYLOAD_TABLE_UPDATED = 1;
-       core_link_write_dpcd(
-                       link,
-                       DP_PAYLOAD_TABLE_UPDATE_STATUS,
-                       &update_status.raw,
-                       1);
-
-       /// Program the changes in DPCD 1C0 - 1C2
-       ASSERT(vc_id == 1);
-       core_link_write_dpcd(
-                       link,
-                       DP_PAYLOAD_ALLOCATE_SET,
-                       &vc_id,
-                       1);
-
-       ASSERT(start_time_slot == 0);
-       core_link_write_dpcd(
-                       link,
-                       DP_PAYLOAD_ALLOCATE_START_TIME_SLOT,
-                       &start_time_slot,
-                       1);
-
-       core_link_write_dpcd(
-                       link,
-                       DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT,
-                       &req_slot_count,
-                       1);
-
-       /// Poll till DPCD 2C0 read 1
-       /// Try for at least 150ms (30 retries, with 5ms delay after each attempt)
-
-       while (retries < max_retries) {
-               if (core_link_read_dpcd(
-                               link,
-                               DP_PAYLOAD_TABLE_UPDATE_STATUS,
-                               &update_status.raw,
-                               1) == DC_OK) {
-                       if (update_status.bits.VC_PAYLOAD_TABLE_UPDATED == 1) {
-                               DC_LOG_DP2("SST Update Payload: downstream payload table updated.");
-                               result = true;
-                               break;
-                       }
-               } else {
-                       union dpcd_rev dpcdRev;
-
-                       if (core_link_read_dpcd(
-                                       link,
-                                       DP_DPCD_REV,
-                                       &dpcdRev.raw,
-                                       1) != DC_OK) {
-                               DC_LOG_ERROR("SST Update Payload: Unable to read DPCD revision "
-                                               "of sink while polling payload table "
-                                               "updated status bit.");
-                               break;
-                       }
-               }
-               retries++;
-               msleep(5);
-       }
-
-       if (!result && retries == max_retries) {
-               DC_LOG_ERROR("SST Update Payload: Payload table not updated after retries, "
-                               "continue on. Something is wrong with the branch.");
-               // TODO - DP2.0 Payload: Read and log the payload table from downstream branch
-       }
-
-       return result;
-}
-
-bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link)
-{
-       /*
-        * wait for ACT handled
-        */
-       int i;
-       const int act_retries = 30;
-       enum act_return_status result = ACT_FAILED;
-       union payload_table_update_status update_status = {0};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
-       union lane_align_status_updated lane_status_updated;
-
-       if (link->aux_access_disabled)
-               return true;
-       for (i = 0; i < act_retries; i++) {
-               get_lane_status(link, link->cur_link_settings.lane_count, dpcd_lane_status, &lane_status_updated);
-
-               if (!dp_is_cr_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
-                               !dp_is_ch_eq_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
-                               !dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) ||
-                               !dp_is_interlane_aligned(lane_status_updated)) {
-                       DC_LOG_ERROR("SST Update Payload: Link loss occurred while "
-                                       "polling for ACT handled.");
-                       result = ACT_LINK_LOST;
-                       break;
-               }
-               core_link_read_dpcd(
-                               link,
-                               DP_PAYLOAD_TABLE_UPDATE_STATUS,
-                               &update_status.raw,
-                               1);
-
-               if (update_status.bits.ACT_HANDLED == 1) {
-                       DC_LOG_DP2("SST Update Payload: ACT handled by downstream.");
-                       result = ACT_SUCCESS;
-                       break;
-               }
-
-               msleep(5);
-       }
-
-       if (result == ACT_FAILED) {
-               DC_LOG_ERROR("SST Update Payload: ACT still not handled after retries, "
-                               "continue on. Something is wrong with the branch.");
-       }
-
-       return (result == ACT_SUCCESS);
-}
-
-struct fixed31_32 calculate_sst_avg_time_slots_per_mtp(
-               const struct dc_stream_state *stream,
-               const struct dc_link *link)
-{
-       struct fixed31_32 link_bw_effective =
-                       dc_fixpt_from_int(
-                                       dc_link_bandwidth_kbps(link, &link->cur_link_settings));
-       struct fixed31_32 timeslot_bw_effective =
-                       dc_fixpt_div_int(link_bw_effective, MAX_MTP_SLOT_COUNT);
-       struct fixed31_32 timing_bw =
-                       dc_fixpt_from_int(
-                                       dc_bandwidth_in_kbps_from_timing(&stream->timing));
-       struct fixed31_32 avg_time_slots_per_mtp =
-                       dc_fixpt_div(timing_bw, timeslot_bw_effective);
-
-       return avg_time_slots_per_mtp;
-}
-
-void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd)
-{
-       if (link->connector_signal != SIGNAL_TYPE_EDP)
-               return;
-
-       link->dc->hwss.edp_power_control(link, true);
-       if (wait_for_hpd)
-               link->dc->hwss.edp_wait_for_hpd_ready(link, true);
-       if (link->dc->hwss.edp_backlight_control)
-               link->dc->hwss.edp_backlight_control(link, true);
-}
-
-void dc_link_clear_dprx_states(struct dc_link *link)
-{
-       memset(&link->dprx_states, 0, sizeof(link->dprx_states));
-}
-
-void 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));
-}
-
-void edp_add_delay_for_T9(struct dc_link *link)
-{
-       if (link && link->panel_config.pps.extra_delay_backlight_off > 0)
-               udelay(link->panel_config.pps.extra_delay_backlight_off * 1000);
-}
-
-bool edp_receiver_ready_T9(struct dc_link *link)
-{
-       unsigned int tries = 0;
-       unsigned char sinkstatus = 0;
-       unsigned char edpRev = 0;
-       enum dc_status result = DC_OK;
-
-       result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
-
-       /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
-       if (result == DC_OK && edpRev >= DP_EDP_12) {
-               do {
-                       sinkstatus = 1;
-                       result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
-                       if (sinkstatus == 0)
-                               break;
-                       if (result != DC_OK)
-                               break;
-                       udelay(100); //MAx T9
-               } while (++tries < 50);
-       }
-
-       return result;
-}
-bool edp_receiver_ready_T7(struct dc_link *link)
-{
-       unsigned char sinkstatus = 0;
-       unsigned char edpRev = 0;
-       enum dc_status result = DC_OK;
-
-       /* use absolute time stamp to constrain max T7*/
-       unsigned long long enter_timestamp = 0;
-       unsigned long long finish_timestamp = 0;
-       unsigned long long time_taken_in_ns = 0;
-
-       result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
-
-       if (result == DC_OK && edpRev >= DP_EDP_12) {
-               /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
-               enter_timestamp = dm_get_timestamp(link->ctx);
-               do {
-                       sinkstatus = 0;
-                       result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
-                       if (sinkstatus == 1)
-                               break;
-                       if (result != DC_OK)
-                               break;
-                       udelay(25);
-                       finish_timestamp = dm_get_timestamp(link->ctx);
-                       time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
-               } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms
-       }
-
-       if (link && link->panel_config.pps.extra_t7_ms > 0)
-               udelay(link->panel_config.pps.extra_t7_ms * 1000);
-
-       return result;
-}
-
-void dp_retrain_link_dp_test(struct dc_link *link,
-                       struct dc_link_settings *link_setting,
-                       bool skip_video_pattern)
-{
-       struct pipe_ctx *pipe;
-       unsigned int i;
-
-       udelay(100);
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
-               if (pipe->stream != NULL &&
-                               pipe->stream->link == link &&
-                               !pipe->stream->dpms_off &&
-                               !pipe->top_pipe && !pipe->prev_odm_pipe) {
-                       core_link_disable_stream(pipe);
-                       pipe->link_config.dp_link_settings = *link_setting;
-                       update_dp_encoder_resources_for_test_harness(
-                                       link->dc,
-                                       pipe->stream->ctx->dc->current_state,
-                                       pipe);
-               }
-       }
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
-               if (pipe->stream != NULL &&
-                               pipe->stream->link == link &&
-                               !pipe->stream->dpms_off &&
-                               !pipe->top_pipe && !pipe->prev_odm_pipe) {
-                       core_link_enable_stream(
-                                       pipe->stream->ctx->dc->current_state,
-                                       pipe);
-               }
-       }
-}
-
-#undef DC_LOGGER
-#define DC_LOGGER \
-       dsc->ctx->logger
-static void dsc_optc_config_log(struct display_stream_compressor *dsc,
-               struct dsc_optc_config *config)
-{
-       uint32_t precision = 1 << 28;
-       uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
-       uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
-       uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
-
-       /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
-        * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
-        * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
-        */
-       ll_bytes_per_pix_fraq *= 10000000;
-       ll_bytes_per_pix_fraq /= precision;
-
-       DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
-                       config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
-       DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
-       DC_LOG_DSC("\tslice_width %d", config->slice_width);
-}
-
-bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
-{
-       struct dc *dc = pipe_ctx->stream->ctx->dc;
-       struct dc_stream_state *stream = pipe_ctx->stream;
-       bool result = false;
-
-       if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
-               result = true;
-       else
-               result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
-       return result;
-}
-
-/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
- * i.e. after dp_enable_dsc_on_rx() had been called
- */
-void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
-{
-       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
-       struct dc *dc = pipe_ctx->stream->ctx->dc;
-       struct dc_stream_state *stream = pipe_ctx->stream;
-       struct pipe_ctx *odm_pipe;
-       int opp_cnt = 1;
-
-       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-               opp_cnt++;
-
-       if (enable) {
-               struct dsc_config dsc_cfg;
-               struct dsc_optc_config dsc_optc_cfg;
-               enum optc_dsc_mode optc_dsc_mode;
-
-               /* Enable DSC hw block */
-               dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
-               dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
-               dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
-               dsc_cfg.color_depth = stream->timing.display_color_depth;
-               dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
-               dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
-               ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
-               dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
-
-               dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
-               dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
-               for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
-                       struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
-
-                       odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
-                       odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
-               }
-               dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
-               dsc_cfg.pic_width *= opp_cnt;
-
-               optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
-
-               /* Enable DSC in encoder */
-               if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
-                               && !link_is_dp_128b_132b_signal(pipe_ctx)) {
-                       DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
-                       dsc_optc_config_log(dsc, &dsc_optc_cfg);
-                       pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
-                                                                       optc_dsc_mode,
-                                                                       dsc_optc_cfg.bytes_per_pixel,
-                                                                       dsc_optc_cfg.slice_width);
-
-                       /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
-               }
-
-               /* Enable DSC in OPTC */
-               DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
-               dsc_optc_config_log(dsc, &dsc_optc_cfg);
-               pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
-                                                       optc_dsc_mode,
-                                                       dsc_optc_cfg.bytes_per_pixel,
-                                                       dsc_optc_cfg.slice_width);
-       } else {
-               /* disable DSC in OPTC */
-               pipe_ctx->stream_res.tg->funcs->set_dsc_config(
-                               pipe_ctx->stream_res.tg,
-                               OPTC_DSC_DISABLED, 0, 0);
-
-               /* disable DSC in stream encoder */
-               if (dc_is_dp_signal(stream->signal)) {
-                       if (link_is_dp_128b_132b_signal(pipe_ctx))
-                               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
-                                                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
-                                                                               false,
-                                                                               NULL,
-                                                                               true);
-                       else if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
-                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
-                                               pipe_ctx->stream_res.stream_enc,
-                                               OPTC_DSC_DISABLED, 0, 0);
-                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
-                                                       pipe_ctx->stream_res.stream_enc, false, NULL, true);
-                       }
-               }
-
-               /* disable DSC block */
-               pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
-               for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-                       odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
-       }
-}
-
-bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
-{
-       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
-       bool result = false;
-
-       if (!pipe_ctx->stream->timing.flags.DSC)
-               goto out;
-       if (!dsc)
-               goto out;
-
-       if (enable) {
-               {
-                       dp_set_dsc_on_stream(pipe_ctx, true);
-                       result = true;
-               }
-       } else {
-               dp_set_dsc_on_rx(pipe_ctx, false);
-               dp_set_dsc_on_stream(pipe_ctx, false);
-               result = true;
-       }
-out:
-       return result;
-}
-
-/*
- * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled;
- * hence PPS info packet update need to use frame update instead of immediate update.
- * Added parameter immediate_update for this purpose.
- * The decision to use frame update is hard-coded in function dp_update_dsc_config(),
- * which is the only place where a "false" would be passed in for param immediate_update.
- *
- * immediate_update is only applicable when DSC is enabled.
- */
-bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update)
-{
-       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
-       struct dc_stream_state *stream = pipe_ctx->stream;
-
-       if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
-               return false;
-
-       if (enable) {
-               struct dsc_config dsc_cfg;
-               uint8_t dsc_packed_pps[128];
-
-               memset(&dsc_cfg, 0, sizeof(dsc_cfg));
-               memset(dsc_packed_pps, 0, 128);
-
-               /* Enable DSC hw block */
-               dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
-               dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
-               dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
-               dsc_cfg.color_depth = stream->timing.display_color_depth;
-               dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
-               dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
-
-               dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
-               memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps));
-               if (dc_is_dp_signal(stream->signal)) {
-                       DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
-                       if (link_is_dp_128b_132b_signal(pipe_ctx))
-                               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
-                                                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
-                                                                               true,
-                                                                               &dsc_packed_pps[0],
-                                                                               immediate_update);
-                       else
-                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
-                                               pipe_ctx->stream_res.stream_enc,
-                                               true,
-                                               &dsc_packed_pps[0],
-                                               immediate_update);
-               }
-       } else {
-               /* disable DSC PPS in stream encoder */
-               memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps));
-               if (dc_is_dp_signal(stream->signal)) {
-                       if (link_is_dp_128b_132b_signal(pipe_ctx))
-                               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
-                                                                               pipe_ctx->stream_res.hpo_dp_stream_enc,
-                                                                               false,
-                                                                               NULL,
-                                                                               true);
-                       else
-                               pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
-                                               pipe_ctx->stream_res.stream_enc, false, NULL, true);
-               }
-       }
-
-       return true;
-}
-
-
-bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
-{
-       struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
-
-       if (!pipe_ctx->stream->timing.flags.DSC)
-               return false;
-       if (!dsc)
-               return false;
-
-       dp_set_dsc_on_stream(pipe_ctx, true);
-       dp_set_dsc_pps_sdp(pipe_ctx, true, false);
-       return true;
-}
-
-#undef DC_LOGGER
-#define DC_LOGGER \
-       link->ctx->logger
index fa2ba3f..74e465b 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "link_enc_cfg.h"
 #include "resource.h"
-#include "dc_link_dp.h"
 #include "link.h"
 
 #define DC_LOGGER dc->ctx->logger
index a5b5f85..e41bbcb 100644 (file)
 #include "virtual/virtual_stream_encoder.h"
 #include "dpcd_defs.h"
 #include "link_enc_cfg.h"
-#include "dc_link_dp.h"
 #include "link.h"
 #include "virtual/virtual_link_hwss.h"
-#include "link/link_hwss_dio.h"
-#include "link/link_hwss_dpia.h"
-#include "link/link_hwss_hpo_dp.h"
+#include "link/hwss/link_hwss_dio.h"
+#include "link/hwss/link_hwss_dpia.h"
+#include "link/hwss/link_hwss_hpo_dp.h"
 
 #if defined(CONFIG_DRM_AMD_DC_SI)
 #include "dce60/dce60_resource.h"
@@ -3270,6 +3269,50 @@ static void set_hfvs_info_packet(
        *info_packet = stream->hfvsif_infopacket;
 }
 
+static void adaptive_sync_override_dp_info_packets_sdp_line_num(
+               const struct dc_crtc_timing *timing,
+               struct enc_sdp_line_num *sdp_line_num,
+               struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
+{
+       uint32_t asic_blank_start = 0;
+       uint32_t asic_blank_end   = 0;
+       uint32_t v_update = 0;
+
+       const struct dc_crtc_timing *tg = timing;
+
+       /* blank_start = frame end - front porch */
+       asic_blank_start = tg->v_total - tg->v_front_porch;
+
+       /* blank_end = blank_start - active */
+       asic_blank_end = (asic_blank_start - tg->v_border_bottom -
+                                               tg->v_addressable - tg->v_border_top);
+
+       if (pipe_dlg_param->vstartup_start > asic_blank_end) {
+               v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end));
+               sdp_line_num->adaptive_sync_line_num_valid = true;
+               sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
+       } else {
+               sdp_line_num->adaptive_sync_line_num_valid = false;
+               sdp_line_num->adaptive_sync_line_num = 0;
+       }
+}
+
+static void set_adaptive_sync_info_packet(
+               struct dc_info_packet *info_packet,
+               const struct dc_stream_state *stream,
+               struct encoder_info_frame *info_frame,
+               struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
+{
+       if (!stream->adaptive_sync_infopacket.valid)
+               return;
+
+       adaptive_sync_override_dp_info_packets_sdp_line_num(
+                       &stream->timing,
+                       &info_frame->sdp_line_num,
+                       pipe_dlg_param);
+
+       *info_packet = stream->adaptive_sync_infopacket;
+}
 
 static void set_vtem_info_packet(
                struct dc_info_packet *info_packet,
@@ -3362,6 +3405,7 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
        info->vsc.valid = false;
        info->hfvsif.valid = false;
        info->vtem.valid = false;
+       info->adaptive_sync.valid = false;
        signal = pipe_ctx->stream->signal;
 
        /* HDMi and DP have different info packets*/
@@ -3382,6 +3426,10 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
                set_spd_info_packet(&info->spd, pipe_ctx->stream);
 
                set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
+               set_adaptive_sync_info_packet(&info->adaptive_sync,
+                                                                               pipe_ctx->stream,
+                                                                               info,
+                                                                               &pipe_ctx->pipe_dlg_param);
        }
 
        patch_gamut_packet_checksum(&info->gamut);
index 22e754a..42ce453 100644 (file)
@@ -47,7 +47,7 @@ struct aux_payload;
 struct set_config_cmd_payload;
 struct dmub_notification;
 
-#define DC_VER "3.2.218"
+#define DC_VER "3.2.220"
 
 #define MAX_SURFACES 3
 #define MAX_PLANES 6
@@ -1414,6 +1414,7 @@ struct dpcd_caps {
        union dpcd_fec_capability fec_cap;
        struct dpcd_dsc_capabilities dsc_caps;
        struct dc_lttpr_caps lttpr_caps;
+       struct adaptive_sync_caps adaptive_sync_caps;
        struct dpcd_usb4_dp_tunneling_info usb4_dp_tun_info;
 
        union dp_128b_132b_supported_link_rates dp_128b_132b_supported_link_rates;
index 84da543..1845838 100644 (file)
@@ -502,7 +502,11 @@ union down_spread_ctrl {
        1 = Main link signal is downspread <= 0.5%
        with frequency in the range of 30kHz ~ 33kHz*/
                uint8_t SPREAD_AMP:1;
-               uint8_t RESERVED2:2;/*Bit 6:5 = RESERVED. Read all 0s*/
+               uint8_t RESERVED2:1;/*Bit 5 = RESERVED. Read all 0s*/
+       /* Bit 6 = FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE.
+       0 = FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE is not enabled by the Source device (default)
+       1 = FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE is enabled by Source device */
+               uint8_t FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE:1;
        /*Bit 7 = MSA_TIMING_PAR_IGNORE_EN
        0 = Source device will send valid data for the MSA Timing Params
        1 = Source device may send invalid data for these MSA Timing Params*/
@@ -858,6 +862,21 @@ struct psr_caps {
        unsigned int psr_power_opt_flag;
 };
 
+union dpcd_dprx_feature_enumeration_list_cont_1 {
+       struct {
+               uint8_t ADAPTIVE_SYNC_SDP_SUPPORT:1;
+               uint8_t AS_SDP_FIRST_HALF_LINE_OR_3840_PIXEL_CYCLE_WINDOW_NOT_SUPPORTED: 1;
+               uint8_t RESERVED0: 2;
+               uint8_t VSC_EXT_SDP_VER1_SUPPORT: 1;
+               uint8_t RESERVED1: 3;
+       } bits;
+       uint8_t raw;
+};
+
+struct adaptive_sync_caps {
+       union dpcd_dprx_feature_enumeration_list_cont_1 dp_adap_sync_caps;
+};
+
 /* Length of router topology ID read from DPCD in bytes. */
 #define DPCD_USB4_TOPOLOGY_ID_LEN 5
 
index 48f6a5b..1927eac 100644 (file)
@@ -280,6 +280,7 @@ struct dc_link {
                bool dp_keep_receiver_powered;
                bool dp_skip_DID2;
                bool dp_skip_reset_segment;
+               bool dp_skip_fs_144hz;
                bool dp_mot_reset_segment;
                /* Some USB4 docks do not handle turning off MST DSC once it has been enabled. */
                bool dpia_mst_dsc_always_on;
@@ -370,11 +371,6 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link,
                uint32_t *backlight_millinits,
                uint32_t *backlight_millinits_peak);
 
-bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable);
-
-bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits);
-bool dc_link_set_default_brightness_aux(struct dc_link *link);
-
 int dc_link_get_backlight_level(const struct dc_link *dc_link);
 
 int dc_link_get_target_backlight_pwm(const struct dc_link *link);
@@ -388,16 +384,10 @@ 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);
 
-bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable);
-
-void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency);
-
 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);
-bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link,
-               uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);
 
 /* Request DC to detect if there is a Panel connected.
  * boot - If this call is during initial boot.
@@ -441,7 +431,8 @@ bool dc_link_wait_for_t12(struct dc_link *link);
 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);
 struct dc_sink_init_data;
 
 struct dc_sink *dc_link_add_remote_sink(
@@ -456,11 +447,6 @@ void dc_link_remove_remote_sink(
 
 /* Used by diagnostics for virtual link at the moment */
 
-void dc_link_dp_set_drive_settings(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings);
-
 bool dc_link_dp_set_test_pattern(
        struct dc_link *link,
        enum dp_test_pattern test_pattern,
@@ -589,4 +575,56 @@ void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on);
 bool dc_link_decide_edp_link_settings(struct dc_link *link,
                struct dc_link_settings *link_setting,
                uint32_t req_bw);
+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);
+
 #endif /* DC_LINK_H_ */
index ef33d7d..5674525 100644 (file)
@@ -190,6 +190,7 @@ struct dc_stream_state {
        struct dc_info_packet vsp_infopacket;
        struct dc_info_packet hfvsif_infopacket;
        struct dc_info_packet vtem_infopacket;
+       struct dc_info_packet adaptive_sync_infopacket;
        uint8_t dsc_packed_pps[128];
        struct rect src; /* composition area */
        struct rect dst; /* stream addressable area */
@@ -313,6 +314,7 @@ struct dc_stream_update {
        struct dc_info_packet *vsp_infopacket;
        struct dc_info_packet *hfvsif_infopacket;
        struct dc_info_packet *vtem_infopacket;
+       struct dc_info_packet *adaptive_sync_infopacket;
        bool *dpms_off;
        bool integer_scaling_update;
        bool *allow_freesync;
index c73a655..f653eca 100644 (file)
@@ -691,6 +691,7 @@ struct psr_config {
        uint8_t su_y_granularity;
        unsigned int line_time_in_us;
        uint8_t rate_control_caps;
+       uint16_t dsc_slice_height;
 };
 
 union dmcu_psr_level {
@@ -802,6 +803,7 @@ struct psr_context {
        uint8_t su_y_granularity;
        unsigned int line_time_in_us;
        uint8_t rate_control_caps;
+       uint16_t dsc_slice_height;
 };
 
 struct colorspace_transform {
index 2d3201b..1e2d2cb 100644 (file)
@@ -417,6 +417,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
        copy_settings_data->relock_delay_frame_cnt = 0;
        if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
                copy_settings_data->relock_delay_frame_cnt = 2;
+       copy_settings_data->dsc_slice_height = psr_context->dsc_slice_height;
 
        dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
        dc_dmub_srv_cmd_execute(dc->dmub_srv);
index a51bd21..adb36be 100644 (file)
@@ -47,7 +47,6 @@
 #include "link_enc_cfg.h"
 #include "link_hwss.h"
 #include "link.h"
-#include "dc_link_dp.h"
 #include "dccg.h"
 #include "clock_source.h"
 #include "clk_mgr.h"
@@ -65,7 +64,6 @@
 
 #include "dcn10/dcn10_hw_sequencer.h"
 
-#include "link/link_dp_trace.h"
 #include "dce110_hw_sequencer.h"
 
 #define GAMMA_HW_POINTS_NUM 256
@@ -653,10 +651,16 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
                pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
-       else
+       else {
+               if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+                       pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+                               pipe_ctx->stream_res.stream_enc,
+                               &pipe_ctx->stream_res.encoder_info_frame);
+
                pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
+       }
 }
 
 void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
@@ -807,19 +811,19 @@ void dce110_edp_power_control(
                                div64_u64(dm_get_elapse_time_in_ns(
                                                ctx,
                                                current_ts,
-                                               dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
+                                               link_dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
                unsigned long long time_since_edp_poweron_ms =
                                div64_u64(dm_get_elapse_time_in_ns(
                                                ctx,
                                                current_ts,
-                                               dp_trace_get_edp_poweron_timestamp(link)), 1000000);
+                                               link_dp_trace_get_edp_poweron_timestamp(link)), 1000000);
                DC_LOG_HW_RESUME_S3(
                                "%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu",
                                __func__,
                                power_up,
                                current_ts,
-                               dp_trace_get_edp_poweroff_timestamp(link),
-                               dp_trace_get_edp_poweron_timestamp(link),
+                               link_dp_trace_get_edp_poweroff_timestamp(link),
+                               link_dp_trace_get_edp_poweron_timestamp(link),
                                time_since_edp_poweroff_ms,
                                time_since_edp_poweron_ms);
 
@@ -834,7 +838,7 @@ void dce110_edp_power_control(
                                        link->panel_config.pps.extra_t12_ms;
 
                        /* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */
-                       if (dp_trace_get_edp_poweroff_timestamp(link) != 0) {
+                       if (link_dp_trace_get_edp_poweroff_timestamp(link) != 0) {
                                if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms)
                                        remaining_min_edp_poweroff_time_ms =
                                                remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms;
@@ -894,13 +898,13 @@ void dce110_edp_power_control(
                                __func__, (power_up ? "On":"Off"),
                                bp_result);
 
-               dp_trace_set_edp_power_timestamp(link, power_up);
+               link_dp_trace_set_edp_power_timestamp(link, power_up);
 
                DC_LOG_HW_RESUME_S3(
                                "%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n",
                                __func__,
-                               dp_trace_get_edp_poweroff_timestamp(link),
-                               dp_trace_get_edp_poweron_timestamp(link));
+                               link_dp_trace_get_edp_poweroff_timestamp(link),
+                               link_dp_trace_get_edp_poweron_timestamp(link));
 
                if (bp_result != BP_RESULT_OK)
                        DC_LOG_ERROR(
@@ -928,14 +932,14 @@ void dce110_edp_wait_for_T12(
                return;
 
        if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) &&
-                       dp_trace_get_edp_poweroff_timestamp(link) != 0) {
+                       link_dp_trace_get_edp_poweroff_timestamp(link) != 0) {
                unsigned int t12_duration = 500; // Default T12 as per spec
                unsigned long long current_ts = dm_get_timestamp(ctx);
                unsigned long long time_since_edp_poweroff_ms =
                                div64_u64(dm_get_elapse_time_in_ns(
                                                ctx,
                                                current_ts,
-                                               dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
+                                               link_dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
 
                t12_duration += link->panel_config.pps.extra_t12_ms; // Add extra T12
 
@@ -1016,7 +1020,7 @@ void dce110_edp_backlight_control(
                 * we shouldn't be doing power-sequencing, hence we can skip
                 * waiting for T7-ready.
                 */
-                       edp_receiver_ready_T7(link);
+                       link_edp_receiver_ready_T7(link);
                else
                        DC_LOG_DC("edp_receiver_ready_T7 skipped\n");
        }
@@ -1047,7 +1051,7 @@ void dce110_edp_backlight_control(
        if (link->dpcd_sink_ext_caps.bits.oled ||
                link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
                link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)
-               dc_link_backlight_enable_aux(link, enable);
+               link_backlight_enable_aux(link, enable);
 
        /*edp 1.2*/
        if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) {
@@ -1059,7 +1063,7 @@ void dce110_edp_backlight_control(
                 * we shouldn't be doing power-sequencing, hence we can skip
                 * waiting for T9-ready.
                 */
-                       edp_add_delay_for_T9(link);
+                       link_edp_add_delay_for_T9(link);
                else
                        DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
        }
@@ -1243,7 +1247,7 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
                                 * we shouldn't be doing power-sequencing, hence we can skip
                                 * waiting for T9-ready.
                                 */
-                               edp_receiver_ready_T9(link);
+                               link_edp_receiver_ready_T9(link);
                        }
                }
        }
index 0a0c930..bb15573 100644 (file)
@@ -45,7 +45,6 @@
 #include "dcn10_hubp.h"
 #include "dcn10_hubbub.h"
 #include "dcn10_cm_common.h"
-#include "dc_link_dp.h"
 #include "dccg.h"
 #include "clk_mgr.h"
 #include "link_hwss.h"
@@ -56,7 +55,6 @@
 #include "dce/dmub_hw_lock_mgr.h"
 #include "dc_trace.h"
 #include "dce/dmub_outbox.h"
-#include "inc/dc_link_dp.h"
 #include "link.h"
 
 #define DC_LOGGER_INIT(logger)
index 1527c3b..a1e32b9 100644 (file)
@@ -28,7 +28,7 @@
 #include "dcn10_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "dc_link_dp.h"
+#include "link.h"
 #include "dpcd_defs.h"
 #include "dcn30/dcn30_afmt.h"
 
@@ -753,12 +753,19 @@ void enc1_stream_encoder_update_dp_info_packets(
         * use other packetIndex (such as 5,6) for other info packet
         */
 
+       if (info_frame->adaptive_sync.valid)
+               enc1_update_generic_info_packet(
+                               enc1,
+                               5,  /* packetIndex */
+                               &info_frame->adaptive_sync);
+
        /* enable/disable transmission of packet(s).
         * If enabled, packet transmission begins on the next frame
         */
        REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, info_frame->vsc.valid);
        REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, info_frame->spd.valid);
        REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, info_frame->hdrsmd.valid);
+       REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, info_frame->adaptive_sync.valid);
 
        /* This bit is the master enable bit.
         * When enabling secondary stream engine,
index 6bfa16d..916dcee 100644 (file)
@@ -46,7 +46,6 @@
 #include "dchubbub.h"
 #include "reg_helper.h"
 #include "dcn10/dcn10_cm_common.h"
-#include "dc_link_dp.h"
 #include "vm_helper.h"
 #include "dccg.h"
 #include "dc_dmub_srv.h"
@@ -2023,8 +2022,11 @@ void dcn20_prepare_bandwidth(
                }
        }
 
-       /* program dchubbub watermarks */
-       dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub,
+       /* program dchubbub watermarks:
+        * For assigning wm_optimized_required, use |= operator since we don't want
+        * to clear the value if the optimize has not happened yet
+        */
+       dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub,
                                        &context->bw_ctx.bw.dcn.watermarks,
                                        dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
                                        false);
index cacf3f5..48f662b 100644 (file)
@@ -29,7 +29,7 @@
 #include "dcn20_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "dc_link_dp.h"
+#include "link.h"
 #include "dpcd_defs.h"
 
 #define DC_LOGGER \
@@ -423,6 +423,22 @@ void enc2_set_dynamic_metadata(struct stream_encoder *enc,
        }
 }
 
+static void enc2_stream_encoder_update_dp_info_packets_sdp_line_num(
+               struct stream_encoder *enc,
+               struct encoder_info_frame *info_frame)
+{
+       struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+       if (info_frame->adaptive_sync.valid == true &&
+               info_frame->sdp_line_num.adaptive_sync_line_num_valid == true) {
+               //00: REFER_TO_DP_SOF, 01: REFER_TO_OTG_SOF
+               REG_UPDATE(DP_SEC_CNTL1, DP_SEC_GSP5_LINE_REFERENCE, 1);
+
+               REG_UPDATE(DP_SEC_CNTL5, DP_SEC_GSP5_LINE_NUM,
+                                       info_frame->sdp_line_num.adaptive_sync_line_num);
+       }
+}
+
 static void enc2_stream_encoder_update_dp_info_packets(
        struct stream_encoder *enc,
        const struct encoder_info_frame *info_frame)
@@ -587,6 +603,8 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
                enc2_stream_encoder_update_hdmi_info_packets,
        .stop_hdmi_info_packets =
                enc2_stream_encoder_stop_hdmi_info_packets,
+       .update_dp_info_packets_sdp_line_num =
+               enc2_stream_encoder_update_dp_info_packets_sdp_line_num,
        .update_dp_info_packets =
                enc2_stream_encoder_update_dp_info_packets,
        .send_immediate_sdp_message =
index 17df537..5f9079d 100644 (file)
@@ -404,6 +404,22 @@ static void enc3_read_state(struct stream_encoder *enc, struct enc_state *s)
        }
 }
 
+void enc3_stream_encoder_update_dp_info_packets_sdp_line_num(
+               struct stream_encoder *enc,
+               struct encoder_info_frame *info_frame)
+{
+       struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+       if (info_frame->adaptive_sync.valid == true &&
+               info_frame->sdp_line_num.adaptive_sync_line_num_valid == true) {
+               //00: REFER_TO_DP_SOF, 01: REFER_TO_OTG_SOF
+               REG_UPDATE(DP_SEC_CNTL1, DP_SEC_GSP5_LINE_REFERENCE, 1);
+
+               REG_UPDATE(DP_SEC_CNTL5, DP_SEC_GSP5_LINE_NUM,
+                                       info_frame->sdp_line_num.adaptive_sync_line_num);
+       }
+}
+
 void enc3_stream_encoder_update_dp_info_packets(
        struct stream_encoder *enc,
        const struct encoder_info_frame *info_frame)
@@ -452,12 +468,20 @@ void enc3_stream_encoder_update_dp_info_packets(
         * use other packetIndex (such as 5,6) for other info packet
         */
 
+       if (info_frame->adaptive_sync.valid)
+               enc->vpg->funcs->update_generic_info_packet(
+                               enc->vpg,
+                               5,  /* packetIndex */
+                               &info_frame->adaptive_sync,
+                               true);
+
        /* enable/disable transmission of packet(s).
         * If enabled, packet transmission begins on the next frame
         */
        REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, info_frame->vsc.valid);
        REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, info_frame->spd.valid);
        REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, info_frame->hdrsmd.valid);
+       REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, info_frame->adaptive_sync.valid);
 
        /* This bit is the master enable bit.
         * When enabling secondary stream engine,
@@ -803,6 +827,8 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = {
                enc3_stream_encoder_update_hdmi_info_packets,
        .stop_hdmi_info_packets =
                enc3_stream_encoder_stop_hdmi_info_packets,
+       .update_dp_info_packets_sdp_line_num =
+               enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
        .update_dp_info_packets =
                enc3_stream_encoder_update_dp_info_packets,
        .stop_dp_info_packets =
index 54ee230..0631097 100644 (file)
@@ -292,6 +292,10 @@ void enc3_stream_encoder_update_hdmi_info_packets(
 void enc3_stream_encoder_stop_hdmi_info_packets(
        struct stream_encoder *enc);
 
+void enc3_stream_encoder_update_dp_info_packets_sdp_line_num(
+               struct stream_encoder *enc,
+               struct encoder_info_frame *info_frame);
+
 void enc3_stream_encoder_update_dp_info_packets(
        struct stream_encoder *enc,
        const struct encoder_info_frame *info_frame);
index 7360b3c..444f9fa 100644 (file)
@@ -50,7 +50,7 @@
 #include "dpcd_defs.h"
 #include "../dcn20/dcn20_hwseq.h"
 #include "dcn30_resource.h"
-#include "inc/dc_link_dp.h"
+#include "link.h"
 
 
 
@@ -674,10 +674,16 @@ void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
                pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
-       else
+       else {
+               if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+                       pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+                               pipe_ctx->stream_res.stream_enc,
+                               &pipe_ctx->stream_res.encoder_info_frame);
+
                pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
+       }
 }
 
 void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
index 16639bd..d76f55a 100644 (file)
@@ -430,6 +430,22 @@ static void dcn31_hpo_dp_stream_enc_set_stream_attribute(
                        MSA_DATA_LANE_3, 0);
 }
 
+static void dcn31_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num(
+               struct hpo_dp_stream_encoder *enc,
+               struct encoder_info_frame *info_frame)
+{
+       struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+       if (info_frame->adaptive_sync.valid == true &&
+               info_frame->sdp_line_num.adaptive_sync_line_num_valid == true) {
+               //00: REFER_TO_DP_SOF, 01: REFER_TO_OTG_SOF
+               REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_SOF_REFERENCE, 1);
+
+               REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_TRANSMISSION_LINE_NUMBER,
+                                       info_frame->sdp_line_num.adaptive_sync_line_num);
+       }
+}
+
 static void dcn31_hpo_dp_stream_enc_update_dp_info_packets(
                struct hpo_dp_stream_encoder *enc,
                const struct encoder_info_frame *info_frame)
@@ -458,12 +474,20 @@ static void dcn31_hpo_dp_stream_enc_update_dp_info_packets(
                                &info_frame->hdrsmd,
                                true);
 
+       if (info_frame->adaptive_sync.valid)
+               enc->vpg->funcs->update_generic_info_packet(
+                               enc->vpg,
+                               5,  /* packetIndex */
+                               &info_frame->adaptive_sync,
+                               true);
+
        /* enable/disable transmission of packet(s).
         * If enabled, packet transmission begins on the next frame
         */
        REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->vsc.valid);
        REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL2, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->spd.valid);
        REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL3, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->hdrsmd.valid);
+       REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->adaptive_sync.valid);
 
        /* check if dynamic metadata packet transmission is enabled */
        REG_GET(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL,
@@ -714,6 +738,7 @@ static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = {
        .dp_blank = dcn31_hpo_dp_stream_enc_dp_blank,
        .disable = dcn31_hpo_dp_stream_enc_disable,
        .set_stream_attribute = dcn31_hpo_dp_stream_enc_set_stream_attribute,
+       .update_dp_info_packets_sdp_line_num = dcn31_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num,
        .update_dp_info_packets = dcn31_hpo_dp_stream_enc_update_dp_info_packets,
        .stop_dp_info_packets = dcn31_hpo_dp_stream_enc_stop_dp_info_packets,
        .dp_set_dsc_pps_info_packet = dcn31_hpo_dp_stream_enc_set_dsc_pps_info_packet,
index 0e1949d..9871f9e 100644 (file)
@@ -45,7 +45,6 @@
 #include "link_hwss.h"
 #include "dpcd_defs.h"
 #include "dce/dmub_outbox.h"
-#include "dc_link_dp.h"
 #include "link.h"
 #include "dcn10/dcn10_hw_sequencer.h"
 #include "inc/link_enc_cfg.h"
@@ -421,6 +420,11 @@ void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx)
                                &pipe_ctx->stream_res.encoder_info_frame);
                return;
        } else {
+               if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+                       pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+                               pipe_ctx->stream_res.stream_enc,
+                               &pipe_ctx->stream_res.encoder_info_frame);
+
                pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
index 67f4589..b818ebe 100644 (file)
@@ -30,7 +30,7 @@
 #include "dcn314_dio_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "dc_link_dp.h"
+#include "link.h"
 #include "dpcd_defs.h"
 
 #define DC_LOGGER \
@@ -429,6 +429,8 @@ static const struct stream_encoder_funcs dcn314_str_enc_funcs = {
                enc3_stream_encoder_update_hdmi_info_packets,
        .stop_hdmi_info_packets =
                enc3_stream_encoder_stop_hdmi_info_packets,
+       .update_dp_info_packets_sdp_line_num =
+               enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
        .update_dp_info_packets =
                enc3_stream_encoder_update_dp_info_packets,
        .stop_dp_info_packets =
index 33dfdf8..ed07723 100644 (file)
@@ -280,6 +280,10 @@ void enc3_stream_encoder_update_hdmi_info_packets(
 void enc3_stream_encoder_stop_hdmi_info_packets(
        struct stream_encoder *enc);
 
+void enc3_stream_encoder_update_dp_info_packets_sdp_line_num(
+               struct stream_encoder *enc,
+               struct encoder_info_frame *info_frame);
+
 void enc3_stream_encoder_update_dp_info_packets(
        struct stream_encoder *enc,
        const struct encoder_info_frame *info_frame);
index 7980462..d725260 100644 (file)
@@ -46,9 +46,7 @@
 #include "link_hwss.h"
 #include "dpcd_defs.h"
 #include "dce/dmub_outbox.h"
-#include "dc_link_dp.h"
 #include "link.h"
-#include "inc/dc_link_dp.h"
 #include "dcn10/dcn10_hw_sequencer.h"
 #include "inc/link_enc_cfg.h"
 #include "dcn30/dcn30_vpg.h"
index f01968f..3c0ce94 100644 (file)
@@ -29,7 +29,7 @@
 #include "dcn32_dio_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
-#include "dc_link_dp.h"
+#include "link.h"
 #include "dpcd_defs.h"
 
 #define DC_LOGGER \
@@ -463,6 +463,8 @@ static const struct stream_encoder_funcs dcn32_str_enc_funcs = {
                enc3_stream_encoder_update_hdmi_info_packets,
        .stop_hdmi_info_packets =
                enc3_stream_encoder_stop_hdmi_info_packets,
+       .update_dp_info_packets_sdp_line_num =
+               enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
        .update_dp_info_packets =
                enc3_stream_encoder_update_dp_info_packets,
        .stop_dp_info_packets =
index 3b44006..addfde5 100644 (file)
@@ -51,7 +51,6 @@
 #include "dce/dmub_hw_lock_mgr.h"
 #include "dcn32_resource.h"
 #include "link.h"
-#include "dc_link_dp.h"
 #include "dmub/inc/dmub_subvp_state.h"
 
 #define DC_LOGGER_INIT(logger)
@@ -247,6 +246,13 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable)
        if (!dc->ctx->dmub_srv)
                return false;
 
+       for (i = 0; i < dc->current_state->stream_count; i++) {
+               /* MALL SS messaging is not supported with PSR at this time */
+               if (dc->current_state->streams[i] != NULL &&
+                               dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED)
+                       return false;
+       }
+
        if (enable) {
                if (dc->current_state) {
 
@@ -689,6 +695,7 @@ static void dcn32_initialize_min_clocks(struct dc *dc)
 {
        struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
 
+       clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
        clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
        clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
        clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
@@ -800,6 +807,16 @@ void dcn32_init_hw(struct dc *dc)
                                        !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
 
                dcn32_initialize_min_clocks(dc);
+
+               /* On HW init, allow idle optimizations after pipes have been turned off.
+                *
+                * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
+                * is reset (i.e. not in idle at the time hw init is called), but software state
+                * still has idle_optimizations = true, so we must disable idle optimizations first
+                * (i.e. set false), then re-enable (set true).
+                */
+               dc_allow_idle_optimizations(dc, false);
+               dc_allow_idle_optimizations(dc, true);
        }
 
        /* In headless boot cases, DIG may be turned
index 47dc96a..74e50c0 100644 (file)
@@ -57,7 +57,6 @@
 #include "dcn31/dcn31_hpo_dp_stream_encoder.h"
 #include "dcn31/dcn31_hpo_dp_link_encoder.h"
 #include "dcn32/dcn32_hpo_dp_link_encoder.h"
-#include "dc_link_dp.h"
 #include "dcn31/dcn31_apg.h"
 #include "dcn31/dcn31_dio_link_encoder.h"
 #include "dcn32/dcn32_dio_link_encoder.h"
@@ -2150,13 +2149,19 @@ static bool dcn32_resource_construct(
        dc->caps.max_cursor_size = 64;
        dc->caps.min_horizontal_blanking_period = 80;
        dc->caps.dmdata_alloc_size = 2048;
-       dc->caps.mall_size_per_mem_channel = 0;
+       dc->caps.mall_size_per_mem_channel = 4;
        dc->caps.mall_size_total = 0;
        dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
 
        dc->caps.cache_line_size = 64;
        dc->caps.cache_num_ways = 16;
-       dc->caps.max_cab_allocation_bytes = 67108864; // 64MB = 1024 * 1024 * 64
+
+       /* Calculate the available MALL space */
+       dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(
+               dc, dc->ctx->dc_bios->vram_info.num_chans) *
+               dc->caps.mall_size_per_mem_channel * 1024 * 1024;
+       dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
+
        dc->caps.subvp_fw_processing_delay_us = 15;
        dc->caps.subvp_drr_max_vblank_margin_us = 40;
        dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
@@ -2593,3 +2598,55 @@ struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
 
        return idle_pipe;
 }
+
+unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans)
+{
+       /*
+        * DCN32 and DCN321 SKUs may have different sizes for MALL
+        *  but we may not be able to access all the MALL space.
+        *  If the num_chans is power of 2, then we can access all
+        *  of the available MALL space.  Otherwise, we can only
+        *  access:
+        *
+        *  max_cab_size_in_bytes = total_cache_size_in_bytes *
+        *    ((2^floor(log2(num_chans)))/num_chans)
+        *
+        * Calculating the MALL sizes for all available SKUs, we
+        *  have come up with the follow simplified check.
+        * - we have max_chans which provides the max MALL size.
+        *  Each chans supports 4MB of MALL so:
+        *
+        *  total_cache_size_in_bytes = max_chans * 4 MB
+        *
+        * - we have avail_chans which shows the number of channels
+        *  we can use if we can't access the entire MALL space.
+        *  It is generally half of max_chans
+        * - so we use the following checks:
+        *
+        *   if (num_chans == max_chans), return max_chans
+        *   if (num_chans < max_chans), return avail_chans
+        *
+        * - exception is GC_11_0_0 where we can't access max_chans,
+        *  so we define max_avail_chans as the maximum available
+        *  MALL space
+        *
+        */
+       int gc_11_0_0_max_chans = 48;
+       int gc_11_0_0_max_avail_chans = 32;
+       int gc_11_0_0_avail_chans = 16;
+       int gc_11_0_3_max_chans = 16;
+       int gc_11_0_3_avail_chans = 8;
+       int gc_11_0_2_max_chans = 8;
+       int gc_11_0_2_avail_chans = 4;
+
+       if (ASICREV_IS_GC_11_0_0(dc->ctx->asic_id.hw_internal_rev)) {
+               return (num_chans == gc_11_0_0_max_chans) ?
+                       gc_11_0_0_max_avail_chans : gc_11_0_0_avail_chans;
+       } else if (ASICREV_IS_GC_11_0_2(dc->ctx->asic_id.hw_internal_rev)) {
+               return (num_chans == gc_11_0_2_max_chans) ?
+                       gc_11_0_2_max_chans : gc_11_0_2_avail_chans;
+       } else { // if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev)) {
+               return (num_chans == gc_11_0_3_max_chans) ?
+                       gc_11_0_3_max_chans : gc_11_0_3_avail_chans;
+       }
+}
index b07d3b0..a09db7c 100644 (file)
@@ -38,6 +38,7 @@
 #define DCN3_2_MBLK_HEIGHT_4BPE 128
 #define DCN3_2_MBLK_HEIGHT_8BPE 64
 #define DCN3_2_VMIN_DISPCLK_HZ 717000000
+#define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq
 
 #define TO_DCN32_RES_POOL(pool)\
        container_of(pool, struct dcn32_resource_pool, base)
@@ -122,6 +123,7 @@ bool dcn32_mpo_in_use(struct dc_state *context);
 
 bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context);
 bool dcn32_is_center_timing(struct pipe_ctx *pipe);
+bool dcn32_is_psr_capable(struct pipe_ctx *pipe);
 
 struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
                struct dc_state *state,
@@ -146,6 +148,8 @@ void dcn32_restore_mall_state(struct dc *dc,
 
 bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe);
 
+unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans);
+
 /* definitions for run time init of reg offsets */
 
 /* CLK SRC */
index 0fc79d7..3a2d7bc 100644 (file)
@@ -251,6 +251,16 @@ bool dcn32_is_center_timing(struct pipe_ctx *pipe)
        return is_center_timing;
 }
 
+bool dcn32_is_psr_capable(struct pipe_ctx *pipe)
+{
+       bool psr_capable = false;
+
+       if (pipe->stream && pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
+               psr_capable = true;
+       }
+       return psr_capable;
+}
+
 /**
  * *******************************************************************************************
  * dcn32_determine_det_override: Determine DET allocation for each pipe
index 260d71c..fd57e01 100644 (file)
@@ -60,7 +60,6 @@
 #include "dcn31/dcn31_hpo_dp_stream_encoder.h"
 #include "dcn31/dcn31_hpo_dp_link_encoder.h"
 #include "dcn32/dcn32_hpo_dp_link_encoder.h"
-#include "dc_link_dp.h"
 #include "dcn31/dcn31_apg.h"
 #include "dcn31/dcn31_dio_link_encoder.h"
 #include "dcn32/dcn32_dio_link_encoder.h"
@@ -1703,11 +1702,18 @@ static bool dcn321_resource_construct(
        dc->caps.max_cursor_size = 64;
        dc->caps.min_horizontal_blanking_period = 80;
        dc->caps.dmdata_alloc_size = 2048;
-       dc->caps.mall_size_per_mem_channel = 0;
+       dc->caps.mall_size_per_mem_channel = 4;
        dc->caps.mall_size_total = 0;
        dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
        dc->caps.cache_line_size = 64;
        dc->caps.cache_num_ways = 16;
+
+       /* Calculate the available MALL space */
+       dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(
+               dc, dc->ctx->dc_bios->vram_info.num_chans) *
+               dc->caps.mall_size_per_mem_channel * 1024 * 1024;
+       dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
+
        dc->caps.max_cab_allocation_bytes = 33554432; // 32MB = 1024 * 1024 * 32
        dc->caps.subvp_fw_processing_delay_us = 15;
        dc->caps.subvp_drr_max_vblank_margin_us = 40;
index af1c50e..c624c76 100644 (file)
@@ -161,6 +161,12 @@ enum dc_edid_status dm_helpers_read_local_edid(
                struct dc_link *link,
                struct dc_sink *sink);
 
+bool dm_helpers_dp_handle_test_pattern_request(
+               struct dc_context *ctx,
+               const struct dc_link *link,
+               union link_test_pattern dpcd_test_pattern,
+               union test_misc dpcd_test_params);
+
 void dm_set_dcn_clocks(
                struct dc_context *ctx,
                struct dc_clocks *clks);
index d2b89c5..197df40 100644 (file)
@@ -26,7 +26,6 @@
 
 #include "resource.h"
 #include "clk_mgr.h"
-#include "dc_link_dp.h"
 #include "dchubbub.h"
 #include "dcn20/dcn20_resource.h"
 #include "dcn21/dcn21_resource.h"
@@ -1004,6 +1003,39 @@ static enum dcn_zstate_support_state  decide_zstate_support(struct dc *dc, struc
        }
 }
 
+static void dcn20_adjust_freesync_v_startup(
+               const struct dc_crtc_timing *dc_crtc_timing, int *vstartup_start)
+{
+       struct dc_crtc_timing patched_crtc_timing;
+       uint32_t asic_blank_end   = 0;
+       uint32_t asic_blank_start = 0;
+       uint32_t newVstartup      = 0;
+
+       patched_crtc_timing = *dc_crtc_timing;
+
+       if (patched_crtc_timing.flags.INTERLACE == 1) {
+               if (patched_crtc_timing.v_front_porch < 2)
+                       patched_crtc_timing.v_front_porch = 2;
+       } else {
+               if (patched_crtc_timing.v_front_porch < 1)
+                       patched_crtc_timing.v_front_porch = 1;
+       }
+
+       /* blank_start = frame end - front porch */
+       asic_blank_start = patched_crtc_timing.v_total -
+                                       patched_crtc_timing.v_front_porch;
+
+       /* blank_end = blank_start - active */
+       asic_blank_end = asic_blank_start -
+                                       patched_crtc_timing.v_border_bottom -
+                                       patched_crtc_timing.v_addressable -
+                                       patched_crtc_timing.v_border_top;
+
+       newVstartup = asic_blank_end + (patched_crtc_timing.v_total - asic_blank_start);
+
+       *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start);
+}
+
 void dcn20_calculate_dlg_params(
                struct dc *dc, struct dc_state *context,
                display_e2e_pipe_params_st *pipes,
@@ -1063,6 +1095,11 @@ void dcn20_calculate_dlg_params(
                context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz =
                                                pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
                context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+               if (context->res_ctx.pipe_ctx[i].stream->adaptive_sync_infopacket.valid)
+                       dcn20_adjust_freesync_v_startup(
+                               &context->res_ctx.pipe_ctx[i].stream->timing,
+                               &context->res_ctx.pipe_ctx[i].pipe_dlg_param.vstartup_start);
+
                pipe_idx++;
        }
        /*save a original dppclock copy*/
index 7feb875..0dc1a03 100644 (file)
@@ -24,7 +24,6 @@
  *
  */
 #include "dcn32_fpu.h"
-#include "dc_link_dp.h"
 #include "dcn32/dcn32_resource.h"
 #include "dcn20/dcn20_resource.h"
 #include "display_mode_vba_util_32.h"
@@ -692,7 +691,7 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
                 *   to combine this with SubVP can cause issues with the scheduling).
                 * - Not TMZ surface
                 */
-               if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) &&
+               if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) && !dcn32_is_psr_capable(pipe) &&
                                pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && !pipe->plane_state->address.tmz_surface &&
                                (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0 ||
                                (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 &&
@@ -1272,6 +1271,38 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
        return false;
 }
 
+static void dcn20_adjust_freesync_v_startup(const struct dc_crtc_timing *dc_crtc_timing, int *vstartup_start)
+{
+       struct dc_crtc_timing patched_crtc_timing;
+       uint32_t asic_blank_end   = 0;
+       uint32_t asic_blank_start = 0;
+       uint32_t newVstartup      = 0;
+
+       patched_crtc_timing = *dc_crtc_timing;
+
+       if (patched_crtc_timing.flags.INTERLACE == 1) {
+               if (patched_crtc_timing.v_front_porch < 2)
+                       patched_crtc_timing.v_front_porch = 2;
+       } else {
+               if (patched_crtc_timing.v_front_porch < 1)
+                       patched_crtc_timing.v_front_porch = 1;
+       }
+
+       /* blank_start = frame end - front porch */
+       asic_blank_start = patched_crtc_timing.v_total -
+                                       patched_crtc_timing.v_front_porch;
+
+       /* blank_end = blank_start - active */
+       asic_blank_end = asic_blank_start -
+                                       patched_crtc_timing.v_border_bottom -
+                                       patched_crtc_timing.v_addressable -
+                                       patched_crtc_timing.v_border_top;
+
+       newVstartup = asic_blank_end + (patched_crtc_timing.v_total - asic_blank_start);
+
+       *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start);
+}
+
 static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
                                       display_e2e_pipe_params_st *pipes,
                                       int pipe_cnt, int vlevel)
@@ -1375,6 +1406,11 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
                        }
                }
 
+               if (context->res_ctx.pipe_ctx[i].stream->adaptive_sync_infopacket.valid)
+                       dcn20_adjust_freesync_v_startup(
+                               &context->res_ctx.pipe_ctx[i].stream->timing,
+                               &context->res_ctx.pipe_ctx[i].pipe_dlg_param.vstartup_start);
+
                pipe_idx++;
        }
        /* If DCN isn't making memory requests we can allow pstate change and lower clocks */
@@ -1601,16 +1637,12 @@ bool dcn32_internal_validate_bw(struct dc *dc,
                 * to support with Prefetch mode 1 (dm_prefetch_support_fclk_and_stutter == 2)
                 */
                context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
-                       dm_prefetch_support_fclk_and_stutter;
+                       dm_prefetch_support_none;
 
+               context->bw_ctx.dml.validate_max_state = fast_validate;
                vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
 
-               /* Last attempt with Prefetch mode 2 (dm_prefetch_support_stutter == 3) */
-               if (vlevel == context->bw_ctx.dml.soc.num_states) {
-                       context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
-                               dm_prefetch_support_stutter;
-                       vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
-               }
+               context->bw_ctx.dml.validate_max_state = false;
 
                if (vlevel < context->bw_ctx.dml.soc.num_states) {
                        memset(split, 0, sizeof(split));
@@ -2499,8 +2531,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
                }
 
                /* Override from VBIOS for num_chan */
-               if (dc->ctx->dc_bios->vram_info.num_chans)
+               if (dc->ctx->dc_bios->vram_info.num_chans) {
                        dcn3_2_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+                       dcn3_2_soc.mall_allocated_for_dcn_mbytes = (double)(dcn32_calc_num_avail_chans_for_mall(dc,
+                               dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel);
+               }
 
                if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
                        dcn3_2_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
index 6c5ab5c..23e50d1 100644 (file)
@@ -1639,9 +1639,14 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 static void mode_support_configuration(struct vba_vars_st *v,
                                  struct display_mode_lib *mode_lib)
 {
-       int i, j;
+       int i, j, start_state;
 
-       for (i = v->soc.num_states - 1; i >= 0; i--) {
+       if (mode_lib->validate_max_state)
+               start_state = v->soc.num_states - 1;
+       else
+               start_state = 0;
+
+       for (i = v->soc.num_states - 1; i >= start_state; i--) {
                for (j = 0; j < 2; j++) {
                        if (mode_lib->vba.ScaleRatioAndTapsSupport == true
                                && mode_lib->vba.SourceFormatPixelAndScanSupport == true
@@ -1710,7 +1715,7 @@ static void mode_support_configuration(struct vba_vars_st *v,
 void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
 {
        struct vba_vars_st *v = &mode_lib->vba;
-       int i, j;
+       int i, j, start_state;
        unsigned int k, m;
        unsigned int MaximumMPCCombine;
        unsigned int NumberOfNonCombinedSurfaceOfMaximumBandwidth;
@@ -1723,6 +1728,10 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 #endif
 
        /*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/
+       if (mode_lib->validate_max_state)
+               start_state = v->soc.num_states - 1;
+       else
+               start_state = 0;
 
        /*Scale Ratio, taps Support Check*/
 
@@ -2012,7 +2021,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
        mode_lib->vba.MPCCombineMethodIncompatible = v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.MPCCombineMethodAsNeededForPStateChangeAndVoltage
                        && v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.MPCCombineMethodAsPossible;
 
-       for (i = 0; i < v->soc.num_states; i++) {
+       for (i = start_state; i < v->soc.num_states; i++) {
                for (j = 0; j < 2; j++) {
                        mode_lib->vba.TotalNumberOfActiveDPP[i][j] = 0;
                        mode_lib->vba.TotalAvailablePipesSupport[i][j] = true;
@@ -2289,7 +2298,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                }
        }
 
-       for (i = 0; i < v->soc.num_states; ++i) {
+       for (i = start_state; i < v->soc.num_states; ++i) {
                mode_lib->vba.ExceededMultistreamSlots[i] = false;
                for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
                        if (mode_lib->vba.OutputMultistreamEn[k] == true && mode_lib->vba.OutputMultistreamId[k] == k) {
@@ -2389,7 +2398,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                }
        }
 
-       for (i = 0; i < v->soc.num_states; ++i) {
+       for (i = start_state; i < v->soc.num_states; ++i) {
                mode_lib->vba.DTBCLKRequiredMoreThanSupported[i] = false;
                for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
                        if (mode_lib->vba.BlendingAndTiming[k] == k
@@ -2406,7 +2415,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                }
        }
 
-       for (i = 0; i < v->soc.num_states; ++i) {
+       for (i = start_state; i < v->soc.num_states; ++i) {
                mode_lib->vba.ODMCombine2To1SupportCheckOK[i] = true;
                mode_lib->vba.ODMCombine4To1SupportCheckOK[i] = true;
                for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
@@ -2424,7 +2433,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                }
        }
 
-       for (i = 0; i < v->soc.num_states; i++) {
+       for (i = start_state; i < v->soc.num_states; i++) {
                mode_lib->vba.DSCCLKRequiredMoreThanSupported[i] = false;
                for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
                        if (mode_lib->vba.BlendingAndTiming[k] == k) {
@@ -2461,7 +2470,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
        /* Check DSC Unit and Slices Support */
        v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.TotalDSCUnitsRequired = 0;
 
-       for (i = 0; i < v->soc.num_states; ++i) {
+       for (i = start_state; i < v->soc.num_states; ++i) {
                mode_lib->vba.NotEnoughDSCUnits[i] = false;
                mode_lib->vba.NotEnoughDSCSlices[i] = false;
                v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.TotalDSCUnitsRequired = 0;
@@ -2496,7 +2505,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
        }
 
        /*DSC Delay per state*/
-       for (i = 0; i < v->soc.num_states; ++i) {
+       for (i = start_state; i < v->soc.num_states; ++i) {
                for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
                        mode_lib->vba.DSCDelayPerState[i][k] = dml32_DSCDelayRequirement(
                                        mode_lib->vba.RequiresDSC[i][k], mode_lib->vba.ODMCombineEnablePerState[i][k],
@@ -2523,7 +2532,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 
        //Calculate Swath, DET Configuration, DCFCLKDeepSleep
        //
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j) {
                        for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
                                mode_lib->vba.RequiredDPPCLKThisState[k] = mode_lib->vba.RequiredDPPCLK[i][j][k];
@@ -2661,7 +2670,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                        mode_lib->vba.SurfaceSizeInMALL,
                        &mode_lib->vba.ExceededMALLSize);
 
-       for (i = 0; i < v->soc.num_states; i++) {
+       for (i = start_state; i < v->soc.num_states; i++) {
                for (j = 0; j < 2; j++) {
                        for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
                                mode_lib->vba.swath_width_luma_ub_this_state[k] =
@@ -2888,7 +2897,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
        }
 
        //Calculate Return BW
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j) {
                        for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
                                if (mode_lib->vba.BlendingAndTiming[k] == k) {
@@ -2967,7 +2976,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                        &mode_lib->vba.MinPrefetchMode,
                        &mode_lib->vba.MaxPrefetchMode);
 
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j)
                        mode_lib->vba.DCFCLKState[i][j] = mode_lib->vba.DCFCLKPerState[i];
        }
@@ -3089,7 +3098,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                                mode_lib->vba.DCFCLKState);
        } // UseMinimumRequiredDCFCLK == true
 
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j) {
                        mode_lib->vba.ReturnBWPerState[i][j] = dml32_get_return_bw_mbps(&mode_lib->vba.soc, i,
                                        mode_lib->vba.HostVMEnable, mode_lib->vba.DCFCLKState[i][j],
@@ -3098,7 +3107,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
        }
 
        //Re-ordering Buffer Support Check
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j) {
                        if ((mode_lib->vba.ROBBufferSizeInKByte - mode_lib->vba.PixelChunkSizeInKByte) * 1024
                                        / mode_lib->vba.ReturnBWPerState[i][j]
@@ -3120,7 +3129,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                                + mode_lib->vba.ReadBandwidthChroma[k];
        }
 
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j) {
                        mode_lib->vba.MaxTotalVerticalActiveAvailableBandwidth[i][j] =
                                dml_min3(mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKState[i][j]
@@ -3144,7 +3153,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 
        /* Prefetch Check */
 
-       for (i = 0; i < (int) v->soc.num_states; ++i) {
+       for (i = start_state; i < (int) v->soc.num_states; ++i) {
                for (j = 0; j <= 1; ++j) {
 
                        mode_lib->vba.TimeCalc = 24 / mode_lib->vba.ProjectedDCFCLKDeepSleep[i][j];
@@ -3662,7 +3671,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 
        MaximumMPCCombine = 0;
 
-       for (i = v->soc.num_states; i >= 0; i--) {
+       for (i = v->soc.num_states; i >= start_state; i--) {
                if (i == v->soc.num_states || mode_lib->vba.ModeSupport[i][0] == true ||
                                mode_lib->vba.ModeSupport[i][1] == true) {
                        mode_lib->vba.VoltageLevel = i;
index 0ea4061..b80cef7 100644 (file)
@@ -534,8 +534,11 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p
                }
 
                /* Override from VBIOS for num_chan */
-               if (dc->ctx->dc_bios->vram_info.num_chans)
+               if (dc->ctx->dc_bios->vram_info.num_chans) {
                        dcn3_21_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+                       dcn3_21_soc.mall_allocated_for_dcn_mbytes = (double)(dcn32_calc_num_avail_chans_for_mall(dc,
+                               dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel);
+               }
 
                if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
                        dcn3_21_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
index 3d643d5..a9d49ef 100644 (file)
@@ -91,6 +91,7 @@ struct display_mode_lib {
        struct dal_logger *logger;
        struct dml_funcs funcs;
        struct _vcs_dpi_display_e2e_pipe_params_st dml_pipe_state[6];
+       bool validate_max_state;
 };
 
 void dml_init_instance(struct display_mode_lib *lib,
index 906a43e..e1422e5 100644 (file)
@@ -32,7 +32,7 @@
 #include "core_types.h"
 #include "link.h"
 #include "link_hwss.h"
-#include "link/link_dpcd.h"
+#include "link/protocols/link_dpcd.h"
 
 #define DC_LOGGER \
        link->ctx->logger
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
deleted file mode 100644 (file)
index 52e1aad..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2015 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_DP_H__
-#define __DC_LINK_DP_H__
-
-#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_verify_link_cap_with_retries(
-       struct dc_link *link,
-       struct dc_link_settings *known_limit_link_setting,
-       int attempts);
-
-bool dp_validate_mode_timing(
-       struct dc_link *link,
-       const struct dc_crtc_timing *timing);
-
-bool hpd_rx_irq_check_link_loss_status(struct dc_link *link,
-                                      union hpd_irq_data *hpd_irq_dpcd_data);
-enum dc_status read_hpd_rx_irq_data(
-       struct dc_link *link,
-       union hpd_irq_data *irq_data);
-
-bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing);
-
-void dp_enable_mst_on_sink(struct dc_link *link, bool enable);
-
-enum dp_panel_mode dp_get_panel_mode(struct dc_link *link);
-void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
-
-void dpcd_write_cable_id_to_dprx(struct dc_link *link);
-
-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);
-
-/* Initialize output parameter lt_settings. */
-void dp_decide_training_settings(
-       struct dc_link *link,
-       const struct dc_link_settings *link_setting,
-       struct link_training_settings *lt_settings);
-
-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 enable_dp_hpo_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct dc_link_settings *link_settings);
-void disable_dp_hpo_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal);
-void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
-void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd);
-void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
-void edp_add_delay_for_T9(struct dc_link *link);
-bool edp_receiver_ready_T9(struct dc_link *link);
-bool edp_receiver_ready_T7(struct dc_link *link);
-
-void dp_retrain_link_dp_test(struct dc_link *link,
-               struct dc_link_settings *link_setting,
-               bool skip_video_pattern);
-
-#endif /* __DC_LINK_DP_H__ */
index 42db4b7..bb5ad70 100644 (file)
@@ -72,6 +72,12 @@ enum dynamic_metadata_mode {
        dmdata_dolby_vision
 };
 
+struct enc_sdp_line_num {
+       /* Adaptive Sync SDP */
+       bool adaptive_sync_line_num_valid;
+       uint32_t adaptive_sync_line_num;
+};
+
 struct encoder_info_frame {
        /* auxiliary video information */
        struct dc_info_packet avi;
@@ -85,6 +91,9 @@ struct encoder_info_frame {
        struct dc_info_packet vsc;
        /* HDR Static MetaData */
        struct dc_info_packet hdrsmd;
+       /* Adaptive Sync SDP*/
+       struct dc_info_packet adaptive_sync;
+       struct enc_sdp_line_num sdp_line_num;
 };
 
 struct encoder_unblank_param {
@@ -154,6 +163,10 @@ struct stream_encoder_funcs {
        void (*stop_hdmi_info_packets)(
                struct stream_encoder *enc);
 
+       void (*update_dp_info_packets_sdp_line_num)(
+               struct stream_encoder *enc,
+               struct encoder_info_frame *info_frame);
+
        void (*update_dp_info_packets)(
                struct stream_encoder *enc,
                const struct encoder_info_frame *info_frame);
@@ -302,6 +315,10 @@ struct hpo_dp_stream_encoder_funcs {
                bool compressed_format,
                bool double_buffer_en);
 
+       void (*update_dp_info_packets_sdp_line_num)(
+               struct hpo_dp_stream_encoder *enc,
+               struct encoder_info_frame *info_frame);
+
        void (*update_dp_info_packets)(
                struct hpo_dp_stream_encoder *enc,
                const struct encoder_info_frame *info_frame);
index 3945522..d4cebf4 100644 (file)
@@ -89,4 +89,21 @@ bool link_decide_link_settings(
        struct dc_stream_state *stream,
        struct dc_link_settings *link_setting);
 
+void link_dp_trace_set_edp_power_timestamp(struct dc_link *link,
+               bool power_up);
+uint64_t link_dp_trace_get_edp_poweron_timestamp(struct dc_link *link);
+uint64_t link_dp_trace_get_edp_poweroff_timestamp(struct dc_link *link);
+
+bool link_is_edp_ilr_optimization_required(struct dc_link *link,
+               struct dc_crtc_timing *crtc_timing);
+
+bool link_backlight_enable_aux(struct dc_link *link, bool enable);
+void link_edp_add_delay_for_T9(struct dc_link *link);
+bool link_edp_receiver_ready_T9(struct dc_link *link);
+bool link_edp_receiver_ready_T7(struct dc_link *link);
+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);
+
 #endif /* __DC_LINK_HPD_H__ */
index 4dee0e6..0f642cb 100644 (file)
 # It abstracts the control and status of back end pipe such as DIO, HPO, DPIA,
 # PHY, HPD, DDC and etc).
 
-LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o \
-link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o link_dp_training.o \
-link_dp_training_8b_10b.o link_dp_training_128b_132b.o link_dp_training_dpia.o \
-link_dp_training_auxless.o link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o \
-link_dp_capability.o
+###############################################################################
+# accessories
+###############################################################################
+LINK_ACCESSORIES = link_dp_trace.o link_dp_cts.o
 
-AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK))
+AMD_DAL_LINK_ACCESSORIES = $(addprefix $(AMDDALPATH)/dc/link/accessories/, \
+$(LINK_ACCESSORIES))
 
-AMD_DISPLAY_FILES += $(AMD_DAL_LINK)
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK_ACCESSORIES)
+###############################################################################
+# hwss
+###############################################################################
+LINK_HWSS = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o
+
+AMD_DAL_LINK_HWSS = $(addprefix $(AMDDALPATH)/dc/link/hwss/, \
+$(LINK_HWSS))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK_HWSS)
+###############################################################################
+# protocols
+###############################################################################
+LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \
+link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \
+link_dp_training_dpia.o link_dp_training_auxless.o \
+link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \
+link_edp_panel_control.o link_dp_irq_handler.o
+
+AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \
+$(LINK_PROTOCOLS))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK_PROTOCOLS)
\ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
new file mode 100644 (file)
index 0000000..7fb2c0b
--- /dev/null
@@ -0,0 +1,1055 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "link_dp_cts.h"
+#include "link/protocols/link_dpcd.h"
+#include "link/protocols/link_dp_training.h"
+#include "link/protocols/link_dp_phy.h"
+#include "link/protocols/link_dp_training_fixed_vs_pe_retimer.h"
+#include "resource.h"
+#include "dm_helpers.h"
+#include "dc_dmub_srv.h"
+#include "dce/dmub_hw_lock_mgr.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate)
+{
+       switch (test_rate) {
+       case DP_TEST_LINK_RATE_RBR:
+               return LINK_RATE_LOW;
+       case DP_TEST_LINK_RATE_HBR:
+               return LINK_RATE_HIGH;
+       case DP_TEST_LINK_RATE_HBR2:
+               return LINK_RATE_HIGH2;
+       case DP_TEST_LINK_RATE_HBR3:
+               return LINK_RATE_HIGH3;
+       case DP_TEST_LINK_RATE_UHBR10:
+               return LINK_RATE_UHBR10;
+       case DP_TEST_LINK_RATE_UHBR20:
+               return LINK_RATE_UHBR20;
+       case DP_TEST_LINK_RATE_UHBR13_5:
+               return LINK_RATE_UHBR13_5;
+       default:
+               return LINK_RATE_UNKNOWN;
+       }
+}
+
+static bool is_dp_phy_sqaure_pattern(enum dp_test_pattern test_pattern)
+{
+       return (DP_TEST_PATTERN_SQUARE_BEGIN <= test_pattern &&
+                       test_pattern <= DP_TEST_PATTERN_SQUARE_END);
+}
+
+static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern)
+{
+       if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern &&
+                       test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) ||
+                       test_pattern == DP_TEST_PATTERN_VIDEO_MODE)
+               return true;
+       else
+               return false;
+}
+
+void dp_retrain_link_dp_test(struct dc_link *link,
+                       struct dc_link_settings *link_setting,
+                       bool skip_video_pattern)
+{
+       struct pipe_ctx *pipe;
+       unsigned int i;
+
+       udelay(100);
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
+               if (pipe->stream != NULL &&
+                               pipe->stream->link == link &&
+                               !pipe->stream->dpms_off &&
+                               !pipe->top_pipe && !pipe->prev_odm_pipe) {
+                       core_link_disable_stream(pipe);
+                       pipe->link_config.dp_link_settings = *link_setting;
+                       update_dp_encoder_resources_for_test_harness(
+                                       link->dc,
+                                       pipe->stream->ctx->dc->current_state,
+                                       pipe);
+               }
+       }
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
+               if (pipe->stream != NULL &&
+                               pipe->stream->link == link &&
+                               !pipe->stream->dpms_off &&
+                               !pipe->top_pipe && !pipe->prev_odm_pipe) {
+                       core_link_enable_stream(
+                                       pipe->stream->ctx->dc->current_state,
+                                       pipe);
+               }
+       }
+}
+
+static void dp_test_send_link_training(struct dc_link *link)
+{
+       struct dc_link_settings link_settings = {0};
+       uint8_t test_rate = 0;
+
+       core_link_read_dpcd(
+                       link,
+                       DP_TEST_LANE_COUNT,
+                       (unsigned char *)(&link_settings.lane_count),
+                       1);
+       core_link_read_dpcd(
+                       link,
+                       DP_TEST_LINK_RATE,
+                       &test_rate,
+                       1);
+       link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate);
+
+       /* Set preferred link settings */
+       link->verified_link_cap.lane_count = link_settings.lane_count;
+       link->verified_link_cap.link_rate = link_settings.link_rate;
+
+       dp_retrain_link_dp_test(link, &link_settings, false);
+}
+
+static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
+{
+       union audio_test_mode            dpcd_test_mode = {0};
+       struct audio_test_pattern_type   dpcd_pattern_type = {0};
+       union audio_test_pattern_period  dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0};
+       enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
+
+       struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+       struct pipe_ctx *pipe_ctx = &pipes[0];
+       unsigned int channel_count;
+       unsigned int channel = 0;
+       unsigned int modes = 0;
+       unsigned int sampling_rate_in_hz = 0;
+
+       // get audio test mode and test pattern parameters
+       core_link_read_dpcd(
+               link,
+               DP_TEST_AUDIO_MODE,
+               &dpcd_test_mode.raw,
+               sizeof(dpcd_test_mode));
+
+       core_link_read_dpcd(
+               link,
+               DP_TEST_AUDIO_PATTERN_TYPE,
+               &dpcd_pattern_type.value,
+               sizeof(dpcd_pattern_type));
+
+       channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT);
+
+       // read pattern periods for requested channels when sawTooth pattern is requested
+       if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
+                       dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) {
+
+               test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ?
+                               DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
+               // read period for each channel
+               for (channel = 0; channel < channel_count; channel++) {
+                       core_link_read_dpcd(
+                                                       link,
+                                                       DP_TEST_AUDIO_PERIOD_CH1 + channel,
+                                                       &dpcd_pattern_period[channel].raw,
+                                                       sizeof(dpcd_pattern_period[channel]));
+               }
+       }
+
+       // translate sampling rate
+       switch (dpcd_test_mode.bits.sampling_rate) {
+       case AUDIO_SAMPLING_RATE_32KHZ:
+               sampling_rate_in_hz = 32000;
+               break;
+       case AUDIO_SAMPLING_RATE_44_1KHZ:
+               sampling_rate_in_hz = 44100;
+               break;
+       case AUDIO_SAMPLING_RATE_48KHZ:
+               sampling_rate_in_hz = 48000;
+               break;
+       case AUDIO_SAMPLING_RATE_88_2KHZ:
+               sampling_rate_in_hz = 88200;
+               break;
+       case AUDIO_SAMPLING_RATE_96KHZ:
+               sampling_rate_in_hz = 96000;
+               break;
+       case AUDIO_SAMPLING_RATE_176_4KHZ:
+               sampling_rate_in_hz = 176400;
+               break;
+       case AUDIO_SAMPLING_RATE_192KHZ:
+               sampling_rate_in_hz = 192000;
+               break;
+       default:
+               sampling_rate_in_hz = 0;
+               break;
+       }
+
+       link->audio_test_data.flags.test_requested = 1;
+       link->audio_test_data.flags.disable_video = disable_video;
+       link->audio_test_data.sampling_rate = sampling_rate_in_hz;
+       link->audio_test_data.channel_count = channel_count;
+       link->audio_test_data.pattern_type = test_pattern;
+
+       if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) {
+               for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) {
+                       link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period;
+               }
+       }
+}
+
+/* TODO Raven hbr2 compliance eye output is unstable
+ * (toggling on and off) with debugger break
+ * This caueses intermittent PHY automation failure
+ * Need to look into the root cause */
+static void dp_test_send_phy_test_pattern(struct dc_link *link)
+{
+       union phy_test_pattern dpcd_test_pattern;
+       union lane_adjust dpcd_lane_adjustment[2];
+       unsigned char dpcd_post_cursor_2_adjustment = 0;
+       unsigned char test_pattern_buffer[
+                       (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
+                       DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
+       unsigned int test_pattern_size = 0;
+       enum dp_test_pattern test_pattern;
+       union lane_adjust dpcd_lane_adjust;
+       unsigned int lane;
+       struct link_training_settings link_training_settings;
+       unsigned char no_preshoot = 0;
+       unsigned char no_deemphasis = 0;
+
+       dpcd_test_pattern.raw = 0;
+       memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment));
+       memset(&link_training_settings, 0, sizeof(link_training_settings));
+
+       /* get phy test pattern and pattern parameters from DP receiver */
+       core_link_read_dpcd(
+                       link,
+                       DP_PHY_TEST_PATTERN,
+                       &dpcd_test_pattern.raw,
+                       sizeof(dpcd_test_pattern));
+       core_link_read_dpcd(
+                       link,
+                       DP_ADJUST_REQUEST_LANE0_1,
+                       &dpcd_lane_adjustment[0].raw,
+                       sizeof(dpcd_lane_adjustment));
+
+       /* prepare link training settings */
+       link_training_settings.link_settings = link->cur_link_settings;
+
+       link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings);
+
+       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+                       link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT)
+               dp_fixed_vs_pe_read_lane_adjust(
+                               link,
+                               link_training_settings.dpcd_lane_settings);
+
+       /*get post cursor 2 parameters
+        * For DP 1.1a or eariler, this DPCD register's value is 0
+        * For DP 1.2 or later:
+        * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1
+        * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3
+        */
+       core_link_read_dpcd(
+                       link,
+                       DP_ADJUST_REQUEST_POST_CURSOR2,
+                       &dpcd_post_cursor_2_adjustment,
+                       sizeof(dpcd_post_cursor_2_adjustment));
+
+       /* translate request */
+       switch (dpcd_test_pattern.bits.PATTERN) {
+       case PHY_TEST_PATTERN_D10_2:
+               test_pattern = DP_TEST_PATTERN_D102;
+               break;
+       case PHY_TEST_PATTERN_SYMBOL_ERROR:
+               test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR;
+               break;
+       case PHY_TEST_PATTERN_PRBS7:
+               test_pattern = DP_TEST_PATTERN_PRBS7;
+               break;
+       case PHY_TEST_PATTERN_80BIT_CUSTOM:
+               test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
+               break;
+       case PHY_TEST_PATTERN_CP2520_1:
+               /* CP2520 pattern is unstable, temporarily use TPS4 instead */
+               test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
+                               DP_TEST_PATTERN_TRAINING_PATTERN4 :
+                               DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
+               break;
+       case PHY_TEST_PATTERN_CP2520_2:
+               /* CP2520 pattern is unstable, temporarily use TPS4 instead */
+               test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
+                               DP_TEST_PATTERN_TRAINING_PATTERN4 :
+                               DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
+               break;
+       case PHY_TEST_PATTERN_CP2520_3:
+               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
+               break;
+       case PHY_TEST_PATTERN_128b_132b_TPS1:
+               test_pattern = DP_TEST_PATTERN_128b_132b_TPS1;
+               break;
+       case PHY_TEST_PATTERN_128b_132b_TPS2:
+               test_pattern = DP_TEST_PATTERN_128b_132b_TPS2;
+               break;
+       case PHY_TEST_PATTERN_PRBS9:
+               test_pattern = DP_TEST_PATTERN_PRBS9;
+               break;
+       case PHY_TEST_PATTERN_PRBS11:
+               test_pattern = DP_TEST_PATTERN_PRBS11;
+               break;
+       case PHY_TEST_PATTERN_PRBS15:
+               test_pattern = DP_TEST_PATTERN_PRBS15;
+               break;
+       case PHY_TEST_PATTERN_PRBS23:
+               test_pattern = DP_TEST_PATTERN_PRBS23;
+               break;
+       case PHY_TEST_PATTERN_PRBS31:
+               test_pattern = DP_TEST_PATTERN_PRBS31;
+               break;
+       case PHY_TEST_PATTERN_264BIT_CUSTOM:
+               test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM;
+               break;
+       case PHY_TEST_PATTERN_SQUARE:
+               test_pattern = DP_TEST_PATTERN_SQUARE;
+               break;
+       case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
+               test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
+               no_preshoot = 1;
+               break;
+       case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
+               test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
+               no_deemphasis = 1;
+               break;
+       case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
+               test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
+               no_preshoot = 1;
+               no_deemphasis = 1;
+               break;
+       default:
+               test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
+       break;
+       }
+
+       if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
+               test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
+                               DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1;
+               core_link_read_dpcd(
+                               link,
+                               DP_TEST_80BIT_CUSTOM_PATTERN_7_0,
+                               test_pattern_buffer,
+                               test_pattern_size);
+       }
+
+       if (is_dp_phy_sqaure_pattern(test_pattern)) {
+               test_pattern_size = 1; // Square pattern data is 1 byte (DP spec)
+               core_link_read_dpcd(
+                               link,
+                               DP_PHY_SQUARE_PATTERN,
+                               test_pattern_buffer,
+                               test_pattern_size);
+       }
+
+       if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) {
+               test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256-
+                               DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1;
+               core_link_read_dpcd(
+                               link,
+                               DP_TEST_264BIT_CUSTOM_PATTERN_7_0,
+                               test_pattern_buffer,
+                               test_pattern_size);
+       }
+
+       for (lane = 0; lane <
+               (unsigned int)(link->cur_link_settings.lane_count);
+               lane++) {
+               dpcd_lane_adjust.raw =
+                       dp_get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
+               if (link_dp_get_encoding_format(&link->cur_link_settings) ==
+                               DP_8b_10b_ENCODING) {
+                       link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING =
+                               (enum dc_voltage_swing)
+                               (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
+                       link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS =
+                               (enum dc_pre_emphasis)
+                               (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
+                       link_training_settings.hw_lane_settings[lane].POST_CURSOR2 =
+                               (enum dc_post_cursor2)
+                               ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
+               } else if (link_dp_get_encoding_format(&link->cur_link_settings) ==
+                               DP_128b_132b_ENCODING) {
+                       link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level =
+                                       dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
+                       link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot;
+                       link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis;
+               }
+       }
+
+       dp_hw_to_dpcd_lane_settings(&link_training_settings,
+                       link_training_settings.hw_lane_settings,
+                       link_training_settings.dpcd_lane_settings);
+       /*Usage: Measure DP physical lane signal
+        * by DP SI test equipment automatically.
+        * PHY test pattern request is generated by equipment via HPD interrupt.
+        * HPD needs to be active all the time. HPD should be active
+        * all the time. Do not touch it.
+        * forward request to DS
+        */
+       dc_link_dp_set_test_pattern(
+               link,
+               test_pattern,
+               DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED,
+               &link_training_settings,
+               test_pattern_buffer,
+               test_pattern_size);
+}
+
+static void set_crtc_test_pattern(struct dc_link *link,
+                               struct pipe_ctx *pipe_ctx,
+                               enum dp_test_pattern test_pattern,
+                               enum dp_test_pattern_color_space test_pattern_color_space)
+{
+       enum controller_dp_test_pattern controller_test_pattern;
+       enum dc_color_depth color_depth = pipe_ctx->
+               stream->timing.display_color_depth;
+       struct bit_depth_reduction_params params;
+       struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
+       int width = pipe_ctx->stream->timing.h_addressable +
+               pipe_ctx->stream->timing.h_border_left +
+               pipe_ctx->stream->timing.h_border_right;
+       int height = pipe_ctx->stream->timing.v_addressable +
+               pipe_ctx->stream->timing.v_border_bottom +
+               pipe_ctx->stream->timing.v_border_top;
+
+       memset(&params, 0, sizeof(params));
+
+       switch (test_pattern) {
+       case DP_TEST_PATTERN_COLOR_SQUARES:
+               controller_test_pattern =
+                               CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
+       break;
+       case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
+               controller_test_pattern =
+                               CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
+       break;
+       case DP_TEST_PATTERN_VERTICAL_BARS:
+               controller_test_pattern =
+                               CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
+       break;
+       case DP_TEST_PATTERN_HORIZONTAL_BARS:
+               controller_test_pattern =
+                               CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
+       break;
+       case DP_TEST_PATTERN_COLOR_RAMP:
+               controller_test_pattern =
+                               CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
+       break;
+       default:
+               controller_test_pattern =
+                               CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
+       break;
+       }
+
+       switch (test_pattern) {
+       case DP_TEST_PATTERN_COLOR_SQUARES:
+       case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
+       case DP_TEST_PATTERN_VERTICAL_BARS:
+       case DP_TEST_PATTERN_HORIZONTAL_BARS:
+       case DP_TEST_PATTERN_COLOR_RAMP:
+       {
+               /* disable bit depth reduction */
+               pipe_ctx->stream->bit_depth_params = params;
+               opp->funcs->opp_program_bit_depth_reduction(opp, &params);
+               if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
+                       pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
+                               controller_test_pattern, color_depth);
+               else if (link->dc->hwss.set_disp_pattern_generator) {
+                       struct pipe_ctx *odm_pipe;
+                       enum controller_dp_color_space controller_color_space;
+                       int opp_cnt = 1;
+                       int offset = 0;
+                       int dpg_width = width;
+
+                       switch (test_pattern_color_space) {
+                       case DP_TEST_PATTERN_COLOR_SPACE_RGB:
+                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
+                               break;
+                       case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
+                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
+                               break;
+                       case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
+                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
+                               break;
+                       case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
+                       default:
+                               controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
+                               DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__);
+                               ASSERT(0);
+                               break;
+                       }
+
+                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+                               opp_cnt++;
+                       dpg_width = width / opp_cnt;
+                       offset = dpg_width;
+
+                       link->dc->hwss.set_disp_pattern_generator(link->dc,
+                                       pipe_ctx,
+                                       controller_test_pattern,
+                                       controller_color_space,
+                                       color_depth,
+                                       NULL,
+                                       dpg_width,
+                                       height,
+                                       0);
+
+                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+                               struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
+
+                               odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
+                               link->dc->hwss.set_disp_pattern_generator(link->dc,
+                                               odm_pipe,
+                                               controller_test_pattern,
+                                               controller_color_space,
+                                               color_depth,
+                                               NULL,
+                                               dpg_width,
+                                               height,
+                                               offset);
+                               offset += offset;
+                       }
+               }
+       }
+       break;
+       case DP_TEST_PATTERN_VIDEO_MODE:
+       {
+               /* restore bitdepth reduction */
+               resource_build_bit_depth_reduction_params(pipe_ctx->stream, &params);
+               pipe_ctx->stream->bit_depth_params = params;
+               opp->funcs->opp_program_bit_depth_reduction(opp, &params);
+               if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
+                       pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
+                               CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+                               color_depth);
+               else if (link->dc->hwss.set_disp_pattern_generator) {
+                       struct pipe_ctx *odm_pipe;
+                       int opp_cnt = 1;
+                       int dpg_width;
+
+                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+                               opp_cnt++;
+
+                       dpg_width = width / opp_cnt;
+                       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+                               struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
+
+                               odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
+                               link->dc->hwss.set_disp_pattern_generator(link->dc,
+                                               odm_pipe,
+                                               CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+                                               CONTROLLER_DP_COLOR_SPACE_UDEFINED,
+                                               color_depth,
+                                               NULL,
+                                               dpg_width,
+                                               height,
+                                               0);
+                       }
+                       link->dc->hwss.set_disp_pattern_generator(link->dc,
+                                       pipe_ctx,
+                                       CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+                                       CONTROLLER_DP_COLOR_SPACE_UDEFINED,
+                                       color_depth,
+                                       NULL,
+                                       dpg_width,
+                                       height,
+                                       0);
+               }
+       }
+       break;
+
+       default:
+       break;
+       }
+}
+
+void dc_link_dp_handle_automated_test(struct dc_link *link)
+{
+       union test_request test_request;
+       union test_response test_response;
+
+       memset(&test_request, 0, sizeof(test_request));
+       memset(&test_response, 0, sizeof(test_response));
+
+       core_link_read_dpcd(
+               link,
+               DP_TEST_REQUEST,
+               &test_request.raw,
+               sizeof(union test_request));
+       if (test_request.bits.LINK_TRAINING) {
+               /* ACK first to let DP RX test box monitor LT sequence */
+               test_response.bits.ACK = 1;
+               core_link_write_dpcd(
+                       link,
+                       DP_TEST_RESPONSE,
+                       &test_response.raw,
+                       sizeof(test_response));
+               dp_test_send_link_training(link);
+               /* no acknowledge request is needed again */
+               test_response.bits.ACK = 0;
+       }
+       if (test_request.bits.LINK_TEST_PATTRN) {
+               union test_misc dpcd_test_params;
+               union link_test_pattern dpcd_test_pattern;
+
+               memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
+               memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
+
+               /* get link test pattern and pattern parameters */
+               core_link_read_dpcd(
+                               link,
+                               DP_TEST_PATTERN,
+                               &dpcd_test_pattern.raw,
+                               sizeof(dpcd_test_pattern));
+               core_link_read_dpcd(
+                               link,
+                               DP_TEST_MISC0,
+                               &dpcd_test_params.raw,
+                               sizeof(dpcd_test_params));
+               test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link,
+                               dpcd_test_pattern, dpcd_test_params) ? 1 : 0;
+       }
+
+       if (test_request.bits.AUDIO_TEST_PATTERN) {
+               dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO);
+               test_response.bits.ACK = 1;
+       }
+
+       if (test_request.bits.PHY_TEST_PATTERN) {
+               dp_test_send_phy_test_pattern(link);
+               test_response.bits.ACK = 1;
+       }
+
+       /* send request acknowledgment */
+       if (test_response.bits.ACK)
+               core_link_write_dpcd(
+                       link,
+                       DP_TEST_RESPONSE,
+                       &test_response.raw,
+                       sizeof(test_response));
+}
+
+bool dc_link_dp_set_test_pattern(
+       struct dc_link *link,
+       enum dp_test_pattern test_pattern,
+       enum dp_test_pattern_color_space test_pattern_color_space,
+       const struct link_training_settings *p_link_settings,
+       const unsigned char *p_custom_pattern,
+       unsigned int cust_pattern_size)
+{
+       struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+       struct pipe_ctx *pipe_ctx = NULL;
+       unsigned int lane;
+       unsigned int i;
+       unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0};
+       union dpcd_training_pattern training_pattern;
+       enum dpcd_phy_test_patterns pattern;
+
+       memset(&training_pattern, 0, sizeof(training_pattern));
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (pipes[i].stream == NULL)
+                       continue;
+
+               if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
+                       pipe_ctx = &pipes[i];
+                       break;
+               }
+       }
+
+       if (pipe_ctx == NULL)
+               return false;
+
+       /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */
+       if (link->test_pattern_enabled && test_pattern ==
+                       DP_TEST_PATTERN_VIDEO_MODE) {
+               /* Set CRTC Test Pattern */
+               set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
+               dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
+                               (uint8_t *)p_custom_pattern,
+                               (uint32_t)cust_pattern_size);
+
+               /* Unblank Stream */
+               link->dc->hwss.unblank_stream(
+                       pipe_ctx,
+                       &link->verified_link_cap);
+               /* TODO:m_pHwss->MuteAudioEndpoint
+                * (pPathMode->pDisplayPath, false);
+                */
+
+               /* Reset Test Pattern state */
+               link->test_pattern_enabled = false;
+
+               return true;
+       }
+
+       /* Check for PHY Test Patterns */
+       if (is_dp_phy_pattern(test_pattern)) {
+               /* Set DPCD Lane Settings before running test pattern */
+               if (p_link_settings != NULL) {
+                       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+                                       p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
+                               dp_fixed_vs_pe_set_retimer_lane_settings(
+                                               link,
+                                               p_link_settings->dpcd_lane_settings,
+                                               p_link_settings->link_settings.lane_count);
+                       } else {
+                               dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX);
+                       }
+                       dpcd_set_lane_settings(link, p_link_settings, DPRX);
+               }
+
+               /* Blank stream if running test pattern */
+               if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
+                       /*TODO:
+                        * m_pHwss->
+                        * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
+                        */
+                       /* Blank stream */
+                       link->dc->hwss.blank_stream(pipe_ctx);
+               }
+
+               dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
+                               (uint8_t *)p_custom_pattern,
+                               (uint32_t)cust_pattern_size);
+
+               if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
+                       /* Set Test Pattern state */
+                       link->test_pattern_enabled = true;
+                       if (p_link_settings != NULL)
+                               dpcd_set_link_settings(link,
+                                               p_link_settings);
+               }
+
+               switch (test_pattern) {
+               case DP_TEST_PATTERN_VIDEO_MODE:
+                       pattern = PHY_TEST_PATTERN_NONE;
+                       break;
+               case DP_TEST_PATTERN_D102:
+                       pattern = PHY_TEST_PATTERN_D10_2;
+                       break;
+               case DP_TEST_PATTERN_SYMBOL_ERROR:
+                       pattern = PHY_TEST_PATTERN_SYMBOL_ERROR;
+                       break;
+               case DP_TEST_PATTERN_PRBS7:
+                       pattern = PHY_TEST_PATTERN_PRBS7;
+                       break;
+               case DP_TEST_PATTERN_80BIT_CUSTOM:
+                       pattern = PHY_TEST_PATTERN_80BIT_CUSTOM;
+                       break;
+               case DP_TEST_PATTERN_CP2520_1:
+                       pattern = PHY_TEST_PATTERN_CP2520_1;
+                       break;
+               case DP_TEST_PATTERN_CP2520_2:
+                       pattern = PHY_TEST_PATTERN_CP2520_2;
+                       break;
+               case DP_TEST_PATTERN_CP2520_3:
+                       pattern = PHY_TEST_PATTERN_CP2520_3;
+                       break;
+               case DP_TEST_PATTERN_128b_132b_TPS1:
+                       pattern = PHY_TEST_PATTERN_128b_132b_TPS1;
+                       break;
+               case DP_TEST_PATTERN_128b_132b_TPS2:
+                       pattern = PHY_TEST_PATTERN_128b_132b_TPS2;
+                       break;
+               case DP_TEST_PATTERN_PRBS9:
+                       pattern = PHY_TEST_PATTERN_PRBS9;
+                       break;
+               case DP_TEST_PATTERN_PRBS11:
+                       pattern = PHY_TEST_PATTERN_PRBS11;
+                       break;
+               case DP_TEST_PATTERN_PRBS15:
+                       pattern = PHY_TEST_PATTERN_PRBS15;
+                       break;
+               case DP_TEST_PATTERN_PRBS23:
+                       pattern = PHY_TEST_PATTERN_PRBS23;
+                       break;
+               case DP_TEST_PATTERN_PRBS31:
+                       pattern = PHY_TEST_PATTERN_PRBS31;
+                       break;
+               case DP_TEST_PATTERN_264BIT_CUSTOM:
+                       pattern = PHY_TEST_PATTERN_264BIT_CUSTOM;
+                       break;
+               case DP_TEST_PATTERN_SQUARE:
+                       pattern = PHY_TEST_PATTERN_SQUARE;
+                       break;
+               case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
+                       pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
+                       break;
+               case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
+                       pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
+                       break;
+               case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
+                       pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
+                       break;
+               default:
+                       return false;
+               }
+
+               if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE
+               /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/)
+                       return false;
+
+               if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
+                       if (is_dp_phy_sqaure_pattern(test_pattern))
+                               core_link_write_dpcd(link,
+                                               DP_LINK_SQUARE_PATTERN,
+                                               p_custom_pattern,
+                                               1);
+
+                       /* tell receiver that we are sending qualification
+                        * pattern DP 1.2 or later - DP receiver's link quality
+                        * pattern is set using DPCD LINK_QUAL_LANEx_SET
+                        * register (0x10B~0x10E)\
+                        */
+                       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++)
+                               link_qual_pattern[lane] =
+                                               (unsigned char)(pattern);
+
+                       core_link_write_dpcd(link,
+                                       DP_LINK_QUAL_LANE0_SET,
+                                       link_qual_pattern,
+                                       sizeof(link_qual_pattern));
+               } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 ||
+                          link->dpcd_caps.dpcd_rev.raw == 0) {
+                       /* tell receiver that we are sending qualification
+                        * pattern DP 1.1a or earlier - DP receiver's link
+                        * quality pattern is set using
+                        * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET
+                        * register (0x102). We will use v_1.3 when we are
+                        * setting test pattern for DP 1.1.
+                        */
+                       core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
+                                           &training_pattern.raw,
+                                           sizeof(training_pattern));
+                       training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
+                       core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
+                                            &training_pattern.raw,
+                                            sizeof(training_pattern));
+               }
+       } else {
+               enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
+
+               switch (test_pattern_color_space) {
+               case DP_TEST_PATTERN_COLOR_SPACE_RGB:
+                       color_space = COLOR_SPACE_SRGB;
+                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+                               color_space = COLOR_SPACE_SRGB_LIMITED;
+                       break;
+
+               case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
+                       color_space = COLOR_SPACE_YCBCR601;
+                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+                               color_space = COLOR_SPACE_YCBCR601_LIMITED;
+                       break;
+               case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
+                       color_space = COLOR_SPACE_YCBCR709;
+                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+                               color_space = COLOR_SPACE_YCBCR709_LIMITED;
+                       break;
+               default:
+                       break;
+               }
+
+               if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) {
+                       if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
+                               union dmub_hw_lock_flags hw_locks = { 0 };
+                               struct dmub_hw_lock_inst_flags inst_flags = { 0 };
+
+                               hw_locks.bits.lock_dig = 1;
+                               inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
+
+                               dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
+                                                       true,
+                                                       &hw_locks,
+                                                       &inst_flags);
+                       } else
+                               pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable(
+                                               pipe_ctx->stream_res.tg);
+               }
+
+               pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
+               /* update MSA to requested color space */
+               pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc,
+                               &pipe_ctx->stream->timing,
+                               color_space,
+                               pipe_ctx->stream->use_vsc_sdp_for_colorimetry,
+                               link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
+
+               if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) {
+                       if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+                               pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range
+                       else
+                               pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7);
+                       resource_build_info_frame(pipe_ctx);
+                       link->dc->hwss.update_info_frame(pipe_ctx);
+               }
+
+               /* CRTC Patterns */
+               set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
+               pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
+               pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
+                               CRTC_STATE_VACTIVE);
+               pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
+                               CRTC_STATE_VBLANK);
+               pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
+                               CRTC_STATE_VACTIVE);
+
+               if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) {
+                       if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
+                               union dmub_hw_lock_flags hw_locks = { 0 };
+                               struct dmub_hw_lock_inst_flags inst_flags = { 0 };
+
+                               hw_locks.bits.lock_dig = 1;
+                               inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
+
+                               dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
+                                                       false,
+                                                       &hw_locks,
+                                                       &inst_flags);
+                       } else
+                               pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable(
+                                               pipe_ctx->stream_res.tg);
+               }
+
+               /* Set Test Pattern state */
+               link->test_pattern_enabled = true;
+       }
+
+       return true;
+}
+
+void dc_link_set_drive_settings(struct dc *dc,
+                               struct link_training_settings *lt_settings,
+                               const struct dc_link *link)
+{
+
+       int i;
+       struct link_resource link_res;
+
+       for (i = 0; i < dc->link_count; i++)
+               if (dc->links[i] == link)
+                       break;
+
+       if (i >= dc->link_count)
+               ASSERT_CRITICAL(false);
+
+       dc_link_get_cur_link_res(link, &link_res);
+       dp_set_drive_settings(dc->links[i], &link_res, lt_settings);
+}
+
+void dc_link_set_preferred_link_settings(struct dc *dc,
+                                        struct dc_link_settings *link_setting,
+                                        struct dc_link *link)
+{
+       int i;
+       struct pipe_ctx *pipe;
+       struct dc_stream_state *link_stream;
+       struct dc_link_settings store_settings = *link_setting;
+
+       link->preferred_link_setting = store_settings;
+
+       /* Retrain with preferred link settings only relevant for
+        * DP signal type
+        * Check for non-DP signal or if passive dongle present
+        */
+       if (!dc_is_dp_signal(link->connector_signal) ||
+               link->dongle_max_pix_clk > 0)
+               return;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+               if (pipe->stream && pipe->stream->link) {
+                       if (pipe->stream->link == link) {
+                               link_stream = pipe->stream;
+                               break;
+                       }
+               }
+       }
+
+       /* Stream not found */
+       if (i == MAX_PIPES)
+               return;
+
+       /* Cannot retrain link if backend is off */
+       if (link_stream->dpms_off)
+               return;
+
+       if (link_decide_link_settings(link_stream, &store_settings))
+               dp_retrain_link_dp_test(link, &store_settings, false);
+}
+
+void dc_link_set_preferred_training_settings(struct dc *dc,
+                                                struct dc_link_settings *link_setting,
+                                                struct dc_link_training_overrides *lt_overrides,
+                                                struct dc_link *link,
+                                                bool skip_immediate_retrain)
+{
+       if (lt_overrides != NULL)
+               link->preferred_training_settings = *lt_overrides;
+       else
+               memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
+
+       if (link_setting != NULL) {
+               link->preferred_link_setting = *link_setting;
+       } else {
+               link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
+               link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
+       }
+
+       if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+                       link->type == dc_connection_mst_branch)
+               dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link);
+
+       /* Retrain now, or wait until next stream update to apply */
+       if (skip_immediate_retrain == false)
+               dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
+}
+
+void dc_link_set_test_pattern(struct dc_link *link,
+               enum dp_test_pattern test_pattern,
+               enum dp_test_pattern_color_space test_pattern_color_space,
+               const struct link_training_settings *p_link_settings,
+               const unsigned char *p_custom_pattern,
+               unsigned int cust_pattern_size)
+{
+       if (link != NULL)
+               dc_link_dp_set_test_pattern(
+                       link,
+                       test_pattern,
+                       test_pattern_color_space,
+                       p_link_settings,
+                       p_custom_pattern,
+                       cust_pattern_size);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h
new file mode 100644 (file)
index 0000000..7f17838
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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_DP_CTS_H__
+#define __LINK_DP_CTS_H__
+#include "link.h"
+
+void dp_retrain_link_dp_test(struct dc_link *link,
+               struct dc_link_settings *link_setting,
+               bool skip_video_pattern);
+
+#endif /* __LINK_DP_CTS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c
new file mode 100644 (file)
index 0000000..04838a3
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "dc_link.h"
+#include "link_dp_trace.h"
+
+void dp_trace_init(struct dc_link *link)
+{
+       memset(&link->dp_trace, 0, sizeof(link->dp_trace));
+       link->dp_trace.is_initialized = true;
+}
+
+void dp_trace_reset(struct dc_link *link)
+{
+       memset(&link->dp_trace, 0, sizeof(link->dp_trace));
+}
+
+bool dc_dp_trace_is_initialized(struct dc_link *link)
+{
+       return link->dp_trace.is_initialized;
+}
+
+void dp_trace_detect_lt_init(struct dc_link *link)
+{
+       memset(&link->dp_trace.detect_lt_trace, 0, sizeof(link->dp_trace.detect_lt_trace));
+}
+
+void dp_trace_commit_lt_init(struct dc_link *link)
+{
+       memset(&link->dp_trace.commit_lt_trace, 0, sizeof(link->dp_trace.commit_lt_trace));
+}
+
+void dp_trace_link_loss_increment(struct dc_link *link)
+{
+       link->dp_trace.link_loss_count++;
+}
+
+void dp_trace_lt_fail_count_update(struct dc_link *link,
+               unsigned int fail_count,
+               bool in_detection)
+{
+       if (in_detection)
+               link->dp_trace.detect_lt_trace.counts.fail = fail_count;
+       else
+               link->dp_trace.commit_lt_trace.counts.fail = fail_count;
+}
+
+void dp_trace_lt_total_count_increment(struct dc_link *link,
+               bool in_detection)
+{
+       if (in_detection)
+               link->dp_trace.detect_lt_trace.counts.total++;
+       else
+               link->dp_trace.commit_lt_trace.counts.total++;
+}
+
+void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
+               bool in_detection,
+               bool is_logged)
+{
+       if (in_detection)
+               link->dp_trace.detect_lt_trace.is_logged = is_logged;
+       else
+               link->dp_trace.commit_lt_trace.is_logged = is_logged;
+}
+
+bool dc_dp_trace_is_logged(struct dc_link *link,
+               bool in_detection)
+{
+       if (in_detection)
+               return link->dp_trace.detect_lt_trace.is_logged;
+       else
+               return link->dp_trace.commit_lt_trace.is_logged;
+}
+
+void dp_trace_lt_result_update(struct dc_link *link,
+               enum link_training_result result,
+               bool in_detection)
+{
+       if (in_detection)
+               link->dp_trace.detect_lt_trace.result = result;
+       else
+               link->dp_trace.commit_lt_trace.result = result;
+}
+
+void dp_trace_set_lt_start_timestamp(struct dc_link *link,
+               bool in_detection)
+{
+       if (in_detection)
+               link->dp_trace.detect_lt_trace.timestamps.start = dm_get_timestamp(link->dc->ctx);
+       else
+               link->dp_trace.commit_lt_trace.timestamps.start = dm_get_timestamp(link->dc->ctx);
+}
+
+void dp_trace_set_lt_end_timestamp(struct dc_link *link,
+               bool in_detection)
+{
+       if (in_detection)
+               link->dp_trace.detect_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx);
+       else
+               link->dp_trace.commit_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx);
+}
+
+unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
+               bool in_detection)
+{
+       if (in_detection)
+               return link->dp_trace.detect_lt_trace.timestamps.end;
+       else
+               return link->dp_trace.commit_lt_trace.timestamps.end;
+}
+
+struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
+               bool in_detection)
+{
+       if (in_detection)
+               return &link->dp_trace.detect_lt_trace.counts;
+       else
+               return &link->dp_trace.commit_lt_trace.counts;
+}
+
+unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link)
+{
+       return link->dp_trace.link_loss_count;
+}
+
+void link_dp_trace_set_edp_power_timestamp(struct dc_link *link,
+               bool power_up)
+{
+       if (!power_up)
+               /*save driver power off time stamp*/
+               link->dp_trace.edp_trace_power_timestamps.poweroff = dm_get_timestamp(link->dc->ctx);
+       else
+               link->dp_trace.edp_trace_power_timestamps.poweron = dm_get_timestamp(link->dc->ctx);
+}
+
+uint64_t link_dp_trace_get_edp_poweron_timestamp(struct dc_link *link)
+{
+       return link->dp_trace.edp_trace_power_timestamps.poweron;
+}
+
+uint64_t link_dp_trace_get_edp_poweroff_timestamp(struct dc_link *link)
+{
+       return link->dp_trace.edp_trace_power_timestamps.poweroff;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h
new file mode 100644 (file)
index 0000000..702f97c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_DP_TRACE_H__
+#define __LINK_DP_TRACE_H__
+
+void dp_trace_init(struct dc_link *link);
+void dp_trace_reset(struct dc_link *link);
+bool dc_dp_trace_is_initialized(struct dc_link *link);
+void dp_trace_detect_lt_init(struct dc_link *link);
+void dp_trace_commit_lt_init(struct dc_link *link);
+void dp_trace_link_loss_increment(struct dc_link *link);
+void dp_trace_lt_fail_count_update(struct dc_link *link,
+               unsigned int fail_count,
+               bool in_detection);
+void dp_trace_lt_total_count_increment(struct dc_link *link,
+               bool in_detection);
+void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
+               bool in_detection,
+               bool is_logged);
+bool dc_dp_trace_is_logged(struct dc_link *link,
+               bool in_detection);
+void dp_trace_lt_result_update(struct dc_link *link,
+               enum link_training_result result,
+               bool in_detection);
+void dp_trace_set_lt_start_timestamp(struct dc_link *link,
+               bool in_detection);
+void dp_trace_set_lt_end_timestamp(struct dc_link *link,
+               bool in_detection);
+unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
+               bool in_detection);
+struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
+               bool in_detection);
+unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
+
+#endif /* __LINK_DP_TRACE_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
new file mode 100644 (file)
index 0000000..841a23d
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "link_hwss_dio.h"
+#include "core_types.h"
+#include "link_enc_cfg.h"
+
+void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+               struct fixed31_32 throttled_vcp_size)
+{
+       struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+
+       stream_encoder->funcs->set_throttled_vcp_size(
+                               stream_encoder,
+                               throttled_vcp_size);
+}
+
+void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
+       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+
+       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,
+                               DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
+       if (stream_enc->funcs->enable_fifo)
+               stream_enc->funcs->enable_fifo(stream_enc);
+}
+
+void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
+       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+
+       if (stream_enc && stream_enc->funcs->disable_fifo)
+               stream_enc->funcs->disable_fifo(stream_enc);
+
+       link_enc->funcs->connect_dig_be_to_fe(
+                       link_enc,
+                       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,
+                               DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
+
+}
+
+void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx)
+{
+       struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+
+       if (!dc_is_virtual_signal(stream->signal))
+               stream_encoder->funcs->setup_stereo_sync(
+                               stream_encoder,
+                               pipe_ctx->stream_res.tg->inst,
+                               stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
+
+       if (dc_is_dp_signal(stream->signal))
+               stream_encoder->funcs->dp_set_stream_attribute(
+                               stream_encoder,
+                               &stream->timing,
+                               stream->output_color_space,
+                               stream->use_vsc_sdp_for_colorimetry,
+                               link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
+       else if (dc_is_hdmi_tmds_signal(stream->signal))
+               stream_encoder->funcs->hdmi_set_stream_attribute(
+                               stream_encoder,
+                               &stream->timing,
+                               stream->phy_pix_clk,
+                               pipe_ctx->stream_res.audio != NULL);
+       else if (dc_is_dvi_signal(stream->signal))
+               stream_encoder->funcs->dvi_set_stream_attribute(
+                               stream_encoder,
+                               &stream->timing,
+                               (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
+                                               true : false);
+       else if (dc_is_lvds_signal(stream->signal))
+               stream_encoder->funcs->lvds_set_stream_attribute(
+                               stream_encoder,
+                               &stream->timing);
+
+       if (dc_is_dp_signal(stream->signal))
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+}
+
+void enable_dio_dp_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal,
+               enum clock_source_id clock_source,
+               const struct dc_link_settings *link_settings)
+{
+       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+       if (dc_is_dp_sst_signal(signal))
+               link_enc->funcs->enable_dp_output(
+                               link_enc,
+                               link_settings,
+                               clock_source);
+       else
+               link_enc->funcs->enable_dp_mst_output(
+                               link_enc,
+                               link_settings,
+                               clock_source);
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
+}
+
+void disable_dio_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+{
+       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);
+}
+
+void set_dio_dp_link_test_pattern(struct dc_link *link,
+               const struct link_resource *link_res,
+               struct encoder_set_dp_phy_pattern_param *tp_params)
+{
+       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);
+}
+
+void set_dio_dp_lane_settings(struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct dc_link_settings *link_settings,
+               const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+       link_enc->funcs->dp_set_lane_settings(link_enc, link_settings, lane_settings);
+}
+
+static void update_dio_stream_allocation_table(struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct link_mst_stream_allocation_table *table)
+{
+       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+       ASSERT(link_enc);
+       link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
+}
+
+void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
+               struct audio_output *audio_output, uint32_t audio_inst)
+{
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
+                               pipe_ctx->stream_res.stream_enc,
+                               audio_inst,
+                               &pipe_ctx->stream->audio_info);
+       else
+               pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
+                               pipe_ctx->stream_res.stream_enc,
+                               audio_inst,
+                               &pipe_ctx->stream->audio_info,
+                               &audio_output->crtc_info);
+}
+
+void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(
+                               pipe_ctx->stream_res.stream_enc);
+
+       pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+                       pipe_ctx->stream_res.stream_enc, false);
+
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(pipe_ctx->stream->link,
+                               DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
+}
+
+void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+       pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+                       pipe_ctx->stream_res.stream_enc, true);
+
+       if (pipe_ctx->stream_res.audio) {
+               if (dc_is_dp_signal(pipe_ctx->stream->signal))
+                       pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
+                                       pipe_ctx->stream_res.stream_enc);
+               else
+                       pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
+                                       pipe_ctx->stream_res.stream_enc);
+       }
+
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(pipe_ctx->stream->link,
+                               DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
+}
+
+static const struct link_hwss dio_link_hwss = {
+       .setup_stream_encoder = setup_dio_stream_encoder,
+       .reset_stream_encoder = reset_dio_stream_encoder,
+       .setup_stream_attribute = setup_dio_stream_attribute,
+       .disable_link_output = disable_dio_link_output,
+       .setup_audio_output = setup_dio_audio_output,
+       .enable_audio_packet = enable_dio_audio_packet,
+       .disable_audio_packet = disable_dio_audio_packet,
+       .ext = {
+               .set_throttled_vcp_size = set_dio_throttled_vcp_size,
+               .enable_dp_link_output = enable_dio_dp_link_output,
+               .set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
+               .set_dp_lane_settings = set_dio_dp_lane_settings,
+               .update_stream_allocation_table = update_dio_stream_allocation_table,
+       },
+};
+
+bool can_use_dio_link_hwss(const struct dc_link *link,
+               const struct link_resource *link_res)
+{
+       return link->link_enc != NULL;
+}
+
+const struct link_hwss *get_dio_link_hwss(void)
+{
+       return &dio_link_hwss;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h
new file mode 100644 (file)
index 0000000..8b8a099
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_DIO_H__
+#define __LINK_HWSS_DIO_H__
+
+#include "link_hwss.h"
+#include "link.h"
+
+const struct link_hwss *get_dio_link_hwss(void);
+bool can_use_dio_link_hwss(const struct dc_link *link,
+               const struct link_resource *link_res);
+void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+               struct fixed31_32 throttled_vcp_size);
+void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx);
+void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx);
+void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx);
+void enable_dio_dp_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal,
+               enum clock_source_id clock_source,
+               const struct dc_link_settings *link_settings);
+void disable_dio_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal);
+void set_dio_dp_link_test_pattern(struct dc_link *link,
+               const struct link_resource *link_res,
+               struct encoder_set_dp_phy_pattern_param *tp_params);
+void set_dio_dp_lane_settings(struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct dc_link_settings *link_settings,
+               const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
+void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
+               struct audio_output *audio_output, uint32_t audio_inst);
+void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
+void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
+
+#endif /* __LINK_HWSS_DIO_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c
new file mode 100644 (file)
index 0000000..861f3cd
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "link_hwss_dpia.h"
+#include "core_types.h"
+#include "link_hwss_dio.h"
+#include "link_enc_cfg.h"
+
+#define DC_LOGGER_INIT(logger)
+
+static void update_dpia_stream_allocation_table(struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct link_mst_stream_allocation_table *table)
+{
+       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+       static enum dc_status status;
+       uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF;
+       int i;
+       DC_LOGGER_INIT(link->ctx->logger);
+
+       for (i = 0; i < table->stream_count; i++)
+               mst_alloc_slots += table->stream_allocations[i].slot_count;
+
+       status = dc_process_dmub_set_mst_slots(link->dc, link->link_index,
+                       mst_alloc_slots, &prev_mst_slots_in_use);
+       ASSERT(status == DC_OK);
+       DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n",
+                       status, mst_alloc_slots, prev_mst_slots_in_use);
+
+       ASSERT(link_enc);
+       link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
+}
+
+static const struct link_hwss dpia_link_hwss = {
+       .setup_stream_encoder = setup_dio_stream_encoder,
+       .reset_stream_encoder = reset_dio_stream_encoder,
+       .setup_stream_attribute = setup_dio_stream_attribute,
+       .disable_link_output = disable_dio_link_output,
+       .setup_audio_output = setup_dio_audio_output,
+       .enable_audio_packet = enable_dio_audio_packet,
+       .disable_audio_packet = disable_dio_audio_packet,
+       .ext = {
+               .set_throttled_vcp_size = set_dio_throttled_vcp_size,
+               .enable_dp_link_output = enable_dio_dp_link_output,
+               .set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
+               .set_dp_lane_settings = set_dio_dp_lane_settings,
+               .update_stream_allocation_table = update_dpia_stream_allocation_table,
+       },
+};
+
+bool can_use_dpia_link_hwss(const struct dc_link *link,
+               const struct link_resource *link_res)
+{
+       return link->is_dig_mapping_flexible &&
+                       link->dc->res_pool->funcs->link_encs_assign;
+}
+
+const struct link_hwss *get_dpia_link_hwss(void)
+{
+       return &dpia_link_hwss;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.h
new file mode 100644 (file)
index 0000000..ad16ec5
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_DPIA_H__
+#define __LINK_HWSS_DPIA_H__
+
+#include "link_hwss.h"
+
+const struct link_hwss *get_dpia_link_hwss(void);
+bool can_use_dpia_link_hwss(const struct dc_link *link,
+               const struct link_resource *link_res);
+
+#endif /* __LINK_HWSS_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
new file mode 100644 (file)
index 0000000..d8947f3
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "link_hwss_hpo_dp.h"
+#include "dm_helpers.h"
+#include "core_types.h"
+#include "dccg.h"
+#include "clk_mgr.h"
+
+static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
+{
+       switch (link->link_enc->transmitter) {
+       case TRANSMITTER_UNIPHY_A:
+               return PHYD32CLKA;
+       case TRANSMITTER_UNIPHY_B:
+               return PHYD32CLKB;
+       case TRANSMITTER_UNIPHY_C:
+               return PHYD32CLKC;
+       case TRANSMITTER_UNIPHY_D:
+               return PHYD32CLKD;
+       case TRANSMITTER_UNIPHY_E:
+               return PHYD32CLKE;
+       default:
+               return PHYD32CLKA;
+       }
+}
+
+static void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+               struct fixed31_32 throttled_vcp_size)
+{
+       struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
+                       pipe_ctx->stream_res.hpo_dp_stream_enc;
+       struct hpo_dp_link_encoder *hpo_dp_link_encoder =
+                       pipe_ctx->link_res.hpo_dp_link_enc;
+
+       hpo_dp_link_encoder->funcs->set_throttled_vcp_size(hpo_dp_link_encoder,
+                       hpo_dp_stream_encoder->inst,
+                       throttled_vcp_size);
+}
+
+static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
+               const struct dc_link_settings *link_settings,
+               struct fixed31_32 throttled_vcp_size)
+{
+       struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
+                       pipe_ctx->stream_res.hpo_dp_stream_enc;
+       struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
+       struct fixed31_32 h_blank_in_ms, time_slot_in_ms, mtp_cnt_per_h_blank;
+       uint32_t link_bw_in_kbps =
+                       dc_link_bandwidth_kbps(pipe_ctx->stream->link, link_settings);
+       uint16_t hblank_min_symbol_width = 0;
+
+       if (link_bw_in_kbps > 0) {
+               h_blank_in_ms = dc_fixpt_div(dc_fixpt_from_int(
+                               timing->h_total - timing->h_addressable),
+                               dc_fixpt_from_fraction(timing->pix_clk_100hz, 10));
+               time_slot_in_ms = dc_fixpt_from_fraction(32 * 4, link_bw_in_kbps);
+               mtp_cnt_per_h_blank = dc_fixpt_div(h_blank_in_ms,
+                               dc_fixpt_mul_int(time_slot_in_ms, 64));
+               hblank_min_symbol_width = dc_fixpt_floor(
+                               dc_fixpt_mul(mtp_cnt_per_h_blank, throttled_vcp_size));
+       }
+
+       hpo_dp_stream_encoder->funcs->set_hblank_min_symbol_width(hpo_dp_stream_encoder,
+                       hblank_min_symbol_width);
+}
+
+static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+       struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+       struct hpo_dp_link_encoder *link_enc = pipe_ctx->link_res.hpo_dp_link_enc;
+
+       stream_enc->funcs->enable_stream(stream_enc);
+       stream_enc->funcs->map_stream_to_link(stream_enc, stream_enc->inst, link_enc->inst);
+}
+
+static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+       struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+
+       stream_enc->funcs->disable(stream_enc);
+}
+
+static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
+{
+       struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+
+       stream_enc->funcs->set_stream_attribute(
+                       stream_enc,
+                       &stream->timing,
+                       stream->output_color_space,
+                       stream->use_vsc_sdp_for_colorimetry,
+                       stream->timing.flags.DSC,
+                       false);
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+}
+
+static void enable_hpo_dp_fpga_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal,
+               enum clock_source_id clock_source,
+               const struct dc_link_settings *link_settings)
+{
+       const struct dc *dc = link->dc;
+       enum phyd32clk_clock_source phyd32clk = get_phyd32clk_src(link);
+       int phyd32clk_freq_khz = link_settings->link_rate == LINK_RATE_UHBR10 ? 312500 :
+                       link_settings->link_rate == LINK_RATE_UHBR13_5 ? 412875 :
+                       link_settings->link_rate == LINK_RATE_UHBR20 ? 625000 : 0;
+
+       dm_set_phyd32clk(dc->ctx, phyd32clk_freq_khz);
+       dc->res_pool->dccg->funcs->set_physymclk(
+                       dc->res_pool->dccg,
+                       link->link_enc_hw_inst,
+                       PHYSYMCLK_FORCE_SRC_PHYD32CLK,
+                       true);
+       dc->res_pool->dccg->funcs->enable_symclk32_le(
+                       dc->res_pool->dccg,
+                       link_res->hpo_dp_link_enc->inst,
+                       phyd32clk);
+       link_res->hpo_dp_link_enc->funcs->link_enable(
+                       link_res->hpo_dp_link_enc,
+                       link_settings->lane_count);
+
+}
+
+static void enable_hpo_dp_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal,
+               enum clock_source_id clock_source,
+               const struct dc_link_settings *link_settings)
+{
+       if (IS_FPGA_MAXIMUS_DC(link->dc->ctx->dce_environment))
+               enable_hpo_dp_fpga_link_output(link, link_res, signal,
+                               clock_source, link_settings);
+       else
+               link_res->hpo_dp_link_enc->funcs->enable_link_phy(
+                               link_res->hpo_dp_link_enc,
+                               link_settings,
+                               link->link_enc->transmitter,
+                               link->link_enc->hpd_source);
+}
+
+
+static void disable_hpo_dp_fpga_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+{
+       const struct dc *dc = link->dc;
+
+       link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
+       dc->res_pool->dccg->funcs->disable_symclk32_le(
+                       dc->res_pool->dccg,
+                       link_res->hpo_dp_link_enc->inst);
+       dc->res_pool->dccg->funcs->set_physymclk(
+                       dc->res_pool->dccg,
+                       link->link_enc_hw_inst,
+                       PHYSYMCLK_FORCE_SRC_SYMCLK,
+                       false);
+       dm_set_phyd32clk(dc->ctx, 0);
+}
+
+static void disable_hpo_dp_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+{
+       if (IS_FPGA_MAXIMUS_DC(link->dc->ctx->dce_environment)) {
+               disable_hpo_dp_fpga_link_output(link, link_res, signal);
+       } else {
+               link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
+               link_res->hpo_dp_link_enc->funcs->disable_link_phy(
+                               link_res->hpo_dp_link_enc, signal);
+       }
+}
+
+static void set_hpo_dp_link_test_pattern(struct dc_link *link,
+               const struct link_resource *link_res,
+               struct encoder_set_dp_phy_pattern_param *tp_params)
+{
+       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);
+}
+
+static void set_hpo_dp_lane_settings(struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct dc_link_settings *link_settings,
+               const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+       link_res->hpo_dp_link_enc->funcs->set_ffe(
+                       link_res->hpo_dp_link_enc,
+                       link_settings,
+                       lane_settings[0].FFE_PRESET.raw);
+}
+
+static void update_hpo_dp_stream_allocation_table(struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct link_mst_stream_allocation_table *table)
+{
+       link_res->hpo_dp_link_enc->funcs->update_stream_allocation_table(
+                       link_res->hpo_dp_link_enc,
+                       table);
+}
+
+static void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
+               struct audio_output *audio_output, uint32_t audio_inst)
+{
+       pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
+                       pipe_ctx->stream_res.hpo_dp_stream_enc,
+                       audio_inst,
+                       &pipe_ctx->stream->audio_info);
+}
+
+static void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+       pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(
+                       pipe_ctx->stream_res.hpo_dp_stream_enc);
+}
+
+static void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
+{
+       if (pipe_ctx->stream_res.audio)
+               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
+                               pipe_ctx->stream_res.hpo_dp_stream_enc);
+}
+
+static const struct link_hwss hpo_dp_link_hwss = {
+       .setup_stream_encoder = setup_hpo_dp_stream_encoder,
+       .reset_stream_encoder = reset_hpo_dp_stream_encoder,
+       .setup_stream_attribute = setup_hpo_dp_stream_attribute,
+       .disable_link_output = disable_hpo_dp_link_output,
+       .setup_audio_output = setup_hpo_dp_audio_output,
+       .enable_audio_packet = enable_hpo_dp_audio_packet,
+       .disable_audio_packet = disable_hpo_dp_audio_packet,
+       .ext = {
+               .set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size,
+               .set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width,
+               .enable_dp_link_output = enable_hpo_dp_link_output,
+               .set_dp_link_test_pattern  = set_hpo_dp_link_test_pattern,
+               .set_dp_lane_settings = set_hpo_dp_lane_settings,
+               .update_stream_allocation_table = update_hpo_dp_stream_allocation_table,
+       },
+};
+
+bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
+               const struct link_resource *link_res)
+{
+       return link_res->hpo_dp_link_enc != NULL;
+}
+
+const struct link_hwss *get_hpo_dp_link_hwss(void)
+{
+       return &hpo_dp_link_hwss;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.h
new file mode 100644 (file)
index 0000000..3cbb94b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_HPO_DP_H__
+#define __LINK_HWSS_HPO_DP_H__
+
+#include "link_hwss.h"
+#include "link.h"
+
+bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
+               const struct link_resource *link_res);
+const struct link_hwss *get_hpo_dp_link_hwss(void);
+
+
+#endif /* __LINK_HWSS_HPO_DP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_ddc.c b/drivers/gpu/drm/amd/display/dc/link/link_ddc.c
deleted file mode 100644 (file)
index 5269125..0000000
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright 2012-15 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 generic display communication protocols such as i2c, aux
- * and scdc. The file should not contain any specific applications of these
- * protocols such as display capability query, detection, or handshaking such as
- * link training.
- */
-#include "link_ddc.h"
-#include "vector.h"
-#include "dce/dce_aux.h"
-#include "dal_asic_id.h"
-#include "link_dpcd.h"
-#include "dm_helpers.h"
-#include "atomfirmware.h"
-
-#define DC_LOGGER_INIT(logger)
-
-static const uint8_t DP_VGA_DONGLE_BRANCH_DEV_NAME[] = "DpVga";
-/* DP to Dual link DVI converter */
-static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa";
-static const uint8_t DP_DVI_CONVERTER_ID_5[] = "3393N2";
-
-struct i2c_payloads {
-       struct vector payloads;
-};
-
-struct aux_payloads {
-       struct vector payloads;
-};
-
-static bool dal_ddc_i2c_payloads_create(
-               struct dc_context *ctx,
-               struct i2c_payloads *payloads,
-               uint32_t count)
-{
-       if (dal_vector_construct(
-               &payloads->payloads, ctx, count, sizeof(struct i2c_payload)))
-               return true;
-
-       return false;
-}
-
-static struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p)
-{
-       return (struct i2c_payload *)p->payloads.container;
-}
-
-static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p)
-{
-       return p->payloads.count;
-}
-
-#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
-
-static void i2c_payloads_add(
-       struct i2c_payloads *payloads,
-       uint32_t address,
-       uint32_t len,
-       uint8_t *data,
-       bool write)
-{
-       uint32_t payload_size = EDID_SEGMENT_SIZE;
-       uint32_t pos;
-
-       for (pos = 0; pos < len; pos += payload_size) {
-               struct i2c_payload payload = {
-                       .write = write,
-                       .address = address,
-                       .length = DDC_MIN(payload_size, len - pos),
-                       .data = data + pos };
-               dal_vector_append(&payloads->payloads, &payload);
-       }
-
-}
-
-static void ddc_service_construct(
-       struct ddc_service *ddc_service,
-       struct ddc_service_init_data *init_data)
-{
-       enum connector_id connector_id =
-               dal_graphics_object_id_get_connector_id(init_data->id);
-
-       struct gpio_service *gpio_service = init_data->ctx->gpio_service;
-       struct graphics_object_i2c_info i2c_info;
-       struct gpio_ddc_hw_info hw_info;
-       struct dc_bios *dcb = init_data->ctx->dc_bios;
-
-       ddc_service->link = init_data->link;
-       ddc_service->ctx = init_data->ctx;
-
-       if (init_data->is_dpia_link ||
-           dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info) != BP_RESULT_OK) {
-               ddc_service->ddc_pin = NULL;
-       } else {
-               DC_LOGGER_INIT(ddc_service->ctx->logger);
-               DC_LOG_DC("BIOS object table - i2c_line: %d", i2c_info.i2c_line);
-               DC_LOG_DC("BIOS object table - i2c_engine_id: %d", i2c_info.i2c_engine_id);
-
-               hw_info.ddc_channel = i2c_info.i2c_line;
-               if (ddc_service->link != NULL)
-                       hw_info.hw_supported = i2c_info.i2c_hw_assist;
-               else
-                       hw_info.hw_supported = false;
-
-               ddc_service->ddc_pin = dal_gpio_create_ddc(
-                       gpio_service,
-                       i2c_info.gpio_info.clk_a_register_index,
-                       1 << i2c_info.gpio_info.clk_a_shift,
-                       &hw_info);
-       }
-
-       ddc_service->flags.EDID_QUERY_DONE_ONCE = false;
-       ddc_service->flags.FORCE_READ_REPEATED_START = false;
-       ddc_service->flags.EDID_STRESS_READ = false;
-
-       ddc_service->flags.IS_INTERNAL_DISPLAY =
-               connector_id == CONNECTOR_ID_EDP ||
-               connector_id == CONNECTOR_ID_LVDS;
-
-       ddc_service->wa.raw = 0;
-}
-
-struct ddc_service *link_create_ddc_service(
-       struct ddc_service_init_data *init_data)
-{
-       struct ddc_service *ddc_service;
-
-       ddc_service = kzalloc(sizeof(struct ddc_service), GFP_KERNEL);
-
-       if (!ddc_service)
-               return NULL;
-
-       ddc_service_construct(ddc_service, init_data);
-       return ddc_service;
-}
-
-static void ddc_service_destruct(struct ddc_service *ddc)
-{
-       if (ddc->ddc_pin)
-               dal_gpio_destroy_ddc(&ddc->ddc_pin);
-}
-
-void link_destroy_ddc_service(struct ddc_service **ddc)
-{
-       if (!ddc || !*ddc) {
-               BREAK_TO_DEBUGGER();
-               return;
-       }
-       ddc_service_destruct(*ddc);
-       kfree(*ddc);
-       *ddc = NULL;
-}
-
-void set_ddc_transaction_type(
-       struct ddc_service *ddc,
-       enum ddc_transaction_type type)
-{
-       ddc->transaction_type = type;
-}
-
-bool link_is_in_aux_transaction_mode(struct ddc_service *ddc)
-{
-       switch (ddc->transaction_type) {
-       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
-       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
-       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER:
-               return true;
-       default:
-               break;
-       }
-       return false;
-}
-
-void set_dongle_type(struct ddc_service *ddc,
-               enum display_dongle_type dongle_type)
-{
-       ddc->dongle_type = dongle_type;
-}
-
-static uint32_t defer_delay_converter_wa(
-       struct ddc_service *ddc,
-       uint32_t defer_delay)
-{
-       struct dc_link *link = ddc->link;
-
-       if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER &&
-               link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
-               (link->dpcd_caps.branch_fw_revision[0] < 0x01 ||
-                               (link->dpcd_caps.branch_fw_revision[0] == 0x01 &&
-                               link->dpcd_caps.branch_fw_revision[1] < 0x40)) &&
-               !memcmp(link->dpcd_caps.branch_dev_name,
-                   DP_VGA_DONGLE_BRANCH_DEV_NAME,
-                       sizeof(link->dpcd_caps.branch_dev_name)))
-
-               return defer_delay > DPVGA_DONGLE_AUX_DEFER_WA_DELAY ?
-                       defer_delay : DPVGA_DONGLE_AUX_DEFER_WA_DELAY;
-
-       if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
-           !memcmp(link->dpcd_caps.branch_dev_name,
-                   DP_DVI_CONVERTER_ID_4,
-                   sizeof(link->dpcd_caps.branch_dev_name)))
-               return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ?
-                       defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY;
-       if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_006037 &&
-           !memcmp(link->dpcd_caps.branch_dev_name,
-                   DP_DVI_CONVERTER_ID_5,
-                   sizeof(link->dpcd_caps.branch_dev_name)))
-               return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY_1MS ?
-                       I2C_OVER_AUX_DEFER_WA_DELAY_1MS : defer_delay;
-
-       return defer_delay;
-}
-
-#define DP_TRANSLATOR_DELAY 5
-
-uint32_t link_get_aux_defer_delay(struct ddc_service *ddc)
-{
-       uint32_t defer_delay = 0;
-
-       switch (ddc->transaction_type) {
-       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
-               if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) ||
-                       (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) ||
-                       (DISPLAY_DONGLE_DP_HDMI_CONVERTER ==
-                               ddc->dongle_type)) {
-
-                       defer_delay = DP_TRANSLATOR_DELAY;
-
-                       defer_delay =
-                               defer_delay_converter_wa(ddc, defer_delay);
-
-               } else /*sink has a delay different from an Active Converter*/
-                       defer_delay = 0;
-               break;
-       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
-               defer_delay = DP_TRANSLATOR_DELAY;
-               break;
-       default:
-               break;
-       }
-       return defer_delay;
-}
-
-static bool submit_aux_command(struct ddc_service *ddc,
-               struct aux_payload *payload)
-{
-       uint32_t retrieved = 0;
-       bool ret = false;
-
-       if (!ddc)
-               return false;
-
-       if (!payload)
-               return false;
-
-       do {
-               struct aux_payload current_payload;
-               bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >=
-                               payload->length;
-               uint32_t payload_length = is_end_of_payload ?
-                               payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE;
-
-               current_payload.address = payload->address;
-               current_payload.data = &payload->data[retrieved];
-               current_payload.defer_delay = payload->defer_delay;
-               current_payload.i2c_over_aux = payload->i2c_over_aux;
-               current_payload.length = payload_length;
-               /* set mot (middle of transaction) to false if it is the last payload */
-               current_payload.mot = is_end_of_payload ? payload->mot:true;
-               current_payload.write_status_update = false;
-               current_payload.reply = payload->reply;
-               current_payload.write = payload->write;
-
-               ret = link_aux_transfer_with_retries_no_mutex(ddc, &current_payload);
-
-               retrieved += payload_length;
-       } while (retrieved < payload->length && ret == true);
-
-       return ret;
-}
-
-bool link_query_ddc_data(
-       struct ddc_service *ddc,
-       uint32_t address,
-       uint8_t *write_buf,
-       uint32_t write_size,
-       uint8_t *read_buf,
-       uint32_t read_size)
-{
-       bool success = true;
-       uint32_t payload_size =
-               link_is_in_aux_transaction_mode(ddc) ?
-                       DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
-
-       uint32_t write_payloads =
-               (write_size + payload_size - 1) / payload_size;
-
-       uint32_t read_payloads =
-               (read_size + payload_size - 1) / payload_size;
-
-       uint32_t payloads_num = write_payloads + read_payloads;
-
-       if (!payloads_num)
-               return false;
-
-       if (link_is_in_aux_transaction_mode(ddc)) {
-               struct aux_payload payload;
-
-               payload.i2c_over_aux = true;
-               payload.address = address;
-               payload.reply = NULL;
-               payload.defer_delay = link_get_aux_defer_delay(ddc);
-               payload.write_status_update = false;
-
-               if (write_size != 0) {
-                       payload.write = true;
-                       /* should not set mot (middle of transaction) to 0
-                        * if there are pending read payloads
-                        */
-                       payload.mot = !(read_size == 0);
-                       payload.length = write_size;
-                       payload.data = write_buf;
-
-                       success = submit_aux_command(ddc, &payload);
-               }
-
-               if (read_size != 0 && success) {
-                       payload.write = false;
-                       /* should set mot (middle of transaction) to 0
-                        * since it is the last payload to send
-                        */
-                       payload.mot = false;
-                       payload.length = read_size;
-                       payload.data = read_buf;
-
-                       success = submit_aux_command(ddc, &payload);
-               }
-       } else {
-               struct i2c_command command = {0};
-               struct i2c_payloads payloads;
-
-               if (!dal_ddc_i2c_payloads_create(ddc->ctx, &payloads, payloads_num))
-                       return false;
-
-               command.payloads = dal_ddc_i2c_payloads_get(&payloads);
-               command.number_of_payloads = 0;
-               command.engine = DDC_I2C_COMMAND_ENGINE;
-               command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
-
-               i2c_payloads_add(
-                       &payloads, address, write_size, write_buf, true);
-
-               i2c_payloads_add(
-                       &payloads, address, read_size, read_buf, false);
-
-               command.number_of_payloads =
-                       dal_ddc_i2c_payloads_get_count(&payloads);
-
-               success = dm_helpers_submit_i2c(
-                               ddc->ctx,
-                               ddc->link,
-                               &command);
-
-               dal_vector_destruct(&payloads.payloads);
-       }
-
-       return success;
-}
-
-int dc_link_aux_transfer_raw(struct ddc_service *ddc,
-               struct aux_payload *payload,
-               enum aux_return_code_type *operation_result)
-{
-       if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc ||
-           !ddc->ddc_pin) {
-               return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
-       } else {
-               return dce_aux_transfer_raw(ddc, payload, operation_result);
-       }
-}
-
-bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc,
-               struct aux_payload *payload)
-{
-       return dce_aux_transfer_with_retries(ddc, payload);
-}
-
-
-bool try_to_configure_aux_timeout(struct ddc_service *ddc,
-               uint32_t timeout)
-{
-       bool result = false;
-       struct ddc *ddc_pin = ddc->ddc_pin;
-
-       if ((ddc->link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
-                       !ddc->link->dc->debug.disable_fixed_vs_aux_timeout_wa &&
-                       ASICREV_IS_YELLOW_CARP(ddc->ctx->asic_id.hw_internal_rev)) {
-               /* Fixed VS workaround for AUX timeout */
-               const uint32_t fixed_vs_address = 0xF004F;
-               const uint8_t fixed_vs_data[4] = {0x1, 0x22, 0x63, 0xc};
-
-               core_link_write_dpcd(ddc->link,
-                               fixed_vs_address,
-                               fixed_vs_data,
-                               sizeof(fixed_vs_data));
-
-               timeout = 3072;
-       }
-
-       /* Do not try to access nonexistent DDC pin. */
-       if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY)
-               return true;
-
-       if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) {
-               ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout);
-               result = true;
-       }
-
-       return result;
-}
-
-struct ddc *get_ddc_pin(struct ddc_service *ddc_service)
-{
-       return ddc_service->ddc_pin;
-}
-
-void write_scdc_data(struct ddc_service *ddc_service,
-               uint32_t pix_clk,
-               bool lte_340_scramble)
-{
-       bool over_340_mhz = pix_clk > 340000 ? 1 : 0;
-       uint8_t slave_address = HDMI_SCDC_ADDRESS;
-       uint8_t offset = HDMI_SCDC_SINK_VERSION;
-       uint8_t sink_version = 0;
-       uint8_t write_buffer[2] = {0};
-       /*Lower than 340 Scramble bit from SCDC caps*/
-
-       if (ddc_service->link->local_sink &&
-               ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
-               return;
-
-       link_query_ddc_data(ddc_service, slave_address, &offset,
-                       sizeof(offset), &sink_version, sizeof(sink_version));
-       if (sink_version == 1) {
-               /*Source Version = 1*/
-               write_buffer[0] = HDMI_SCDC_SOURCE_VERSION;
-               write_buffer[1] = 1;
-               link_query_ddc_data(ddc_service, slave_address,
-                               write_buffer, sizeof(write_buffer), NULL, 0);
-               /*Read Request from SCDC caps*/
-       }
-       write_buffer[0] = HDMI_SCDC_TMDS_CONFIG;
-
-       if (over_340_mhz) {
-               write_buffer[1] = 3;
-       } else if (lte_340_scramble) {
-               write_buffer[1] = 1;
-       } else {
-               write_buffer[1] = 0;
-       }
-       link_query_ddc_data(ddc_service, slave_address, write_buffer,
-                       sizeof(write_buffer), NULL, 0);
-}
-
-void read_scdc_data(struct ddc_service *ddc_service)
-{
-       uint8_t slave_address = HDMI_SCDC_ADDRESS;
-       uint8_t offset = HDMI_SCDC_TMDS_CONFIG;
-       uint8_t tmds_config = 0;
-
-       if (ddc_service->link->local_sink &&
-               ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
-               return;
-
-       link_query_ddc_data(ddc_service, slave_address, &offset,
-                       sizeof(offset), &tmds_config, sizeof(tmds_config));
-       if (tmds_config & 0x1) {
-               union hdmi_scdc_status_flags_data status_data = {0};
-               uint8_t scramble_status = 0;
-
-               offset = HDMI_SCDC_SCRAMBLER_STATUS;
-               link_query_ddc_data(ddc_service, slave_address,
-                               &offset, sizeof(offset), &scramble_status,
-                               sizeof(scramble_status));
-               offset = HDMI_SCDC_STATUS_FLAGS;
-               link_query_ddc_data(ddc_service, slave_address,
-                               &offset, sizeof(offset), &status_data.byte,
-                               sizeof(status_data.byte));
-       }
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_ddc.h b/drivers/gpu/drm/amd/display/dc/link/link_ddc.h
deleted file mode 100644 (file)
index 86e9d2e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-15 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 __DAL_DDC_SERVICE_H__
-#define __DAL_DDC_SERVICE_H__
-
-#include "link.h"
-
-#define AUX_POWER_UP_WA_DELAY 500
-#define I2C_OVER_AUX_DEFER_WA_DELAY 70
-#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40
-#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1
-#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
-
-#define EDID_SEGMENT_SIZE 256
-
-void set_ddc_transaction_type(
-               struct ddc_service *ddc,
-               enum ddc_transaction_type type);
-
-bool try_to_configure_aux_timeout(struct ddc_service *ddc,
-               uint32_t timeout);
-
-void write_scdc_data(
-               struct ddc_service *ddc_service,
-               uint32_t pix_clk,
-               bool lte_340_scramble);
-
-void read_scdc_data(
-               struct ddc_service *ddc_service);
-
-void set_dongle_type(struct ddc_service *ddc,
-               enum display_dongle_type dongle_type);
-
-struct ddc *get_ddc_pin(struct ddc_service *ddc_service);
-
-#endif /* __DAL_DDC_SERVICE_H__ */
-
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.c
deleted file mode 100644 (file)
index e72ad1b..0000000
+++ /dev/null
@@ -1,2169 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This file implements dp specific link capability retrieval sequence. It is
- * responsible for retrieving, parsing, overriding, deciding capability obtained
- * from dp link. Link capability consists of encoders, DPRXs, cables, retimers,
- * usb and all other possible backend capabilities. Other components should
- * include this header file in order to access link capability. Accessing link
- * capability by dereferencing dc_link outside dp_link_capability is not a
- * recommended method as it makes the component dependent on the underlying data
- * structure used to represent link capability instead of function interfaces.
- */
-
-#include "link_dp_capability.h"
-#include "link_ddc.h"
-#include "link_dpcd.h"
-#include "link_dp_dpia.h"
-#include "link_dp_phy.h"
-#include "link_dp_trace.h"
-#include "link_dp_training.h"
-#include "atomfirmware.h"
-#include "resource.h"
-#include "link_enc_cfg.h"
-#include "dc_link_dp.h"
-#include "dc_dmub_srv.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
-
-#ifndef MAX
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#endif
-#ifndef MIN
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-#endif
-
-#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
-
-struct dp_lt_fallback_entry {
-       enum dc_lane_count lane_count;
-       enum dc_link_rate link_rate;
-};
-
-static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = {
-               /* This link training fallback array is ordered by
-                * link bandwidth from highest to lowest.
-                * DP specs makes it a normative policy to always
-                * choose the next highest link bandwidth during
-                * link training fallback.
-                */
-               {LANE_COUNT_FOUR, LINK_RATE_UHBR20},
-               {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5},
-               {LANE_COUNT_TWO, LINK_RATE_UHBR20},
-               {LANE_COUNT_FOUR, LINK_RATE_UHBR10},
-               {LANE_COUNT_TWO, LINK_RATE_UHBR13_5},
-               {LANE_COUNT_FOUR, LINK_RATE_HIGH3},
-               {LANE_COUNT_ONE, LINK_RATE_UHBR20},
-               {LANE_COUNT_TWO, LINK_RATE_UHBR10},
-               {LANE_COUNT_FOUR, LINK_RATE_HIGH2},
-               {LANE_COUNT_ONE, LINK_RATE_UHBR13_5},
-               {LANE_COUNT_TWO, LINK_RATE_HIGH3},
-               {LANE_COUNT_ONE, LINK_RATE_UHBR10},
-               {LANE_COUNT_TWO, LINK_RATE_HIGH2},
-               {LANE_COUNT_FOUR, LINK_RATE_HIGH},
-               {LANE_COUNT_ONE, LINK_RATE_HIGH3},
-               {LANE_COUNT_FOUR, LINK_RATE_LOW},
-               {LANE_COUNT_ONE, LINK_RATE_HIGH2},
-               {LANE_COUNT_TWO, LINK_RATE_HIGH},
-               {LANE_COUNT_TWO, LINK_RATE_LOW},
-               {LANE_COUNT_ONE, LINK_RATE_HIGH},
-               {LANE_COUNT_ONE, LINK_RATE_LOW},
-};
-
-static const struct dc_link_settings fail_safe_link_settings = {
-               .lane_count = LANE_COUNT_ONE,
-               .link_rate = LINK_RATE_LOW,
-               .link_spread = LINK_SPREAD_DISABLED,
-};
-
-bool is_dp_active_dongle(const struct dc_link *link)
-{
-       return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) &&
-                               (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER);
-}
-
-bool is_dp_branch_device(const struct dc_link *link)
-{
-       return link->dpcd_caps.is_branch_dev;
-}
-
-static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc)
-{
-       switch (bpc) {
-       case DOWN_STREAM_MAX_8BPC:
-               return 8;
-       case DOWN_STREAM_MAX_10BPC:
-               return 10;
-       case DOWN_STREAM_MAX_12BPC:
-               return 12;
-       case DOWN_STREAM_MAX_16BPC:
-               return 16;
-       default:
-               break;
-       }
-
-       return -1;
-}
-
-uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count)
-{
-       switch (lttpr_repeater_count) {
-       case 0x80: // 1 lttpr repeater
-               return 1;
-       case 0x40: // 2 lttpr repeaters
-               return 2;
-       case 0x20: // 3 lttpr repeaters
-               return 3;
-       case 0x10: // 4 lttpr repeaters
-               return 4;
-       case 0x08: // 5 lttpr repeaters
-               return 5;
-       case 0x04: // 6 lttpr repeaters
-               return 6;
-       case 0x02: // 7 lttpr repeaters
-               return 7;
-       case 0x01: // 8 lttpr repeaters
-               return 8;
-       default:
-               break;
-       }
-       return 0; // invalid value
-}
-
-uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
-{
-       switch (bw) {
-       case 0b001:
-               return 9000000;
-       case 0b010:
-               return 18000000;
-       case 0b011:
-               return 24000000;
-       case 0b100:
-               return 32000000;
-       case 0b101:
-               return 40000000;
-       case 0b110:
-               return 48000000;
-       }
-
-       return 0;
-}
-
-static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
-{
-       enum dc_link_rate link_rate;
-       // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation.
-       switch (link_rate_in_khz) {
-       case 1620000:
-               link_rate = LINK_RATE_LOW;      // Rate_1 (RBR) - 1.62 Gbps/Lane
-               break;
-       case 2160000:
-               link_rate = LINK_RATE_RATE_2;   // Rate_2       - 2.16 Gbps/Lane
-               break;
-       case 2430000:
-               link_rate = LINK_RATE_RATE_3;   // Rate_3       - 2.43 Gbps/Lane
-               break;
-       case 2700000:
-               link_rate = LINK_RATE_HIGH;     // Rate_4 (HBR) - 2.70 Gbps/Lane
-               break;
-       case 3240000:
-               link_rate = LINK_RATE_RBR2;     // Rate_5 (RBR2)- 3.24 Gbps/Lane
-               break;
-       case 4320000:
-               link_rate = LINK_RATE_RATE_6;   // Rate_6       - 4.32 Gbps/Lane
-               break;
-       case 5400000:
-               link_rate = LINK_RATE_HIGH2;    // Rate_7 (HBR2)- 5.40 Gbps/Lane
-               break;
-       case 8100000:
-               link_rate = LINK_RATE_HIGH3;    // Rate_8 (HBR3)- 8.10 Gbps/Lane
-               break;
-       default:
-               link_rate = LINK_RATE_UNKNOWN;
-               break;
-       }
-       return link_rate;
-}
-
-static union dp_cable_id intersect_cable_id(
-               union dp_cable_id *a, union dp_cable_id *b)
-{
-       union dp_cable_id out;
-
-       out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,
-                       b->bits.UHBR10_20_CAPABILITY);
-       out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,
-                       b->bits.UHBR13_5_CAPABILITY);
-       out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE);
-
-       return out;
-}
-
-/*
- * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw.
- */
-static uint32_t intersect_frl_link_bw_support(
-       const uint32_t max_supported_frl_bw_in_kbps,
-       const union hdmi_encoded_link_bw hdmi_encoded_link_bw)
-{
-       uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
-
-       // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
-       if (hdmi_encoded_link_bw.bits.FRL_MODE) {
-               if (hdmi_encoded_link_bw.bits.BW_48Gbps)
-                       supported_bw_in_kbps = 48000000;
-               else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
-                       supported_bw_in_kbps = 40000000;
-               else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
-                       supported_bw_in_kbps = 32000000;
-               else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
-                       supported_bw_in_kbps = 24000000;
-               else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
-                       supported_bw_in_kbps = 18000000;
-               else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
-                       supported_bw_in_kbps = 9000000;
-       }
-
-       return supported_bw_in_kbps;
-}
-
-static enum clock_source_id get_clock_source_id(struct dc_link *link)
-{
-       enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
-       struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
-
-       if (dp_cs != NULL) {
-               dp_cs_id = dp_cs->id;
-       } else {
-               /*
-                * dp clock source is not initialized for some reason.
-                * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
-                */
-               ASSERT(dp_cs);
-       }
-
-       return dp_cs_id;
-}
-
-static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
-               int length)
-{
-       int retry = 0;
-       union dp_downstream_port_present ds_port = { 0 };
-
-       if (!link->dpcd_caps.dpcd_rev.raw) {
-               do {
-                       dc_link_dp_receiver_power_ctrl(link, true);
-                       core_link_read_dpcd(link, DP_DPCD_REV,
-                                                       dpcd_data, length);
-                       link->dpcd_caps.dpcd_rev.raw = dpcd_data[
-                               DP_DPCD_REV -
-                               DP_DPCD_REV];
-               } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw);
-       }
-
-       ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
-                                DP_DPCD_REV];
-
-       if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
-               switch (link->dpcd_caps.branch_dev_id) {
-               /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down
-                * all internal circuits including AUX communication preventing
-                * reading DPCD table and EDID (spec violation).
-                * Encoder will skip DP RX power down on disable_output to
-                * keep receiver powered all the time.*/
-               case DP_BRANCH_DEVICE_ID_0010FA:
-               case DP_BRANCH_DEVICE_ID_0080E1:
-               case DP_BRANCH_DEVICE_ID_00E04C:
-                       link->wa_flags.dp_keep_receiver_powered = true;
-                       break;
-
-               /* TODO: May need work around for other dongles. */
-               default:
-                       link->wa_flags.dp_keep_receiver_powered = false;
-                       break;
-               }
-       } else
-               link->wa_flags.dp_keep_receiver_powered = false;
-}
-
-bool dc_link_is_fec_supported(const struct dc_link *link)
-{
-       /* TODO - use asic cap instead of link_enc->features
-        * we no longer know which link enc to use for this link before commit
-        */
-       struct link_encoder *link_enc = NULL;
-
-       link_enc = link_enc_cfg_get_link_enc(link);
-       ASSERT(link_enc);
-
-       return (dc_is_dp_signal(link->connector_signal) && link_enc &&
-                       link_enc->features.fec_supported &&
-                       link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
-                       !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment));
-}
-
-bool dc_link_should_enable_fec(const struct dc_link *link)
-{
-       bool force_disable = false;
-
-       if (link->fec_state == dc_link_fec_enabled)
-               force_disable = false;
-       else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST &&
-                       link->local_sink &&
-                       link->local_sink->edid_caps.panel_patch.disable_fec)
-               force_disable = true;
-       else if (link->connector_signal == SIGNAL_TYPE_EDP
-                       && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.
-                        dsc_support.DSC_SUPPORT == false
-                               || link->panel_config.dsc.disable_dsc_edp
-                               || !link->dc->caps.edp_dsc_support))
-               force_disable = true;
-
-       return !force_disable && dc_link_is_fec_supported(link);
-}
-
-bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
-{
-       /* If this assert is hit then we have a link encoder dynamic management issue */
-       ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true);
-       return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
-                       pipe_ctx->link_res.hpo_dp_link_enc &&
-                       dc_is_dp_signal(pipe_ctx->stream->signal));
-}
-
-bool dp_is_lttpr_present(struct dc_link *link)
-{
-       return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
-                       link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
-                       link->dpcd_caps.lttpr_caps.max_lane_count <= 4 &&
-                       link->dpcd_caps.lttpr_caps.revision.raw >= 0x14);
-}
-
-/* in DP compliance test, DPR-120 may have
- * a random value in its MAX_LINK_BW dpcd field.
- * We map it to the maximum supported link rate that
- * is smaller than MAX_LINK_BW in this case.
- */
-static enum dc_link_rate get_link_rate_from_max_link_bw(
-                uint8_t max_link_bw)
-{
-       enum dc_link_rate link_rate;
-
-       if (max_link_bw >= LINK_RATE_HIGH3) {
-               link_rate = LINK_RATE_HIGH3;
-       } else if (max_link_bw < LINK_RATE_HIGH3
-                       && max_link_bw >= LINK_RATE_HIGH2) {
-               link_rate = LINK_RATE_HIGH2;
-       } else if (max_link_bw < LINK_RATE_HIGH2
-                       && max_link_bw >= LINK_RATE_HIGH) {
-               link_rate = LINK_RATE_HIGH;
-       } else if (max_link_bw < LINK_RATE_HIGH
-                       && max_link_bw >= LINK_RATE_LOW) {
-               link_rate = LINK_RATE_LOW;
-       } else {
-               link_rate = LINK_RATE_UNKNOWN;
-       }
-
-       return link_rate;
-}
-
-static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
-{
-       enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
-
-       if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20)
-               lttpr_max_link_rate = LINK_RATE_UHBR20;
-       else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5)
-               lttpr_max_link_rate = LINK_RATE_UHBR13_5;
-       else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10)
-               lttpr_max_link_rate = LINK_RATE_UHBR10;
-
-       return lttpr_max_link_rate;
-}
-
-static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link)
-{
-       enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN;
-
-       if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
-               cable_max_link_rate = LINK_RATE_UHBR20;
-       else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY)
-               cable_max_link_rate = LINK_RATE_UHBR13_5;
-       else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10)
-               cable_max_link_rate = LINK_RATE_UHBR10;
-
-       return cable_max_link_rate;
-}
-
-static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count)
-{
-       return lane_count <= LANE_COUNT_ONE;
-}
-
-static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate)
-{
-       return link_rate <= LINK_RATE_LOW;
-}
-
-static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
-{
-       switch (lane_count) {
-       case LANE_COUNT_FOUR:
-               return LANE_COUNT_TWO;
-       case LANE_COUNT_TWO:
-               return LANE_COUNT_ONE;
-       case LANE_COUNT_ONE:
-               return LANE_COUNT_UNKNOWN;
-       default:
-               return LANE_COUNT_UNKNOWN;
-       }
-}
-
-static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
-{
-       switch (link_rate) {
-       case LINK_RATE_UHBR20:
-               return LINK_RATE_UHBR13_5;
-       case LINK_RATE_UHBR13_5:
-               return LINK_RATE_UHBR10;
-       case LINK_RATE_UHBR10:
-               return LINK_RATE_HIGH3;
-       case LINK_RATE_HIGH3:
-               return LINK_RATE_HIGH2;
-       case LINK_RATE_HIGH2:
-               return LINK_RATE_HIGH;
-       case LINK_RATE_HIGH:
-               return LINK_RATE_LOW;
-       case LINK_RATE_LOW:
-               return LINK_RATE_UNKNOWN;
-       default:
-               return LINK_RATE_UNKNOWN;
-       }
-}
-
-static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count)
-{
-       switch (lane_count) {
-       case LANE_COUNT_ONE:
-               return LANE_COUNT_TWO;
-       case LANE_COUNT_TWO:
-               return LANE_COUNT_FOUR;
-       default:
-               return LANE_COUNT_UNKNOWN;
-       }
-}
-
-static enum dc_link_rate increase_link_rate(struct dc_link *link,
-               enum dc_link_rate link_rate)
-{
-       switch (link_rate) {
-       case LINK_RATE_LOW:
-               return LINK_RATE_HIGH;
-       case LINK_RATE_HIGH:
-               return LINK_RATE_HIGH2;
-       case LINK_RATE_HIGH2:
-               return LINK_RATE_HIGH3;
-       case LINK_RATE_HIGH3:
-               return LINK_RATE_UHBR10;
-       case LINK_RATE_UHBR10:
-               /* upto DP2.x specs UHBR13.5 is the only link rate that could be
-                * not supported by DPRX when higher link rate is supported.
-                * so we treat it as a special case for code simplicity. When we
-                * have new specs with more link rates like this, we should
-                * consider a more generic solution to handle discrete link
-                * rate capabilities.
-                */
-               return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ?
-                               LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20;
-       case LINK_RATE_UHBR13_5:
-               return LINK_RATE_UHBR20;
-       default:
-               return LINK_RATE_UNKNOWN;
-       }
-}
-
-static bool decide_fallback_link_setting_max_bw_policy(
-               struct dc_link *link,
-               const struct dc_link_settings *max,
-               struct dc_link_settings *cur,
-               enum link_training_result training_result)
-{
-       uint8_t cur_idx = 0, next_idx;
-       bool found = false;
-
-       if (training_result == LINK_TRAINING_ABORT)
-               return false;
-
-       while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks))
-               /* find current index */
-               if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count &&
-                               dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate)
-                       break;
-               else
-                       cur_idx++;
-
-       next_idx = cur_idx + 1;
-
-       while (next_idx < ARRAY_SIZE(dp_lt_fallbacks))
-               /* find next index */
-               if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count ||
-                               dp_lt_fallbacks[next_idx].link_rate > max->link_rate)
-                       next_idx++;
-               else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 &&
-                               link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0)
-                       /* upto DP2.x specs UHBR13.5 is the only link rate that
-                        * could be not supported by DPRX when higher link rate
-                        * is supported. so we treat it as a special case for
-                        * code simplicity. When we have new specs with more
-                        * link rates like this, we should consider a more
-                        * generic solution to handle discrete link rate
-                        * capabilities.
-                        */
-                       next_idx++;
-               else
-                       break;
-
-       if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) {
-               cur->lane_count = dp_lt_fallbacks[next_idx].lane_count;
-               cur->link_rate = dp_lt_fallbacks[next_idx].link_rate;
-               found = true;
-       }
-
-       return found;
-}
-
-/*
- * function: set link rate and lane count fallback based
- * on current link setting and last link training result
- * return value:
- *                     true - link setting could be set
- *                     false - has reached minimum setting
- *                                     and no further fallback could be done
- */
-bool decide_fallback_link_setting(
-               struct dc_link *link,
-               struct dc_link_settings *max,
-               struct dc_link_settings *cur,
-               enum link_training_result training_result)
-{
-       if (link_dp_get_encoding_format(max) == DP_128b_132b_ENCODING ||
-                       link->dc->debug.force_dp2_lt_fallback_method)
-               return decide_fallback_link_setting_max_bw_policy(link, max,
-                               cur, training_result);
-
-       switch (training_result) {
-       case LINK_TRAINING_CR_FAIL_LANE0:
-       case LINK_TRAINING_CR_FAIL_LANE1:
-       case LINK_TRAINING_CR_FAIL_LANE23:
-       case LINK_TRAINING_LQA_FAIL:
-       {
-               if (!reached_minimum_link_rate(cur->link_rate)) {
-                       cur->link_rate = reduce_link_rate(cur->link_rate);
-               } else if (!reached_minimum_lane_count(cur->lane_count)) {
-                       cur->link_rate = max->link_rate;
-                       if (training_result == LINK_TRAINING_CR_FAIL_LANE0)
-                               return false;
-                       else if (training_result == LINK_TRAINING_CR_FAIL_LANE1)
-                               cur->lane_count = LANE_COUNT_ONE;
-                       else if (training_result == LINK_TRAINING_CR_FAIL_LANE23)
-                               cur->lane_count = LANE_COUNT_TWO;
-                       else
-                               cur->lane_count = reduce_lane_count(cur->lane_count);
-               } else {
-                       return false;
-               }
-               break;
-       }
-       case LINK_TRAINING_EQ_FAIL_EQ:
-       case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
-       {
-               if (!reached_minimum_lane_count(cur->lane_count)) {
-                       cur->lane_count = reduce_lane_count(cur->lane_count);
-               } else if (!reached_minimum_link_rate(cur->link_rate)) {
-                       cur->link_rate = reduce_link_rate(cur->link_rate);
-                       /* Reduce max link rate to avoid potential infinite loop.
-                        * Needed so that any subsequent CR_FAIL fallback can't
-                        * re-set the link rate higher than the link rate from
-                        * the latest EQ_FAIL fallback.
-                        */
-                       max->link_rate = cur->link_rate;
-                       cur->lane_count = max->lane_count;
-               } else {
-                       return false;
-               }
-               break;
-       }
-       case LINK_TRAINING_EQ_FAIL_CR:
-       {
-               if (!reached_minimum_link_rate(cur->link_rate)) {
-                       cur->link_rate = reduce_link_rate(cur->link_rate);
-                       /* Reduce max link rate to avoid potential infinite loop.
-                        * Needed so that any subsequent CR_FAIL fallback can't
-                        * re-set the link rate higher than the link rate from
-                        * the latest EQ_FAIL fallback.
-                        */
-                       max->link_rate = cur->link_rate;
-                       cur->lane_count = max->lane_count;
-               } else {
-                       return false;
-               }
-               break;
-       }
-       default:
-               return false;
-       }
-       return true;
-}
-static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
-{
-       struct dc_link_settings initial_link_setting = {
-               LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0};
-       struct dc_link_settings current_link_setting =
-                       initial_link_setting;
-       uint32_t link_bw;
-
-       if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
-               return false;
-
-       /* search for the minimum link setting that:
-        * 1. is supported according to the link training result
-        * 2. could support the b/w requested by the timing
-        */
-       while (current_link_setting.link_rate <=
-                       link->verified_link_cap.link_rate) {
-               link_bw = dc_link_bandwidth_kbps(
-                               link,
-                               &current_link_setting);
-               if (req_bw <= link_bw) {
-                       *link_setting = current_link_setting;
-                       return true;
-               }
-
-               if (current_link_setting.lane_count <
-                               link->verified_link_cap.lane_count) {
-                       current_link_setting.lane_count =
-                                       increase_lane_count(
-                                                       current_link_setting.lane_count);
-               } else {
-                       current_link_setting.link_rate =
-                                       increase_link_rate(link,
-                                                       current_link_setting.link_rate);
-                       current_link_setting.lane_count =
-                                       initial_link_setting.lane_count;
-               }
-       }
-
-       return false;
-}
-
-bool dc_link_decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
-{
-       struct dc_link_settings initial_link_setting;
-       struct dc_link_settings current_link_setting;
-       uint32_t link_bw;
-
-       /*
-        * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
-        * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
-        */
-       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
-                       link->dpcd_caps.edp_supported_link_rates_count == 0) {
-               *link_setting = link->verified_link_cap;
-               return true;
-       }
-
-       memset(&initial_link_setting, 0, sizeof(initial_link_setting));
-       initial_link_setting.lane_count = LANE_COUNT_ONE;
-       initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
-       initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
-       initial_link_setting.use_link_rate_set = true;
-       initial_link_setting.link_rate_set = 0;
-       current_link_setting = initial_link_setting;
-
-       /* search for the minimum link setting that:
-        * 1. is supported according to the link training result
-        * 2. could support the b/w requested by the timing
-        */
-       while (current_link_setting.link_rate <=
-                       link->verified_link_cap.link_rate) {
-               link_bw = dc_link_bandwidth_kbps(
-                               link,
-                               &current_link_setting);
-               if (req_bw <= link_bw) {
-                       *link_setting = current_link_setting;
-                       return true;
-               }
-
-               if (current_link_setting.lane_count <
-                               link->verified_link_cap.lane_count) {
-                       current_link_setting.lane_count =
-                                       increase_lane_count(
-                                                       current_link_setting.lane_count);
-               } else {
-                       if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
-                               current_link_setting.link_rate_set++;
-                               current_link_setting.link_rate =
-                                       link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
-                               current_link_setting.lane_count =
-                                                                       initial_link_setting.lane_count;
-                       } else
-                               break;
-               }
-       }
-       return false;
-}
-
-bool decide_edp_link_settings_with_dsc(struct dc_link *link,
-               struct dc_link_settings *link_setting,
-               uint32_t req_bw,
-               enum dc_link_rate max_link_rate)
-{
-       struct dc_link_settings initial_link_setting;
-       struct dc_link_settings current_link_setting;
-       uint32_t link_bw;
-
-       unsigned int policy = 0;
-
-       policy = link->panel_config.dsc.force_dsc_edp_policy;
-       if (max_link_rate == LINK_RATE_UNKNOWN)
-               max_link_rate = link->verified_link_cap.link_rate;
-       /*
-        * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
-        * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
-        */
-       if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
-                       link->dpcd_caps.edp_supported_link_rates_count == 0)) {
-               /* for DSC enabled case, we search for minimum lane count */
-               memset(&initial_link_setting, 0, sizeof(initial_link_setting));
-               initial_link_setting.lane_count = LANE_COUNT_ONE;
-               initial_link_setting.link_rate = LINK_RATE_LOW;
-               initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
-               initial_link_setting.use_link_rate_set = false;
-               initial_link_setting.link_rate_set = 0;
-               current_link_setting = initial_link_setting;
-               if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
-                       return false;
-
-               /* search for the minimum link setting that:
-                * 1. is supported according to the link training result
-                * 2. could support the b/w requested by the timing
-                */
-               while (current_link_setting.link_rate <=
-                               max_link_rate) {
-                       link_bw = dc_link_bandwidth_kbps(
-                                       link,
-                                       &current_link_setting);
-                       if (req_bw <= link_bw) {
-                               *link_setting = current_link_setting;
-                               return true;
-                       }
-                       if (policy) {
-                               /* minimize lane */
-                               if (current_link_setting.link_rate < max_link_rate) {
-                                       current_link_setting.link_rate =
-                                                       increase_link_rate(link,
-                                                                       current_link_setting.link_rate);
-                               } else {
-                                       if (current_link_setting.lane_count <
-                                                                       link->verified_link_cap.lane_count) {
-                                               current_link_setting.lane_count =
-                                                               increase_lane_count(
-                                                                               current_link_setting.lane_count);
-                                               current_link_setting.link_rate = initial_link_setting.link_rate;
-                                       } else
-                                               break;
-                               }
-                       } else {
-                               /* minimize link rate */
-                               if (current_link_setting.lane_count <
-                                               link->verified_link_cap.lane_count) {
-                                       current_link_setting.lane_count =
-                                                       increase_lane_count(
-                                                                       current_link_setting.lane_count);
-                               } else {
-                                       current_link_setting.link_rate =
-                                                       increase_link_rate(link,
-                                                                       current_link_setting.link_rate);
-                                       current_link_setting.lane_count =
-                                                       initial_link_setting.lane_count;
-                               }
-                       }
-               }
-               return false;
-       }
-
-       /* if optimize edp link is supported */
-       memset(&initial_link_setting, 0, sizeof(initial_link_setting));
-       initial_link_setting.lane_count = LANE_COUNT_ONE;
-       initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
-       initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
-       initial_link_setting.use_link_rate_set = true;
-       initial_link_setting.link_rate_set = 0;
-       current_link_setting = initial_link_setting;
-
-       /* search for the minimum link setting that:
-        * 1. is supported according to the link training result
-        * 2. could support the b/w requested by the timing
-        */
-       while (current_link_setting.link_rate <=
-                       max_link_rate) {
-               link_bw = dc_link_bandwidth_kbps(
-                               link,
-                               &current_link_setting);
-               if (req_bw <= link_bw) {
-                       *link_setting = current_link_setting;
-                       return true;
-               }
-               if (policy) {
-                       /* minimize lane */
-                       if (current_link_setting.link_rate_set <
-                                       link->dpcd_caps.edp_supported_link_rates_count
-                                       && current_link_setting.link_rate < max_link_rate) {
-                               current_link_setting.link_rate_set++;
-                               current_link_setting.link_rate =
-                                       link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
-                       } else {
-                               if (current_link_setting.lane_count < link->verified_link_cap.lane_count) {
-                                       current_link_setting.lane_count =
-                                                       increase_lane_count(
-                                                                       current_link_setting.lane_count);
-                                       current_link_setting.link_rate_set = initial_link_setting.link_rate_set;
-                                       current_link_setting.link_rate =
-                                               link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
-                               } else
-                                       break;
-                       }
-               } else {
-                       /* minimize link rate */
-                       if (current_link_setting.lane_count <
-                                       link->verified_link_cap.lane_count) {
-                               current_link_setting.lane_count =
-                                               increase_lane_count(
-                                                               current_link_setting.lane_count);
-                       } else {
-                               if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
-                                       current_link_setting.link_rate_set++;
-                                       current_link_setting.link_rate =
-                                               link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
-                                       current_link_setting.lane_count =
-                                               initial_link_setting.lane_count;
-                               } else
-                                       break;
-                       }
-               }
-       }
-       return false;
-}
-
-static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting)
-{
-       *link_setting = link->verified_link_cap;
-       return true;
-}
-
-bool link_decide_link_settings(struct dc_stream_state *stream,
-       struct dc_link_settings *link_setting)
-{
-       struct dc_link *link = stream->link;
-       uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
-
-       memset(link_setting, 0, sizeof(*link_setting));
-
-       /* if preferred is specified through AMDDP, use it, if it's enough
-        * to drive the mode
-        */
-       if (link->preferred_link_setting.lane_count !=
-                       LANE_COUNT_UNKNOWN &&
-                       link->preferred_link_setting.link_rate !=
-                                       LINK_RATE_UNKNOWN) {
-               *link_setting = link->preferred_link_setting;
-               return true;
-       }
-
-       /* MST doesn't perform link training for now
-        * TODO: add MST specific link training routine
-        */
-       if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
-               decide_mst_link_settings(link, link_setting);
-       } else if (link->connector_signal == SIGNAL_TYPE_EDP) {
-               /* enable edp link optimization for DSC eDP case */
-               if (stream->timing.flags.DSC) {
-                       enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN;
-
-                       if (link->panel_config.dsc.force_dsc_edp_policy) {
-                               /* calculate link max link rate cap*/
-                               struct dc_link_settings tmp_link_setting;
-                               struct dc_crtc_timing tmp_timing = stream->timing;
-                               uint32_t orig_req_bw;
-
-                               tmp_link_setting.link_rate = LINK_RATE_UNKNOWN;
-                               tmp_timing.flags.DSC = 0;
-                               orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing);
-                               dc_link_decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw);
-                               max_link_rate = tmp_link_setting.link_rate;
-                       }
-                       decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate);
-               } else {
-                       dc_link_decide_edp_link_settings(link, link_setting, req_bw);
-               }
-       } else {
-               decide_dp_link_settings(link, link_setting, req_bw);
-       }
-
-       return link_setting->lane_count != LANE_COUNT_UNKNOWN &&
-                       link_setting->link_rate != LINK_RATE_UNKNOWN;
-}
-
-enum dp_link_encoding link_dp_get_encoding_format(const struct dc_link_settings *link_settings)
-{
-       if ((link_settings->link_rate >= LINK_RATE_LOW) &&
-                       (link_settings->link_rate <= LINK_RATE_HIGH3))
-               return DP_8b_10b_ENCODING;
-       else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
-                       (link_settings->link_rate <= LINK_RATE_UHBR20))
-               return DP_128b_132b_ENCODING;
-       return DP_UNKNOWN_ENCODING;
-}
-
-enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link)
-{
-       struct dc_link_settings link_settings = {0};
-
-       if (!dc_is_dp_signal(link->connector_signal))
-               return DP_UNKNOWN_ENCODING;
-
-       if (link->preferred_link_setting.lane_count !=
-                       LANE_COUNT_UNKNOWN &&
-                       link->preferred_link_setting.link_rate !=
-                                       LINK_RATE_UNKNOWN) {
-               link_settings = link->preferred_link_setting;
-       } else {
-               decide_mst_link_settings(link, &link_settings);
-       }
-
-       return link_dp_get_encoding_format(&link_settings);
-}
-
-static void read_dp_device_vendor_id(struct dc_link *link)
-{
-       struct dp_device_vendor_id dp_id;
-
-       /* read IEEE branch device id */
-       core_link_read_dpcd(
-               link,
-               DP_BRANCH_OUI,
-               (uint8_t *)&dp_id,
-               sizeof(dp_id));
-
-       link->dpcd_caps.branch_dev_id =
-               (dp_id.ieee_oui[0] << 16) +
-               (dp_id.ieee_oui[1] << 8) +
-               dp_id.ieee_oui[2];
-
-       memmove(
-               link->dpcd_caps.branch_dev_name,
-               dp_id.ieee_device_id,
-               sizeof(dp_id.ieee_device_id));
-}
-
-static enum dc_status wake_up_aux_channel(struct dc_link *link)
-{
-       enum dc_status status = DC_ERROR_UNEXPECTED;
-       uint32_t aux_channel_retry_cnt = 0;
-       uint8_t dpcd_power_state = '\0';
-
-       while (status != DC_OK && aux_channel_retry_cnt < 10) {
-               status = core_link_read_dpcd(link, DP_SET_POWER,
-                               &dpcd_power_state, sizeof(dpcd_power_state));
-
-               /* Delay 1 ms if AUX CH is in power down state. Based on spec
-                * section 2.3.1.2, if AUX CH may be powered down due to
-                * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
-                * signal and may need up to 1 ms before being able to reply.
-                */
-               if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
-                       udelay(1000);
-                       aux_channel_retry_cnt++;
-               }
-       }
-
-       if (status != DC_OK) {
-               dpcd_power_state = DP_SET_POWER_D0;
-               status = core_link_write_dpcd(
-                               link,
-                               DP_SET_POWER,
-                               &dpcd_power_state,
-                               sizeof(dpcd_power_state));
-
-               dpcd_power_state = DP_SET_POWER_D3;
-               status = core_link_write_dpcd(
-                               link,
-                               DP_SET_POWER,
-                               &dpcd_power_state,
-                               sizeof(dpcd_power_state));
-               return DC_ERROR_UNEXPECTED;
-       }
-
-       return DC_OK;
-}
-
-static void get_active_converter_info(
-       uint8_t data, struct dc_link *link)
-{
-       union dp_downstream_port_present ds_port = { .byte = data };
-       memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
-
-       /* decode converter info*/
-       if (!ds_port.fields.PORT_PRESENT) {
-               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
-               set_dongle_type(link->ddc,
-                               link->dpcd_caps.dongle_type);
-               link->dpcd_caps.is_branch_dev = false;
-               return;
-       }
-
-       /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */
-       link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT;
-
-       switch (ds_port.fields.PORT_TYPE) {
-       case DOWNSTREAM_VGA:
-               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
-               break;
-       case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS:
-               /* At this point we don't know is it DVI or HDMI or DP++,
-                * assume DVI.*/
-               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
-               break;
-       default:
-               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
-               break;
-       }
-
-       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) {
-               uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/
-               union dwnstream_port_caps_byte0 *port_caps =
-                       (union dwnstream_port_caps_byte0 *)det_caps;
-               if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0,
-                               det_caps, sizeof(det_caps)) == DC_OK) {
-
-                       switch (port_caps->bits.DWN_STRM_PORTX_TYPE) {
-                       /*Handle DP case as DONGLE_NONE*/
-                       case DOWN_STREAM_DETAILED_DP:
-                               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
-                               break;
-                       case DOWN_STREAM_DETAILED_VGA:
-                               link->dpcd_caps.dongle_type =
-                                       DISPLAY_DONGLE_DP_VGA_CONVERTER;
-                               break;
-                       case DOWN_STREAM_DETAILED_DVI:
-                               link->dpcd_caps.dongle_type =
-                                       DISPLAY_DONGLE_DP_DVI_CONVERTER;
-                               break;
-                       case DOWN_STREAM_DETAILED_HDMI:
-                       case DOWN_STREAM_DETAILED_DP_PLUS_PLUS:
-                               /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/
-                               link->dpcd_caps.dongle_type =
-                                       DISPLAY_DONGLE_DP_HDMI_CONVERTER;
-
-                               link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type;
-                               if (ds_port.fields.DETAILED_CAPS) {
-
-                                       union dwnstream_port_caps_byte3_hdmi
-                                               hdmi_caps = {.raw = det_caps[3] };
-                                       union dwnstream_port_caps_byte2
-                                               hdmi_color_caps = {.raw = det_caps[2] };
-                                       link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz =
-                                               det_caps[1] * 2500;
-
-                                       link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter =
-                                               hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK;
-                                       /*YCBCR capability only for HDMI case*/
-                                       if (port_caps->bits.DWN_STRM_PORTX_TYPE
-                                                       == DOWN_STREAM_DETAILED_HDMI) {
-                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through =
-                                                               hdmi_caps.bits.YCrCr422_PASS_THROUGH;
-                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through =
-                                                               hdmi_caps.bits.YCrCr420_PASS_THROUGH;
-                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter =
-                                                               hdmi_caps.bits.YCrCr422_CONVERSION;
-                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter =
-                                                               hdmi_caps.bits.YCrCr420_CONVERSION;
-                                       }
-
-                                       link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc =
-                                               translate_dpcd_max_bpc(
-                                                       hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
-
-                                       if (link->dc->caps.dp_hdmi21_pcon_support) {
-                                               union hdmi_encoded_link_bw hdmi_encoded_link_bw;
-
-                                               link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps =
-                                                               dc_link_bw_kbps_from_raw_frl_link_rate_data(
-                                                                               hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT);
-
-                                               // Intersect reported max link bw support with the supported link rate post FRL link training
-                                               if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS,
-                                                               &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) {
-                                                       link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support(
-                                                                       link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps,
-                                                                       hdmi_encoded_link_bw);
-                                               }
-
-                                               if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0)
-                                                       link->dpcd_caps.dongle_caps.extendedCapValid = true;
-                                       }
-
-                                       if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0)
-                                               link->dpcd_caps.dongle_caps.extendedCapValid = true;
-                               }
-
-                               break;
-                       }
-               }
-       }
-
-       set_dongle_type(link->ddc, link->dpcd_caps.dongle_type);
-
-       {
-               struct dp_sink_hw_fw_revision dp_hw_fw_revision;
-
-               core_link_read_dpcd(
-                       link,
-                       DP_BRANCH_REVISION_START,
-                       (uint8_t *)&dp_hw_fw_revision,
-                       sizeof(dp_hw_fw_revision));
-
-               link->dpcd_caps.branch_hw_revision =
-                       dp_hw_fw_revision.ieee_hw_rev;
-
-               memmove(
-                       link->dpcd_caps.branch_fw_revision,
-                       dp_hw_fw_revision.ieee_fw_rev,
-                       sizeof(dp_hw_fw_revision.ieee_fw_rev));
-       }
-       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
-                       link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
-               union dp_dfp_cap_ext dfp_cap_ext;
-               memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext));
-               core_link_read_dpcd(
-                               link,
-                               DP_DFP_CAPABILITY_EXTENSION_SUPPORT,
-                               dfp_cap_ext.raw,
-                               sizeof(dfp_cap_ext.raw));
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported;
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps =
-                               dfp_cap_ext.fields.max_pixel_rate_in_mps[0] +
-                               (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8);
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width =
-                               dfp_cap_ext.fields.max_video_h_active_width[0] +
-                               (dfp_cap_ext.fields.max_video_h_active_width[1] << 8);
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height =
-                               dfp_cap_ext.fields.max_video_v_active_height[0] +
-                               (dfp_cap_ext.fields.max_video_v_active_height[1] << 8);
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps =
-                               dfp_cap_ext.fields.encoding_format_caps;
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps =
-                               dfp_cap_ext.fields.rgb_color_depth_caps;
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps =
-                               dfp_cap_ext.fields.ycbcr444_color_depth_caps;
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps =
-                               dfp_cap_ext.fields.ycbcr422_color_depth_caps;
-               link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps =
-                               dfp_cap_ext.fields.ycbcr420_color_depth_caps;
-               DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index);
-               DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false");
-               DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps);
-               DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width);
-               DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height);
-       }
-}
-
-static void apply_usbc_combo_phy_reset_wa(struct dc_link *link,
-               struct dc_link_settings *link_settings)
-{
-       /* Temporary Renoir-specific workaround PHY will sometimes be in bad
-        * state on hotplugging display from certain USB-C dongle, so add extra
-        * cycle of enabling and disabling the PHY before first link training.
-        */
-       struct link_resource link_res = {0};
-       enum clock_source_id dp_cs_id = get_clock_source_id(link);
-
-       dp_enable_link_phy(link, &link_res, link->connector_signal,
-                       dp_cs_id, link_settings);
-       dp_disable_link_phy(link, &link_res, link->connector_signal);
-}
-
-static bool dp_overwrite_extended_receiver_cap(struct dc_link *link)
-{
-       uint8_t dpcd_data[16];
-       uint32_t read_dpcd_retry_cnt = 3;
-       enum dc_status status = DC_ERROR_UNEXPECTED;
-       union dp_downstream_port_present ds_port = { 0 };
-       union down_stream_port_count down_strm_port_count;
-       union edp_configuration_cap edp_config_cap;
-
-       int i;
-
-       for (i = 0; i < read_dpcd_retry_cnt; i++) {
-               status = core_link_read_dpcd(
-                               link,
-                               DP_DPCD_REV,
-                               dpcd_data,
-                               sizeof(dpcd_data));
-               if (status == DC_OK)
-                       break;
-       }
-
-       link->dpcd_caps.dpcd_rev.raw =
-               dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
-
-       if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
-               return false;
-
-       ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
-                       DP_DPCD_REV];
-
-       get_active_converter_info(ds_port.byte, link);
-
-       down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
-                       DP_DPCD_REV];
-
-       link->dpcd_caps.allow_invalid_MSA_timing_param =
-               down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
-
-       link->dpcd_caps.max_ln_count.raw = dpcd_data[
-               DP_MAX_LANE_COUNT - DP_DPCD_REV];
-
-       link->dpcd_caps.max_down_spread.raw = dpcd_data[
-               DP_MAX_DOWNSPREAD - DP_DPCD_REV];
-
-       link->reported_link_cap.lane_count =
-               link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
-       link->reported_link_cap.link_rate = dpcd_data[
-               DP_MAX_LINK_RATE - DP_DPCD_REV];
-       link->reported_link_cap.link_spread =
-               link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
-               LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
-
-       edp_config_cap.raw = dpcd_data[
-               DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
-       link->dpcd_caps.panel_mode_edp =
-               edp_config_cap.bits.ALT_SCRAMBLER_RESET;
-       link->dpcd_caps.dpcd_display_control_capable =
-               edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
-
-       return true;
-}
-
-void dc_link_overwrite_extended_receiver_cap(
-               struct dc_link *link)
-{
-       dp_overwrite_extended_receiver_cap(link);
-}
-
-void dpcd_set_source_specific_data(struct dc_link *link)
-{
-       if (!link->dc->vendor_signature.is_valid) {
-               enum dc_status result_write_min_hblank = DC_NOT_SUPPORTED;
-               struct dpcd_amd_signature amd_signature = {0};
-               struct dpcd_amd_device_id amd_device_id = {0};
-
-               amd_device_id.device_id_byte1 =
-                               (uint8_t)(link->ctx->asic_id.chip_id);
-               amd_device_id.device_id_byte2 =
-                               (uint8_t)(link->ctx->asic_id.chip_id >> 8);
-               amd_device_id.dce_version =
-                               (uint8_t)(link->ctx->dce_version);
-               amd_device_id.dal_version_byte1 = 0x0; // needed? where to get?
-               amd_device_id.dal_version_byte2 = 0x0; // needed? where to get?
-
-               core_link_read_dpcd(link, DP_SOURCE_OUI,
-                               (uint8_t *)(&amd_signature),
-                               sizeof(amd_signature));
-
-               if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) &&
-                       (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) &&
-                       (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) {
-
-                       amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0;
-                       amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0;
-                       amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A;
-
-                       core_link_write_dpcd(link, DP_SOURCE_OUI,
-                               (uint8_t *)(&amd_signature),
-                               sizeof(amd_signature));
-               }
-
-               core_link_write_dpcd(link, DP_SOURCE_OUI+0x03,
-                               (uint8_t *)(&amd_device_id),
-                               sizeof(amd_device_id));
-
-               if (link->ctx->dce_version >= DCN_VERSION_2_0 &&
-                       link->dc->caps.min_horizontal_blanking_period != 0) {
-
-                       uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period;
-
-                       result_write_min_hblank = core_link_write_dpcd(link,
-                               DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size),
-                               sizeof(hblank_size));
-               }
-               DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
-                                                       WPP_BIT_FLAG_DC_DETECTION_DP_CAPS,
-                                                       "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'",
-                                                       result_write_min_hblank,
-                                                       link->link_index,
-                                                       link->ctx->dce_version,
-                                                       DP_SOURCE_MINIMUM_HBLANK_SUPPORTED,
-                                                       link->dc->caps.min_horizontal_blanking_period,
-                                                       link->dpcd_caps.branch_dev_id,
-                                                       link->dpcd_caps.branch_dev_name[0],
-                                                       link->dpcd_caps.branch_dev_name[1],
-                                                       link->dpcd_caps.branch_dev_name[2],
-                                                       link->dpcd_caps.branch_dev_name[3],
-                                                       link->dpcd_caps.branch_dev_name[4],
-                                                       link->dpcd_caps.branch_dev_name[5]);
-       } else {
-               core_link_write_dpcd(link, DP_SOURCE_OUI,
-                               link->dc->vendor_signature.data.raw,
-                               sizeof(link->dc->vendor_signature.data.raw));
-       }
-}
-
-void dpcd_write_cable_id_to_dprx(struct dc_link *link)
-{
-       if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED ||
-                       link->dpcd_caps.cable_id.raw == 0 ||
-                       link->dprx_states.cable_id_written)
-               return;
-
-       core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX,
-                       &link->dpcd_caps.cable_id.raw,
-                       sizeof(link->dpcd_caps.cable_id.raw));
-
-       link->dprx_states.cable_id_written = 1;
-}
-
-static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id)
-{
-       union dmub_rb_cmd cmd;
-
-       if (!link->ctx->dmub_srv ||
-                       link->ep_type != DISPLAY_ENDPOINT_PHY ||
-                       link->link_enc->features.flags.bits.DP_IS_USB_C == 0)
-               return false;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID;
-       cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data);
-       cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx(
-                       link->dc, link->link_enc->transmitter);
-       if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) &&
-                       cmd.cable_id.header.ret_status == 1) {
-               cable_id->raw = cmd.cable_id.data.output_raw;
-               DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw);
-       }
-       return cmd.cable_id.header.ret_status == 1;
-}
-
-static void retrieve_cable_id(struct dc_link *link)
-{
-       union dp_cable_id usbc_cable_id;
-
-       link->dpcd_caps.cable_id.raw = 0;
-       core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
-                       &link->dpcd_caps.cable_id.raw, sizeof(uint8_t));
-
-       if (get_usbc_cable_id(link, &usbc_cable_id))
-               link->dpcd_caps.cable_id = intersect_cable_id(
-                               &link->dpcd_caps.cable_id, &usbc_cable_id);
-}
-
-bool read_is_mst_supported(struct dc_link *link)
-{
-       bool mst          = false;
-       enum dc_status st = DC_OK;
-       union dpcd_rev rev;
-       union mstm_cap cap;
-
-       if (link->preferred_training_settings.mst_enable &&
-               *link->preferred_training_settings.mst_enable == false) {
-               return false;
-       }
-
-       rev.raw  = 0;
-       cap.raw  = 0;
-
-       st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw,
-                       sizeof(rev));
-
-       if (st == DC_OK && rev.raw >= DPCD_REV_12) {
-
-               st = core_link_read_dpcd(link, DP_MSTM_CAP,
-                               &cap.raw, sizeof(cap));
-               if (st == DC_OK && cap.bits.MST_CAP == 1)
-                       mst = true;
-       }
-       return mst;
-
-}
-
-/* Read additional sink caps defined in source specific DPCD area
- * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP)
- * TODO: Add FS caps and read from DP_SOURCE_SINK_FS_CAP as well
- */
-static bool dpcd_read_sink_ext_caps(struct dc_link *link)
-{
-       uint8_t dpcd_data;
-
-       if (!link)
-               return false;
-
-       if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK)
-               return false;
-
-       link->dpcd_sink_ext_caps.raw = dpcd_data;
-       return true;
-}
-
-enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
-{
-       uint8_t lttpr_dpcd_data[8];
-       enum dc_status status;
-       bool is_lttpr_present;
-
-       /* Logic to determine LTTPR support*/
-       bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
-
-       if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support)
-               return DC_ERROR_UNEXPECTED;
-
-       /* By reading LTTPR capability, RX assumes that we will enable
-        * LTTPR extended aux timeout if LTTPR is present.
-        */
-       status = core_link_read_dpcd(
-                       link,
-                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
-                       lttpr_dpcd_data,
-                       sizeof(lttpr_dpcd_data));
-
-       link->dpcd_caps.lttpr_caps.revision.raw =
-                       lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       link->dpcd_caps.lttpr_caps.max_link_rate =
-                       lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       link->dpcd_caps.lttpr_caps.phy_repeater_cnt =
-                       lttpr_dpcd_data[DP_PHY_REPEATER_CNT -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       link->dpcd_caps.lttpr_caps.max_lane_count =
-                       lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       link->dpcd_caps.lttpr_caps.mode =
-                       lttpr_dpcd_data[DP_PHY_REPEATER_MODE -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       link->dpcd_caps.lttpr_caps.max_ext_timeout =
-                       lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-       link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw =
-                       lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw =
-                       lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES -
-                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-       /* If this chip cap is set, at least one retimer must exist in the chain
-        * Override count to 1 if we receive a known bad count (0 or an invalid value) */
-       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
-                       (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) {
-               ASSERT(0);
-               link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80;
-               DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-       }
-
-       /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
-       is_lttpr_present = dp_is_lttpr_present(link);
-
-       if (is_lttpr_present)
-               CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
-
-       DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present);
-       return status;
-}
-
-static bool retrieve_link_cap(struct dc_link *link)
-{
-       /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
-        * which means size 16 will be good for both of those DPCD register block reads
-        */
-       uint8_t dpcd_data[16];
-       /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
-        */
-       uint8_t dpcd_dprx_data = '\0';
-
-       struct dp_device_vendor_id sink_id;
-       union down_stream_port_count down_strm_port_count;
-       union edp_configuration_cap edp_config_cap;
-       union dp_downstream_port_present ds_port = { 0 };
-       enum dc_status status = DC_ERROR_UNEXPECTED;
-       uint32_t read_dpcd_retry_cnt = 3;
-       int i;
-       struct dp_sink_hw_fw_revision dp_hw_fw_revision;
-       const uint32_t post_oui_delay = 30; // 30ms
-
-       memset(dpcd_data, '\0', sizeof(dpcd_data));
-       memset(&down_strm_port_count,
-               '\0', sizeof(union down_stream_port_count));
-       memset(&edp_config_cap, '\0',
-               sizeof(union edp_configuration_cap));
-
-       /* if extended timeout is supported in hardware,
-        * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer
-        * CTS 4.2.1.1 regression introduced by CTS specs requirement update.
-        */
-       try_to_configure_aux_timeout(link->ddc,
-                       LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
-
-       status = dp_retrieve_lttpr_cap(link);
-
-       if (status != DC_OK) {
-               status = wake_up_aux_channel(link);
-               if (status == DC_OK)
-                       dp_retrieve_lttpr_cap(link);
-               else
-                       return false;
-       }
-
-       if (dp_is_lttpr_present(link))
-               configure_lttpr_mode_transparent(link);
-
-       /* Read DP tunneling information. */
-       status = dpcd_get_tunneling_device_data(link);
-
-       dpcd_set_source_specific_data(link);
-       /* Sink may need to configure internals based on vendor, so allow some
-        * time before proceeding with possibly vendor specific transactions
-        */
-       msleep(post_oui_delay);
-
-       for (i = 0; i < read_dpcd_retry_cnt; i++) {
-               status = core_link_read_dpcd(
-                               link,
-                               DP_DPCD_REV,
-                               dpcd_data,
-                               sizeof(dpcd_data));
-               if (status == DC_OK)
-                       break;
-       }
-
-
-       if (status != DC_OK) {
-               dm_error("%s: Read receiver caps dpcd data failed.\n", __func__);
-               return false;
-       }
-
-       if (!dp_is_lttpr_present(link))
-               try_to_configure_aux_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
-
-
-       {
-               union training_aux_rd_interval aux_rd_interval;
-
-               aux_rd_interval.raw =
-                       dpcd_data[DP_TRAINING_AUX_RD_INTERVAL];
-
-               link->dpcd_caps.ext_receiver_cap_field_present =
-                               aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1 ? true:false;
-
-               if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) {
-                       uint8_t ext_cap_data[16];
-
-                       memset(ext_cap_data, '\0', sizeof(ext_cap_data));
-                       for (i = 0; i < read_dpcd_retry_cnt; i++) {
-                               status = core_link_read_dpcd(
-                               link,
-                               DP_DP13_DPCD_REV,
-                               ext_cap_data,
-                               sizeof(ext_cap_data));
-                               if (status == DC_OK) {
-                                       memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data));
-                                       break;
-                               }
-                       }
-                       if (status != DC_OK)
-                               dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__);
-               }
-       }
-
-       link->dpcd_caps.dpcd_rev.raw =
-                       dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
-
-       if (link->dpcd_caps.ext_receiver_cap_field_present) {
-               for (i = 0; i < read_dpcd_retry_cnt; i++) {
-                       status = core_link_read_dpcd(
-                                       link,
-                                       DP_DPRX_FEATURE_ENUMERATION_LIST,
-                                       &dpcd_dprx_data,
-                                       sizeof(dpcd_dprx_data));
-                       if (status == DC_OK)
-                               break;
-               }
-
-               link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data;
-
-               if (status != DC_OK)
-                       dm_error("%s: Read DPRX caps data failed.\n", __func__);
-       }
-
-       else {
-               link->dpcd_caps.dprx_feature.raw = 0;
-       }
-
-
-       /* Error condition checking...
-        * It is impossible for Sink to report Max Lane Count = 0.
-        * It is possible for Sink to report Max Link Rate = 0, if it is
-        * an eDP device that is reporting specialized link rates in the
-        * SUPPORTED_LINK_RATE table.
-        */
-       if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
-               return false;
-
-       ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
-                                DP_DPCD_REV];
-
-       read_dp_device_vendor_id(link);
-
-       /* TODO - decouple raw mst capability from policy decision */
-       link->dpcd_caps.is_mst_capable = read_is_mst_supported(link);
-
-       get_active_converter_info(ds_port.byte, link);
-
-       dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
-
-       down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
-                                DP_DPCD_REV];
-
-       link->dpcd_caps.allow_invalid_MSA_timing_param =
-               down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
-
-       link->dpcd_caps.max_ln_count.raw = dpcd_data[
-               DP_MAX_LANE_COUNT - DP_DPCD_REV];
-
-       link->dpcd_caps.max_down_spread.raw = dpcd_data[
-               DP_MAX_DOWNSPREAD - DP_DPCD_REV];
-
-       link->reported_link_cap.lane_count =
-               link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
-       link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw(
-                       dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]);
-       link->reported_link_cap.link_spread =
-               link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
-               LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
-
-       edp_config_cap.raw = dpcd_data[
-               DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
-       link->dpcd_caps.panel_mode_edp =
-               edp_config_cap.bits.ALT_SCRAMBLER_RESET;
-       link->dpcd_caps.dpcd_display_control_capable =
-               edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
-       link->dpcd_caps.channel_coding_cap.raw =
-                       dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV];
-       link->test_pattern_enabled = false;
-       link->compliance_test_state.raw = 0;
-
-       /* read sink count */
-       core_link_read_dpcd(link,
-                       DP_SINK_COUNT,
-                       &link->dpcd_caps.sink_count.raw,
-                       sizeof(link->dpcd_caps.sink_count.raw));
-
-       /* read sink ieee oui */
-       core_link_read_dpcd(link,
-                       DP_SINK_OUI,
-                       (uint8_t *)(&sink_id),
-                       sizeof(sink_id));
-
-       link->dpcd_caps.sink_dev_id =
-                       (sink_id.ieee_oui[0] << 16) +
-                       (sink_id.ieee_oui[1] << 8) +
-                       (sink_id.ieee_oui[2]);
-
-       memmove(
-               link->dpcd_caps.sink_dev_id_str,
-               sink_id.ieee_device_id,
-               sizeof(sink_id.ieee_device_id));
-
-       core_link_read_dpcd(
-               link,
-               DP_SINK_HW_REVISION_START,
-               (uint8_t *)&dp_hw_fw_revision,
-               sizeof(dp_hw_fw_revision));
-
-       link->dpcd_caps.sink_hw_revision =
-               dp_hw_fw_revision.ieee_hw_rev;
-
-       memmove(
-               link->dpcd_caps.sink_fw_revision,
-               dp_hw_fw_revision.ieee_fw_rev,
-               sizeof(dp_hw_fw_revision.ieee_fw_rev));
-
-       /* Quirk for Retina panels: wrong DP_MAX_LINK_RATE */
-       {
-               uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
-               uint8_t fwrev_mbp_2018[] = { 7, 4 };
-               uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
-
-               /* We also check for the firmware revision as 16,1 models have an
-                * identical device id and are incorrectly quirked otherwise.
-                */
-               if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
-                   !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
-                            sizeof(str_mbp_2018)) &&
-                   (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
-                            sizeof(fwrev_mbp_2018)) ||
-                   !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
-                            sizeof(fwrev_mbp_2018_vega)))) {
-                       link->reported_link_cap.link_rate = LINK_RATE_RBR2;
-               }
-       }
-
-       memset(&link->dpcd_caps.dsc_caps, '\0',
-                       sizeof(link->dpcd_caps.dsc_caps));
-       memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
-       /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
-       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
-               status = core_link_read_dpcd(
-                               link,
-                               DP_FEC_CAPABILITY,
-                               &link->dpcd_caps.fec_cap.raw,
-                               sizeof(link->dpcd_caps.fec_cap.raw));
-               status = core_link_read_dpcd(
-                               link,
-                               DP_DSC_SUPPORT,
-                               link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
-                               sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
-               if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
-                       status = core_link_read_dpcd(
-                                       link,
-                                       DP_DSC_BRANCH_OVERALL_THROUGHPUT_0,
-                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
-                                       sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw));
-                       DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index);
-                       DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x",
-                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0);
-                       DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x",
-                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1);
-                       DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x",
-                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH);
-               }
-
-               /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode
-                * only if required.
-                */
-               if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
-                               link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around &&
-                               link->dpcd_caps.is_branch_dev &&
-                               link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
-                               link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 &&
-                               (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE ||
-                               link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) {
-                       /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA.
-                        * Clear FEC and DSC capabilities as a work around if that is not the case.
-                        */
-                       link->wa_flags.dpia_forced_tbt3_mode = true;
-                       memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps));
-                       memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
-                       DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index);
-               } else
-                       link->wa_flags.dpia_forced_tbt3_mode = false;
-       }
-
-       if (!dpcd_read_sink_ext_caps(link))
-               link->dpcd_sink_ext_caps.raw = 0;
-
-       if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
-               DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index);
-
-               core_link_read_dpcd(link,
-                               DP_128B132B_SUPPORTED_LINK_RATES,
-                               &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw,
-                               sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw));
-               if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20)
-                       link->reported_link_cap.link_rate = LINK_RATE_UHBR20;
-               else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5)
-                       link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5;
-               else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10)
-                       link->reported_link_cap.link_rate = LINK_RATE_UHBR10;
-               else
-                       dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__);
-               DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index);
-               DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz",
-                               link->reported_link_cap.link_rate / 100,
-                               link->reported_link_cap.link_rate % 100);
-
-               core_link_read_dpcd(link,
-                               DP_SINK_VIDEO_FALLBACK_FORMATS,
-                               &link->dpcd_caps.fallback_formats.raw,
-                               sizeof(link->dpcd_caps.fallback_formats.raw));
-               DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index);
-               if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support)
-                       DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported");
-               if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support)
-                       DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported");
-               if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support)
-                       DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported");
-               if (link->dpcd_caps.fallback_formats.raw == 0) {
-                       DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported");
-                       link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1;
-               }
-
-               core_link_read_dpcd(link,
-                               DP_FEC_CAPABILITY_1,
-                               &link->dpcd_caps.fec_cap1.raw,
-                               sizeof(link->dpcd_caps.fec_cap1.raw));
-               DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index);
-               if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE)
-                       DC_LOG_DP2("\tFEC aggregated error counters are supported");
-       }
-
-       retrieve_cable_id(link);
-       dpcd_write_cable_id_to_dprx(link);
-
-       /* Connectivity log: detection */
-       CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
-
-       return true;
-}
-
-bool detect_dp_sink_caps(struct dc_link *link)
-{
-       return retrieve_link_cap(link);
-}
-
-void detect_edp_sink_caps(struct dc_link *link)
-{
-       uint8_t supported_link_rates[16];
-       uint32_t entry;
-       uint32_t link_rate_in_khz;
-       enum dc_link_rate link_rate = LINK_RATE_UNKNOWN;
-       uint8_t backlight_adj_cap;
-       uint8_t general_edp_cap;
-
-       retrieve_link_cap(link);
-       link->dpcd_caps.edp_supported_link_rates_count = 0;
-       memset(supported_link_rates, 0, sizeof(supported_link_rates));
-
-       /*
-        * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
-        * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
-        */
-       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
-                       (link->panel_config.ilr.optimize_edp_link_rate ||
-                       link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) {
-               // Read DPCD 00010h - 0001Fh 16 bytes at one shot
-               core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
-                                                       supported_link_rates, sizeof(supported_link_rates));
-
-               for (entry = 0; entry < 16; entry += 2) {
-                       // DPCD register reports per-lane link rate = 16-bit link rate capability
-                       // value X 200 kHz. Need multiplier to find link rate in kHz.
-                       link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
-                                                                               supported_link_rates[entry]) * 200;
-
-                       if (link_rate_in_khz != 0) {
-                               link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz);
-                               link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate;
-                               link->dpcd_caps.edp_supported_link_rates_count++;
-
-                               if (link->reported_link_cap.link_rate < link_rate)
-                                       link->reported_link_cap.link_rate = link_rate;
-                       }
-               }
-       }
-       core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP,
-                                               &backlight_adj_cap, sizeof(backlight_adj_cap));
-
-       link->dpcd_caps.dynamic_backlight_capable_edp =
-                               (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false;
-
-       core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1,
-                                               &general_edp_cap, sizeof(general_edp_cap));
-
-       link->dpcd_caps.set_power_state_capable_edp =
-                               (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false;
-
-       dc_link_set_default_brightness_aux(link);
-
-       core_link_read_dpcd(link, DP_EDP_DPCD_REV,
-               &link->dpcd_caps.edp_rev,
-               sizeof(link->dpcd_caps.edp_rev));
-       /*
-        * PSR is only valid for eDP v1.3 or higher.
-        */
-       if (link->dpcd_caps.edp_rev >= DP_EDP_13) {
-               core_link_read_dpcd(link, DP_PSR_SUPPORT,
-                       &link->dpcd_caps.psr_info.psr_version,
-                       sizeof(link->dpcd_caps.psr_info.psr_version));
-               if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
-                       core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY,
-                                               &link->dpcd_caps.psr_info.force_psrsu_cap,
-                                               sizeof(link->dpcd_caps.psr_info.force_psrsu_cap));
-               core_link_read_dpcd(link, DP_PSR_CAPS,
-                       &link->dpcd_caps.psr_info.psr_dpcd_caps.raw,
-                       sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw));
-               if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) {
-                       core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY,
-                               &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap,
-                               sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap));
-               }
-       }
-
-       /*
-        * ALPM is only valid for eDP v1.4 or higher.
-        */
-       if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14)
-               core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP,
-                       &link->dpcd_caps.alpm_caps.raw,
-                       sizeof(link->dpcd_caps.alpm_caps.raw));
-}
-
-bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
-{
-       struct link_encoder *link_enc = NULL;
-
-       if (!max_link_enc_cap) {
-               DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__);
-               return false;
-       }
-
-       link_enc = link_enc_cfg_get_link_enc(link);
-       ASSERT(link_enc);
-
-       if (link_enc && link_enc->funcs->get_max_link_cap) {
-               link_enc->funcs->get_max_link_cap(link_enc, max_link_enc_cap);
-               return true;
-       }
-
-       DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__);
-       max_link_enc_cap->lane_count = 1;
-       max_link_enc_cap->link_rate = 6;
-       return false;
-}
-
-const struct dc_link_settings *dc_link_get_link_cap(
-               const struct dc_link *link)
-{
-       if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN &&
-                       link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
-               return &link->preferred_link_setting;
-       return &link->verified_link_cap;
-}
-
-struct dc_link_settings dp_get_max_link_cap(struct dc_link *link)
-{
-       struct dc_link_settings max_link_cap = {0};
-       enum dc_link_rate lttpr_max_link_rate;
-       enum dc_link_rate cable_max_link_rate;
-       struct link_encoder *link_enc = NULL;
-
-
-       link_enc = link_enc_cfg_get_link_enc(link);
-       ASSERT(link_enc);
-
-       /* get max link encoder capability */
-       if (link_enc)
-               link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap);
-
-       /* Lower link settings based on sink's link cap */
-       if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
-               max_link_cap.lane_count =
-                               link->reported_link_cap.lane_count;
-       if (link->reported_link_cap.link_rate < max_link_cap.link_rate)
-               max_link_cap.link_rate =
-                               link->reported_link_cap.link_rate;
-       if (link->reported_link_cap.link_spread <
-                       max_link_cap.link_spread)
-               max_link_cap.link_spread =
-                               link->reported_link_cap.link_spread;
-
-       /* Lower link settings based on cable attributes
-        * Cable ID is a DP2 feature to identify max certified link rate that
-        * a cable can carry. The cable identification method requires both
-        * cable and display hardware support. Since the specs comes late, it is
-        * anticipated that the first round of DP2 cables and displays may not
-        * be fully compatible to reliably return cable ID data. Therefore the
-        * decision of our cable id policy is that if the cable can return non
-        * zero cable id data, we will take cable's link rate capability into
-        * account. However if we get zero data, the cable link rate capability
-        * is considered inconclusive. In this case, we will not take cable's
-        * capability into account to avoid of over limiting hardware capability
-        * from users. The max overall link rate capability is still determined
-        * after actual dp pre-training. Cable id is considered as an auxiliary
-        * method of determining max link bandwidth capability.
-        */
-       cable_max_link_rate = get_cable_max_link_rate(link);
-
-       if (!link->dc->debug.ignore_cable_id &&
-                       cable_max_link_rate != LINK_RATE_UNKNOWN &&
-                       cable_max_link_rate < max_link_cap.link_rate)
-               max_link_cap.link_rate = cable_max_link_rate;
-
-       /* account for lttpr repeaters cap
-        * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
-        */
-       if (dp_is_lttpr_present(link)) {
-               if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count)
-                       max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count;
-               lttpr_max_link_rate = get_lttpr_max_link_rate(link);
-
-               if (lttpr_max_link_rate < max_link_cap.link_rate)
-                       max_link_cap.link_rate = lttpr_max_link_rate;
-
-               DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR,  max_lane count %d max_link rate %d \n",
-                                               __func__,
-                                               max_link_cap.lane_count,
-                                               max_link_cap.link_rate);
-       }
-
-       if (link_dp_get_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING &&
-                       link->dc->debug.disable_uhbr)
-               max_link_cap.link_rate = LINK_RATE_HIGH3;
-
-       return max_link_cap;
-}
-
-static bool dp_verify_link_cap(
-       struct dc_link *link,
-       struct dc_link_settings *known_limit_link_setting,
-       int *fail_count)
-{
-       struct dc_link_settings cur_link_settings = {0};
-       struct dc_link_settings max_link_settings = *known_limit_link_setting;
-       bool success = false;
-       bool skip_video_pattern;
-       enum clock_source_id dp_cs_id = get_clock_source_id(link);
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
-       union hpd_irq_data irq_data;
-       struct link_resource link_res;
-
-       memset(&irq_data, 0, sizeof(irq_data));
-       cur_link_settings = max_link_settings;
-
-       /* Grant extended timeout request */
-       if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) {
-               uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80;
-
-               core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
-       }
-
-       do {
-               if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings))
-                       continue;
-
-               skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW;
-               dp_enable_link_phy(
-                               link,
-                               &link_res,
-                               link->connector_signal,
-                               dp_cs_id,
-                               &cur_link_settings);
-
-               status = dp_perform_link_training(
-                               link,
-                               &link_res,
-                               &cur_link_settings,
-                               skip_video_pattern);
-
-               if (status == LINK_TRAINING_SUCCESS) {
-                       success = true;
-                       udelay(1000);
-                       if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
-                                       hpd_rx_irq_check_link_loss_status(
-                                                       link,
-                                                       &irq_data))
-                               (*fail_count)++;
-
-               } else {
-                       (*fail_count)++;
-               }
-               dp_trace_lt_total_count_increment(link, true);
-               dp_trace_lt_result_update(link, status, true);
-               dp_disable_link_phy(link, &link_res, link->connector_signal);
-       } while (!success && decide_fallback_link_setting(link,
-                       &max_link_settings, &cur_link_settings, status));
-
-       link->verified_link_cap = success ?
-                       cur_link_settings : fail_safe_link_settings;
-       return success;
-}
-
-bool dp_verify_link_cap_with_retries(
-       struct dc_link *link,
-       struct dc_link_settings *known_limit_link_setting,
-       int attempts)
-{
-       int i = 0;
-       bool success = false;
-       int fail_count = 0;
-
-       dp_trace_detect_lt_init(link);
-
-       if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
-                       link->dc->debug.usbc_combo_phy_reset_wa)
-               apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting);
-
-       dp_trace_set_lt_start_timestamp(link, false);
-       for (i = 0; i < attempts; i++) {
-               enum dc_connection_type type = dc_connection_none;
-
-               memset(&link->verified_link_cap, 0,
-                               sizeof(struct dc_link_settings));
-               if (!dc_link_detect_sink(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,
-                               &fail_count) && fail_count == 0) {
-                       success = true;
-                       break;
-               }
-               msleep(10);
-       }
-
-       dp_trace_lt_fail_count_update(link, fail_count, true);
-       dp_trace_set_lt_end_timestamp(link, true);
-
-       return success;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_capability.h
deleted file mode 100644 (file)
index 5500744..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DC_LINK_DP_CAPABILITY_H__
-#define __DC_LINK_DP_CAPABILITY_H__
-
-#include "link.h"
-
-bool detect_dp_sink_caps(struct dc_link *link);
-
-void detect_edp_sink_caps(struct dc_link *link);
-
-struct dc_link_settings dp_get_max_link_cap(struct dc_link *link);
-
-
-enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
-
-/* Convert PHY repeater count read from DPCD uint8_t. */
-uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count);
-
-bool dp_is_lttpr_present(struct dc_link *link);
-
-bool is_dp_active_dongle(const struct dc_link *link);
-
-bool is_dp_branch_device(const struct dc_link *link);
-
-bool decide_edp_link_settings_with_dsc(struct dc_link *link,
-               struct dc_link_settings *link_setting,
-               uint32_t req_bw,
-               enum dc_link_rate max_link_rate);
-
-void dpcd_set_source_specific_data(struct dc_link *link);
-
-/*query dpcd for version and mst cap addresses*/
-bool read_is_mst_supported(struct dc_link *link);
-
-bool decide_fallback_link_setting(
-               struct dc_link *link,
-               struct dc_link_settings *max,
-               struct dc_link_settings *cur,
-               enum link_training_result training_result);
-
-
-#endif /* __DC_LINK_DP_CAPABILITY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.c
deleted file mode 100644 (file)
index 6136db3..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright 2021 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 "dc.h"
-#include "inc/core_status.h"
-#include "dc_link.h"
-#include "dc_link_dp.h"
-#include "dpcd_defs.h"
-
-#include "link_dp_dpia.h"
-#include "link_hwss.h"
-#include "dm_helpers.h"
-#include "dmub/inc/dmub_cmd.h"
-#include "link_dpcd.h"
-#include "link_dp_training.h"
-#include "dc_dmub_srv.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-
-/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */
-/* DPCD DP Tunneling over USB4 */
-#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d
-#define DP_IN_ADAPTER_INFO                0xe000e
-#define DP_USB4_DRIVER_ID                 0xe000f
-#define DP_USB4_ROUTER_TOPOLOGY_ID        0xe001b
-
-enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
-{
-       enum dc_status status = DC_OK;
-       uint8_t dpcd_dp_tun_data[3] = {0};
-       uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0};
-       uint8_t i = 0;
-
-       status = core_link_read_dpcd(
-                       link,
-                       DP_TUNNELING_CAPABILITIES_SUPPORT,
-                       dpcd_dp_tun_data,
-                       sizeof(dpcd_dp_tun_data));
-
-       status = core_link_read_dpcd(
-                       link,
-                       DP_USB4_ROUTER_TOPOLOGY_ID,
-                       dpcd_topology_data,
-                       sizeof(dpcd_topology_data));
-
-       link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw =
-                       dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - DP_TUNNELING_CAPABILITIES_SUPPORT];
-       link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw =
-                       dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT];
-       link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id =
-                       dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT];
-
-       for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++)
-               link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i];
-
-       return status;
-}
-
-bool dc_link_dpia_query_hpd_status(struct dc_link *link)
-{
-       union dmub_rb_cmd cmd = {0};
-       struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv;
-       bool is_hpd_high = false;
-
-       /* prepare QUERY_HPD command */
-       cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE;
-       cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1;
-       cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA;
-
-       /* Return HPD status reported by DMUB if query successfully executed. */
-       if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS)
-               is_hpd_high = cmd.query_hpd.data.result;
-
-       DC_LOG_DEBUG("%s: link(%d) dpia(%d) cmd_status(%d) result(%d)\n",
-               __func__,
-               link->link_index,
-               link->link_id.enum_id - ENUM_ID_1,
-               cmd.query_hpd.data.status,
-               cmd.query_hpd.data.result);
-
-       return is_hpd_high;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia.h
deleted file mode 100644 (file)
index 98935cc..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright 2021 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_DPIA_H__
-#define __DC_LINK_DPIA_H__
-
-#include "link.h"
-
-/* Read tunneling device capability from DPCD and update link capability
- * accordingly.
- */
-enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link);
-
-/* Query hot plug status of USB4 DP tunnel.
- * Returns true if HPD high.
- */
-bool dc_link_dpia_query_hpd_status(struct dc_link *link);
-
-
-#endif /* __DC_LINK_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c
deleted file mode 100644 (file)
index 801a95b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-/*********************************************************************/
-//                             USB4 DPIA BANDWIDTH ALLOCATION LOGIC
-/*********************************************************************/
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h
deleted file mode 100644 (file)
index 58eb7b5..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2021 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_INC_LINK_DP_DPIA_BW_H_
-#define DC_INC_LINK_DP_DPIA_BW_H_
-
-/*
- * Host Router BW type
- */
-enum bw_type {
-       HOST_ROUTER_BW_ESTIMATED,
-       HOST_ROUTER_BW_ALLOCATED,
-       HOST_ROUTER_BW_INVALID,
-};
-
-/*
- * Enable BW Allocation Mode Support from the DP-Tx side
- *
- * @link: pointer to the dc_link struct instance
- *
- * return: SUCCESS or FAILURE
- */
-bool set_dptx_usb4_bw_alloc_support(struct dc_link *link);
-
-/*
- * Send a request from DP-Tx requesting to allocate BW remotely after
- * allocating it locally. This will get processed by CM and a CB function
- * will be called.
- *
- * @link: pointer to the dc_link struct instance
- * @req_bw: The requested bw in Kbyte to allocated
- *
- * return: none
- */
-void set_usb4_req_bw_req(struct dc_link *link, int req_bw);
-
-/*
- * CB function for when the status of the Req above is complete. We will
- * find out the result of allocating on CM and update structs accordingly
- *
- * @link: pointer to the dc_link struct instance
- * @bw: Allocated or Estimated BW depending on the result
- * @result: Response type
- *
- * return: none
- */
-void get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result);
-
-/*
- * Return the response_ready flag from dc_link struct
- *
- * @link: pointer to the dc_link struct instance
- *
- * return: response_ready flag from dc_link struct
- */
-bool get_cm_response_ready_flag(struct dc_link *link);
-
-/*
- * Get the Max Available BW or Max Estimated BW for each Host Router
- *
- * @link: pointer to the dc_link struct instance
- * @type: ESTIMATD BW or MAX AVAILABLE BW
- *
- * return: response_ready flag from dc_link struct
- */
-int get_host_router_total_bw(struct dc_link *link, uint8_t type);
-
-/*
- * Cleanup function for when the dpia is unplugged to reset struct
- * and perform any required clean up
- *
- * @link: pointer to the dc_link struct instance
- *
- * return: none
- */
-bool dpia_bw_alloc_unplug(struct dc_link *link);
-
-#endif /* DC_INC_LINK_DP_DPIA_BW_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.c
deleted file mode 100644 (file)
index afe3b21..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This file implements basic dp phy functionality such as enable/disable phy
- * output and set lane/drive settings. This file is responsible for maintaining
- * and update software state representing current phy status such as current
- * link settings.
- */
-
-#include "link_dp_phy.h"
-#include "link_dpcd.h"
-#include "link_dp_training.h"
-#include "link_dp_capability.h"
-#include "clk_mgr.h"
-#include "resource.h"
-#include "dc_link_dp.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-
-void dc_link_dp_set_drive_settings(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings)
-{
-       /* program ASIC PHY settings*/
-       dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
-
-       dp_hw_to_dpcd_lane_settings(lt_settings,
-                       lt_settings->hw_lane_settings,
-                       lt_settings->dpcd_lane_settings);
-
-       /* Notify DP sink the PHY settings from source */
-       dpcd_set_lane_settings(link, lt_settings, DPRX);
-}
-
-void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on)
-{
-       uint8_t state;
-
-       state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
-
-       if (link->sync_lt_in_progress)
-               return;
-
-       core_link_write_dpcd(link, DP_SET_POWER, &state,
-                                                sizeof(state));
-
-}
-
-void dp_enable_link_phy(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       enum signal_type signal,
-       enum clock_source_id clock_source,
-       const struct dc_link_settings *link_settings)
-{
-       link->cur_link_settings = *link_settings;
-       link->dc->hwss.enable_dp_link_output(link, link_res, signal,
-                       clock_source, link_settings);
-       dc_link_dp_receiver_power_ctrl(link, true);
-}
-
-void dp_disable_link_phy(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal)
-{
-       struct dc  *dc = link->ctx->dc;
-
-       if (!link->wa_flags.dp_keep_receiver_powered)
-               dc_link_dp_receiver_power_ctrl(link, false);
-
-       dc->hwss.disable_link_output(link, link_res, signal);
-       /* Clear current link setting.*/
-       memset(&link->cur_link_settings, 0,
-                       sizeof(link->cur_link_settings));
-
-       if (dc->clk_mgr->funcs->notify_link_rate_change)
-               dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
-}
-
-void dp_disable_link_phy_mst(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal)
-{
-       /* MST disable link only when no stream use the link */
-       if (link->mst_stream_alloc_table.stream_count > 0)
-               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)
-{
-       return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ==
-                       offset);
-}
-
-void dp_set_hw_lane_settings(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       const struct link_training_settings *link_settings,
-       uint32_t offset)
-{
-       const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
-
-       if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) &&
-                       !is_immediate_downstream(link, offset))
-               return;
-
-       if (link_hwss->ext.set_dp_lane_settings)
-               link_hwss->ext.set_dp_lane_settings(link, link_res,
-                               &link_settings->link_settings,
-                               link_settings->hw_lane_settings);
-
-       memmove(link->cur_lane_setting,
-                       link_settings->hw_lane_settings,
-                       sizeof(link->cur_lane_setting));
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_phy.h
deleted file mode 100644 (file)
index 717e078..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DC_LINK_DP_PHY_H__
-#define __DC_LINK_DP_PHY_H__
-
-#include "link.h"
-void dp_enable_link_phy(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       enum signal_type signal,
-       enum clock_source_id clock_source,
-       const struct dc_link_settings *link_settings);
-
-void dp_disable_link_phy(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal);
-
-void dp_disable_link_phy_mst(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal);
-
-void dp_set_hw_lane_settings(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct link_training_settings *link_settings,
-               uint32_t offset);
-
-#endif /* __DC_LINK_DP_PHY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c
deleted file mode 100644 (file)
index 2c1a3bf..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#include "dc_link.h"
-#include "link_dp_trace.h"
-
-void dp_trace_init(struct dc_link *link)
-{
-       memset(&link->dp_trace, 0, sizeof(link->dp_trace));
-       link->dp_trace.is_initialized = true;
-}
-
-void dp_trace_reset(struct dc_link *link)
-{
-       memset(&link->dp_trace, 0, sizeof(link->dp_trace));
-}
-
-bool dc_dp_trace_is_initialized(struct dc_link *link)
-{
-       return link->dp_trace.is_initialized;
-}
-
-void dp_trace_detect_lt_init(struct dc_link *link)
-{
-       memset(&link->dp_trace.detect_lt_trace, 0, sizeof(link->dp_trace.detect_lt_trace));
-}
-
-void dp_trace_commit_lt_init(struct dc_link *link)
-{
-       memset(&link->dp_trace.commit_lt_trace, 0, sizeof(link->dp_trace.commit_lt_trace));
-}
-
-void dp_trace_link_loss_increment(struct dc_link *link)
-{
-       link->dp_trace.link_loss_count++;
-}
-
-void dp_trace_lt_fail_count_update(struct dc_link *link,
-               unsigned int fail_count,
-               bool in_detection)
-{
-       if (in_detection)
-               link->dp_trace.detect_lt_trace.counts.fail = fail_count;
-       else
-               link->dp_trace.commit_lt_trace.counts.fail = fail_count;
-}
-
-void dp_trace_lt_total_count_increment(struct dc_link *link,
-               bool in_detection)
-{
-       if (in_detection)
-               link->dp_trace.detect_lt_trace.counts.total++;
-       else
-               link->dp_trace.commit_lt_trace.counts.total++;
-}
-
-void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
-               bool in_detection,
-               bool is_logged)
-{
-       if (in_detection)
-               link->dp_trace.detect_lt_trace.is_logged = is_logged;
-       else
-               link->dp_trace.commit_lt_trace.is_logged = is_logged;
-}
-
-bool dc_dp_trace_is_logged(struct dc_link *link,
-               bool in_detection)
-{
-       if (in_detection)
-               return link->dp_trace.detect_lt_trace.is_logged;
-       else
-               return link->dp_trace.commit_lt_trace.is_logged;
-}
-
-void dp_trace_lt_result_update(struct dc_link *link,
-               enum link_training_result result,
-               bool in_detection)
-{
-       if (in_detection)
-               link->dp_trace.detect_lt_trace.result = result;
-       else
-               link->dp_trace.commit_lt_trace.result = result;
-}
-
-void dp_trace_set_lt_start_timestamp(struct dc_link *link,
-               bool in_detection)
-{
-       if (in_detection)
-               link->dp_trace.detect_lt_trace.timestamps.start = dm_get_timestamp(link->dc->ctx);
-       else
-               link->dp_trace.commit_lt_trace.timestamps.start = dm_get_timestamp(link->dc->ctx);
-}
-
-void dp_trace_set_lt_end_timestamp(struct dc_link *link,
-               bool in_detection)
-{
-       if (in_detection)
-               link->dp_trace.detect_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx);
-       else
-               link->dp_trace.commit_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx);
-}
-
-unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
-               bool in_detection)
-{
-       if (in_detection)
-               return link->dp_trace.detect_lt_trace.timestamps.end;
-       else
-               return link->dp_trace.commit_lt_trace.timestamps.end;
-}
-
-struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
-               bool in_detection)
-{
-       if (in_detection)
-               return &link->dp_trace.detect_lt_trace.counts;
-       else
-               return &link->dp_trace.commit_lt_trace.counts;
-}
-
-unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link)
-{
-       return link->dp_trace.link_loss_count;
-}
-
-void dp_trace_set_edp_power_timestamp(struct dc_link *link,
-               bool power_up)
-{
-       if (!power_up)
-               /*save driver power off time stamp*/
-               link->dp_trace.edp_trace_power_timestamps.poweroff = dm_get_timestamp(link->dc->ctx);
-       else
-               link->dp_trace.edp_trace_power_timestamps.poweron = dm_get_timestamp(link->dc->ctx);
-}
-
-uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link)
-{
-       return link->dp_trace.edp_trace_power_timestamps.poweron;
-}
-
-uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link)
-{
-       return link->dp_trace.edp_trace_power_timestamps.poweroff;
-}
\ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h
deleted file mode 100644 (file)
index 26700e3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#ifndef __LINK_DP_TRACE_H__
-#define __LINK_DP_TRACE_H__
-
-void dp_trace_init(struct dc_link *link);
-void dp_trace_reset(struct dc_link *link);
-bool dc_dp_trace_is_initialized(struct dc_link *link);
-void dp_trace_detect_lt_init(struct dc_link *link);
-void dp_trace_commit_lt_init(struct dc_link *link);
-void dp_trace_link_loss_increment(struct dc_link *link);
-void dp_trace_lt_fail_count_update(struct dc_link *link,
-               unsigned int fail_count,
-               bool in_detection);
-void dp_trace_lt_total_count_increment(struct dc_link *link,
-               bool in_detection);
-void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
-               bool in_detection,
-               bool is_logged);
-bool dc_dp_trace_is_logged(struct dc_link *link,
-               bool in_detection);
-void dp_trace_lt_result_update(struct dc_link *link,
-               enum link_training_result result,
-               bool in_detection);
-void dp_trace_set_lt_start_timestamp(struct dc_link *link,
-               bool in_detection);
-void dp_trace_set_lt_end_timestamp(struct dc_link *link,
-               bool in_detection);
-unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
-               bool in_detection);
-struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
-               bool in_detection);
-unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
-
-void dp_trace_set_edp_power_timestamp(struct dc_link *link,
-               bool power_up);
-uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link);
-uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link);
-
-#endif /* __LINK_DP_TRACE_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training.c
deleted file mode 100644 (file)
index e49e025..0000000
+++ /dev/null
@@ -1,1700 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This file implements all generic dp link training helper functions and top
- * level generic training sequence. All variations of dp link training sequence
- * should be called inside the top level training functions in this file to
- * ensure the integrity of our overall training procedure across different types
- * of link encoding and back end hardware.
- */
-#include "link_dp_training.h"
-#include "link_dp_training_8b_10b.h"
-#include "link_dp_training_128b_132b.h"
-#include "link_dp_training_auxless.h"
-#include "link_dp_training_dpia.h"
-#include "link_dp_training_fixed_vs_pe_retimer.h"
-#include "link_dpcd.h"
-#include "link_dp_trace.h"
-#include "link_dp_phy.h"
-#include "link_dp_capability.h"
-#include "dc_link_dp.h"
-#include "atomfirmware.h"
-#include "link_enc_cfg.h"
-#include "resource.h"
-#include "dm_helpers.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-
-#define POST_LT_ADJ_REQ_LIMIT 6
-#define POST_LT_ADJ_REQ_TIMEOUT 200
-
-void dp_log_training_result(
-       struct dc_link *link,
-       const struct link_training_settings *lt_settings,
-       enum link_training_result status)
-{
-       char *link_rate = "Unknown";
-       char *lt_result = "Unknown";
-       char *lt_spread = "Disabled";
-
-       switch (lt_settings->link_settings.link_rate) {
-       case LINK_RATE_LOW:
-               link_rate = "RBR";
-               break;
-       case LINK_RATE_RATE_2:
-               link_rate = "R2";
-               break;
-       case LINK_RATE_RATE_3:
-               link_rate = "R3";
-               break;
-       case LINK_RATE_HIGH:
-               link_rate = "HBR";
-               break;
-       case LINK_RATE_RBR2:
-               link_rate = "RBR2";
-               break;
-       case LINK_RATE_RATE_6:
-               link_rate = "R6";
-               break;
-       case LINK_RATE_HIGH2:
-               link_rate = "HBR2";
-               break;
-       case LINK_RATE_HIGH3:
-               link_rate = "HBR3";
-               break;
-       case LINK_RATE_UHBR10:
-               link_rate = "UHBR10";
-               break;
-       case LINK_RATE_UHBR13_5:
-               link_rate = "UHBR13.5";
-               break;
-       case LINK_RATE_UHBR20:
-               link_rate = "UHBR20";
-               break;
-       default:
-               break;
-       }
-
-       switch (status) {
-       case LINK_TRAINING_SUCCESS:
-               lt_result = "pass";
-               break;
-       case LINK_TRAINING_CR_FAIL_LANE0:
-               lt_result = "CR failed lane0";
-               break;
-       case LINK_TRAINING_CR_FAIL_LANE1:
-               lt_result = "CR failed lane1";
-               break;
-       case LINK_TRAINING_CR_FAIL_LANE23:
-               lt_result = "CR failed lane23";
-               break;
-       case LINK_TRAINING_EQ_FAIL_CR:
-               lt_result = "CR failed in EQ";
-               break;
-       case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
-               lt_result = "CR failed in EQ partially";
-               break;
-       case LINK_TRAINING_EQ_FAIL_EQ:
-               lt_result = "EQ failed";
-               break;
-       case LINK_TRAINING_LQA_FAIL:
-               lt_result = "LQA failed";
-               break;
-       case LINK_TRAINING_LINK_LOSS:
-               lt_result = "Link loss";
-               break;
-       case DP_128b_132b_LT_FAILED:
-               lt_result = "LT_FAILED received";
-               break;
-       case DP_128b_132b_MAX_LOOP_COUNT_REACHED:
-               lt_result = "max loop count reached";
-               break;
-       case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT:
-               lt_result = "channel EQ timeout";
-               break;
-       case DP_128b_132b_CDS_DONE_TIMEOUT:
-               lt_result = "CDS timeout";
-               break;
-       default:
-               break;
-       }
-
-       switch (lt_settings->link_settings.link_spread) {
-       case LINK_SPREAD_DISABLED:
-               lt_spread = "Disabled";
-               break;
-       case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
-               lt_spread = "0.5% 30KHz";
-               break;
-       case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
-               lt_spread = "0.5% 33KHz";
-               break;
-       default:
-               break;
-       }
-
-       /* Connectivity log: link training */
-
-       /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
-
-       CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
-                               link_rate,
-                               lt_settings->link_settings.lane_count,
-                               lt_result,
-                               lt_settings->hw_lane_settings[0].VOLTAGE_SWING,
-                               lt_settings->hw_lane_settings[0].PRE_EMPHASIS,
-                               lt_spread);
-}
-
-uint8_t dp_initialize_scrambling_data_symbols(
-       struct dc_link *link,
-       enum dc_dp_training_pattern pattern)
-{
-       uint8_t disable_scrabled_data_symbols = 0;
-
-       switch (pattern) {
-       case DP_TRAINING_PATTERN_SEQUENCE_1:
-       case DP_TRAINING_PATTERN_SEQUENCE_2:
-       case DP_TRAINING_PATTERN_SEQUENCE_3:
-               disable_scrabled_data_symbols = 1;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_4:
-       case DP_128b_132b_TPS1:
-       case DP_128b_132b_TPS2:
-               disable_scrabled_data_symbols = 0;
-               break;
-       default:
-               ASSERT(0);
-               DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
-                       __func__, pattern);
-               break;
-       }
-       return disable_scrabled_data_symbols;
-}
-
-enum dpcd_training_patterns
-       dp_training_pattern_to_dpcd_training_pattern(
-       struct dc_link *link,
-       enum dc_dp_training_pattern pattern)
-{
-       enum dpcd_training_patterns dpcd_tr_pattern =
-       DPCD_TRAINING_PATTERN_VIDEOIDLE;
-
-       switch (pattern) {
-       case DP_TRAINING_PATTERN_SEQUENCE_1:
-               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_2:
-               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_3:
-               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_4:
-               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
-               break;
-       case DP_128b_132b_TPS1:
-               dpcd_tr_pattern = DPCD_128b_132b_TPS1;
-               break;
-       case DP_128b_132b_TPS2:
-               dpcd_tr_pattern = DPCD_128b_132b_TPS2;
-               break;
-       case DP_128b_132b_TPS2_CDS:
-               dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS;
-               break;
-       case DP_TRAINING_PATTERN_VIDEOIDLE:
-               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
-               break;
-       default:
-               ASSERT(0);
-               DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
-                       __func__, pattern);
-               break;
-       }
-
-       return dpcd_tr_pattern;
-}
-
-static uint8_t get_nibble_at_index(const uint8_t *buf,
-       uint32_t index)
-{
-       uint8_t nibble;
-       nibble = buf[index / 2];
-
-       if (index % 2)
-               nibble >>= 4;
-       else
-               nibble &= 0x0F;
-
-       return nibble;
-}
-
-void dp_wait_for_training_aux_rd_interval(
-       struct dc_link *link,
-       uint32_t wait_in_micro_secs)
-{
-       if (wait_in_micro_secs > 1000)
-               msleep(wait_in_micro_secs/1000);
-       else
-               udelay(wait_in_micro_secs);
-
-       DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
-               __func__,
-               wait_in_micro_secs);
-}
-
-/* maximum pre emphasis level allowed for each voltage swing level*/
-static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
-               PRE_EMPHASIS_LEVEL3,
-               PRE_EMPHASIS_LEVEL2,
-               PRE_EMPHASIS_LEVEL1,
-               PRE_EMPHASIS_DISABLED };
-
-static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing(
-       enum dc_voltage_swing voltage)
-{
-       enum dc_pre_emphasis pre_emphasis;
-       pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
-
-       if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
-               pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
-
-       return pre_emphasis;
-
-}
-
-static void maximize_lane_settings(const struct link_training_settings *lt_settings,
-               struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
-{
-       uint32_t lane;
-       struct dc_lane_settings max_requested;
-
-       max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING;
-       max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS;
-       max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET;
-
-       /* Determine what the maximum of the requested settings are*/
-       for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) {
-               if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING)
-                       max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING;
-
-               if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS)
-                       max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS;
-               if (lane_settings[lane].FFE_PRESET.settings.level >
-                               max_requested.FFE_PRESET.settings.level)
-                       max_requested.FFE_PRESET.settings.level =
-                                       lane_settings[lane].FFE_PRESET.settings.level;
-       }
-
-       /* make sure the requested settings are
-        * not higher than maximum settings*/
-       if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
-               max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
-
-       if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
-               max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
-       if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
-               max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
-
-       /* make sure the pre-emphasis matches the voltage swing*/
-       if (max_requested.PRE_EMPHASIS >
-               get_max_pre_emphasis_for_voltage_swing(
-                       max_requested.VOLTAGE_SWING))
-               max_requested.PRE_EMPHASIS =
-               get_max_pre_emphasis_for_voltage_swing(
-                       max_requested.VOLTAGE_SWING);
-
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
-               lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
-               lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
-       }
-}
-
-void dp_hw_to_dpcd_lane_settings(
-               const struct link_training_settings *lt_settings,
-               const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
-               union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
-{
-       uint8_t lane = 0;
-
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_8b_10b_ENCODING) {
-                       dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
-                                       (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
-                       dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
-                                       (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
-                       dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
-                                       (hw_lane_settings[lane].VOLTAGE_SWING ==
-                                                       VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
-                       dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
-                                       (hw_lane_settings[lane].PRE_EMPHASIS ==
-                                                       PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
-               } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_128b_132b_ENCODING) {
-                       dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
-                                       hw_lane_settings[lane].FFE_PRESET.settings.level;
-               }
-       }
-}
-
-uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
-{
-       uint8_t link_rate = 0;
-       enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings);
-
-       if (encoding == DP_128b_132b_ENCODING)
-               switch (link_settings->link_rate) {
-               case LINK_RATE_UHBR10:
-                       link_rate = 0x1;
-                       break;
-               case LINK_RATE_UHBR20:
-                       link_rate = 0x2;
-                       break;
-               case LINK_RATE_UHBR13_5:
-                       link_rate = 0x4;
-                       break;
-               default:
-                       link_rate = 0;
-                       break;
-               }
-       else if (encoding == DP_8b_10b_ENCODING)
-               link_rate = (uint8_t) link_settings->link_rate;
-       else
-               link_rate = 0;
-
-       return link_rate;
-}
-
-/* Only used for channel equalization */
-uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
-{
-       unsigned int aux_rd_interval_us = 400;
-
-       switch (dpcd_aux_read_interval) {
-       case 0x01:
-               aux_rd_interval_us = 4000;
-               break;
-       case 0x02:
-               aux_rd_interval_us = 8000;
-               break;
-       case 0x03:
-               aux_rd_interval_us = 12000;
-               break;
-       case 0x04:
-               aux_rd_interval_us = 16000;
-               break;
-       case 0x05:
-               aux_rd_interval_us = 32000;
-               break;
-       case 0x06:
-               aux_rd_interval_us = 64000;
-               break;
-       default:
-               break;
-       }
-
-       return aux_rd_interval_us;
-}
-
-enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
-                                       union lane_status *dpcd_lane_status)
-{
-       enum link_training_result result = LINK_TRAINING_SUCCESS;
-
-       if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
-               result = LINK_TRAINING_CR_FAIL_LANE0;
-       else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
-               result = LINK_TRAINING_CR_FAIL_LANE1;
-       else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
-               result = LINK_TRAINING_CR_FAIL_LANE23;
-       else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
-               result = LINK_TRAINING_CR_FAIL_LANE23;
-       return result;
-}
-
-bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
-{
-       return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
-}
-
-bool dp_is_max_vs_reached(
-       const struct link_training_settings *lt_settings)
-{
-       uint32_t lane;
-       for (lane = 0; lane <
-               (uint32_t)(lt_settings->link_settings.lane_count);
-               lane++) {
-               if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
-                       == VOLTAGE_SWING_MAX_LEVEL)
-                       return true;
-       }
-       return false;
-
-}
-
-bool dp_is_cr_done(enum dc_lane_count ln_count,
-       union lane_status *dpcd_lane_status)
-{
-       bool done = true;
-       uint32_t lane;
-       /*LANEx_CR_DONE bits All 1's?*/
-       for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
-               if (!dpcd_lane_status[lane].bits.CR_DONE_0)
-                       done = false;
-       }
-       return done;
-
-}
-
-bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
-               union lane_status *dpcd_lane_status)
-{
-       bool done = true;
-       uint32_t lane;
-       for (lane = 0; lane < (uint32_t)(ln_count); lane++)
-               if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
-                       done = false;
-       return done;
-}
-
-bool dp_is_symbol_locked(enum dc_lane_count ln_count,
-               union lane_status *dpcd_lane_status)
-{
-       bool locked = true;
-       uint32_t lane;
-       for (lane = 0; lane < (uint32_t)(ln_count); lane++)
-               if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
-                       locked = false;
-       return locked;
-}
-
-bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
-{
-       return align_status.bits.INTERLANE_ALIGN_DONE == 1;
-}
-
-enum link_training_result dp_check_link_loss_status(
-       struct dc_link *link,
-       const struct link_training_settings *link_training_setting)
-{
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
-       union lane_status lane_status;
-       uint8_t dpcd_buf[6] = {0};
-       uint32_t lane;
-
-       core_link_read_dpcd(
-                       link,
-                       DP_SINK_COUNT,
-                       (uint8_t *)(dpcd_buf),
-                       sizeof(dpcd_buf));
-
-       /*parse lane status*/
-       for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
-               /*
-                * check lanes status
-                */
-               lane_status.raw = get_nibble_at_index(&dpcd_buf[2], lane);
-
-               if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
-                       !lane_status.bits.CR_DONE_0 ||
-                       !lane_status.bits.SYMBOL_LOCKED_0) {
-                       /* if one of the channel equalization, clock
-                        * recovery or symbol lock is dropped
-                        * consider it as (link has been
-                        * dropped) dp sink status has changed
-                        */
-                       status = LINK_TRAINING_LINK_LOSS;
-                       break;
-               }
-       }
-
-       return status;
-}
-
-enum dc_status dp_get_lane_status_and_lane_adjust(
-       struct dc_link *link,
-       const struct link_training_settings *link_training_setting,
-       union lane_status ln_status[LANE_COUNT_DP_MAX],
-       union lane_align_status_updated *ln_align,
-       union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
-       uint32_t offset)
-{
-       unsigned int lane01_status_address = DP_LANE0_1_STATUS;
-       uint8_t lane_adjust_offset = 4;
-       unsigned int lane01_adjust_address;
-       uint8_t dpcd_buf[6] = {0};
-       uint32_t lane;
-       enum dc_status status;
-
-       if (is_repeater(link_training_setting, offset)) {
-               lane01_status_address =
-                               DP_LANE0_1_STATUS_PHY_REPEATER1 +
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-               lane_adjust_offset = 3;
-       }
-
-       status = core_link_read_dpcd(
-               link,
-               lane01_status_address,
-               (uint8_t *)(dpcd_buf),
-               sizeof(dpcd_buf));
-
-       if (status != DC_OK) {
-               DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
-                       " keep current lane status and lane adjust unchanged",
-                       __func__,
-                       lane01_status_address);
-               return status;
-       }
-
-       for (lane = 0; lane <
-               (uint32_t)(link_training_setting->link_settings.lane_count);
-               lane++) {
-
-               ln_status[lane].raw =
-                       get_nibble_at_index(&dpcd_buf[0], lane);
-               ln_adjust[lane].raw =
-                       get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
-       }
-
-       ln_align->raw = dpcd_buf[2];
-
-       if (is_repeater(link_training_setting, offset)) {
-               DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
-                               " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
-                       __func__,
-                       offset,
-                       lane01_status_address, dpcd_buf[0],
-                       lane01_status_address + 1, dpcd_buf[1]);
-
-               lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
-               DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
-                               " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
-                                       __func__,
-                                       offset,
-                                       lane01_adjust_address,
-                                       dpcd_buf[lane_adjust_offset],
-                                       lane01_adjust_address + 1,
-                                       dpcd_buf[lane_adjust_offset + 1]);
-       } else {
-               DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
-                       __func__,
-                       lane01_status_address, dpcd_buf[0],
-                       lane01_status_address + 1, dpcd_buf[1]);
-
-               lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
-
-               DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
-                       __func__,
-                       lane01_adjust_address,
-                       dpcd_buf[lane_adjust_offset],
-                       lane01_adjust_address + 1,
-                       dpcd_buf[lane_adjust_offset + 1]);
-       }
-
-       return status;
-}
-
-static void override_lane_settings(const struct link_training_settings *lt_settings,
-               struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
-{
-       uint32_t lane;
-
-       if (lt_settings->voltage_swing == NULL &&
-                       lt_settings->pre_emphasis == NULL &&
-                       lt_settings->ffe_preset == NULL &&
-                       lt_settings->post_cursor2 == NULL)
-
-               return;
-
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               if (lt_settings->voltage_swing)
-                       lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
-               if (lt_settings->pre_emphasis)
-                       lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
-               if (lt_settings->post_cursor2)
-                       lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
-               if (lt_settings->ffe_preset)
-                       lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
-       }
-}
-
-void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
-{
-       if (!dp_is_lttpr_present(link))
-               return;
-
-       if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
-               *override = LTTPR_MODE_TRANSPARENT;
-       } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
-               *override = LTTPR_MODE_NON_TRANSPARENT;
-       } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
-               *override = LTTPR_MODE_NON_LTTPR;
-       }
-       DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
-}
-
-void override_training_settings(
-               struct dc_link *link,
-               const struct dc_link_training_overrides *overrides,
-               struct link_training_settings *lt_settings)
-{
-       uint32_t lane;
-
-       /* Override link spread */
-       if (!link->dp_ss_off && overrides->downspread != NULL)
-               lt_settings->link_settings.link_spread = *overrides->downspread ?
-                               LINK_SPREAD_05_DOWNSPREAD_30KHZ
-                               : LINK_SPREAD_DISABLED;
-
-       /* Override lane settings */
-       if (overrides->voltage_swing != NULL)
-               lt_settings->voltage_swing = overrides->voltage_swing;
-       if (overrides->pre_emphasis != NULL)
-               lt_settings->pre_emphasis = overrides->pre_emphasis;
-       if (overrides->post_cursor2 != NULL)
-               lt_settings->post_cursor2 = overrides->post_cursor2;
-       if (overrides->ffe_preset != NULL)
-               lt_settings->ffe_preset = overrides->ffe_preset;
-       /* Override HW lane settings with BIOS forced values if present */
-       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
-                       lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
-               lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
-               lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
-               lt_settings->always_match_dpcd_with_hw_lane_settings = false;
-       }
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
-                       lt_settings->voltage_swing != NULL ?
-                       *lt_settings->voltage_swing :
-                       VOLTAGE_SWING_LEVEL0;
-               lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
-                       lt_settings->pre_emphasis != NULL ?
-                       *lt_settings->pre_emphasis
-                       : PRE_EMPHASIS_DISABLED;
-               lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
-                       lt_settings->post_cursor2 != NULL ?
-                       *lt_settings->post_cursor2
-                       : POST_CURSOR2_DISABLED;
-       }
-
-       if (lt_settings->always_match_dpcd_with_hw_lane_settings)
-               dp_hw_to_dpcd_lane_settings(lt_settings,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-
-       /* Override training timings */
-       if (overrides->cr_pattern_time != NULL)
-               lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
-       if (overrides->eq_pattern_time != NULL)
-               lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
-       if (overrides->pattern_for_cr != NULL)
-               lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
-       if (overrides->pattern_for_eq != NULL)
-               lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
-       if (overrides->enhanced_framing != NULL)
-               lt_settings->enhanced_framing = *overrides->enhanced_framing;
-       if (link->preferred_training_settings.fec_enable != NULL)
-               lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       /* Check DP tunnel LTTPR mode debug option. */
-       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
-               lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
-
-#endif
-       dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
-
-}
-
-enum dc_dp_training_pattern decide_cr_training_pattern(
-               const struct dc_link_settings *link_settings)
-{
-       switch (link_dp_get_encoding_format(link_settings)) {
-       case DP_8b_10b_ENCODING:
-       default:
-               return DP_TRAINING_PATTERN_SEQUENCE_1;
-       case DP_128b_132b_ENCODING:
-               return DP_128b_132b_TPS1;
-       }
-}
-
-enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
-               const struct dc_link_settings *link_settings)
-{
-       struct link_encoder *link_enc;
-       struct encoder_feature_support *enc_caps;
-       struct dpcd_caps *rx_caps = &link->dpcd_caps;
-       enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
-
-       link_enc = link_enc_cfg_get_link_enc(link);
-       ASSERT(link_enc);
-       enc_caps = &link_enc->features;
-
-       switch (link_dp_get_encoding_format(link_settings)) {
-       case DP_8b_10b_ENCODING:
-               if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
-                               rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
-                       pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
-               else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
-                               rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
-                       pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
-               else
-                       pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
-               break;
-       case DP_128b_132b_ENCODING:
-               pattern = DP_128b_132b_TPS2;
-               break;
-       default:
-               pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
-               break;
-       }
-       return pattern;
-}
-
-enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link,
-               struct dc_link_settings *link_setting)
-{
-       enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting);
-
-       if (encoding == DP_8b_10b_ENCODING)
-               return dp_decide_8b_10b_lttpr_mode(link);
-       else if (encoding == DP_128b_132b_ENCODING)
-               return dp_decide_128b_132b_lttpr_mode(link);
-
-       ASSERT(0);
-       return LTTPR_MODE_NON_LTTPR;
-}
-
-void dp_decide_lane_settings(
-               const struct link_training_settings *lt_settings,
-               const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
-               struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
-               union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
-{
-       uint32_t lane;
-
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_8b_10b_ENCODING) {
-                       hw_lane_settings[lane].VOLTAGE_SWING =
-                                       (enum dc_voltage_swing)(ln_adjust[lane].bits.
-                                                       VOLTAGE_SWING_LANE);
-                       hw_lane_settings[lane].PRE_EMPHASIS =
-                                       (enum dc_pre_emphasis)(ln_adjust[lane].bits.
-                                                       PRE_EMPHASIS_LANE);
-               } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_128b_132b_ENCODING) {
-                       hw_lane_settings[lane].FFE_PRESET.raw =
-                                       ln_adjust[lane].tx_ffe.PRESET_VALUE;
-               }
-       }
-       dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
-
-       if (lt_settings->disallow_per_lane_settings) {
-               /* we find the maximum of the requested settings across all lanes*/
-               /* and set this maximum for all lanes*/
-               maximize_lane_settings(lt_settings, hw_lane_settings);
-               override_lane_settings(lt_settings, hw_lane_settings);
-
-               if (lt_settings->always_match_dpcd_with_hw_lane_settings)
-                       dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
-       }
-
-}
-
-void dp_decide_training_settings(
-               struct dc_link *link,
-               const struct dc_link_settings *link_settings,
-               struct link_training_settings *lt_settings)
-{
-       if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
-               decide_8b_10b_training_settings(link, link_settings, lt_settings);
-       else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
-               decide_128b_132b_training_settings(link, link_settings, lt_settings);
-}
-
-
-enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
-{
-       uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
-
-       DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
-       return core_link_write_dpcd(link,
-                       DP_PHY_REPEATER_MODE,
-                       (uint8_t *)&repeater_mode,
-                       sizeof(repeater_mode));
-}
-
-static enum dc_status configure_lttpr_mode_non_transparent(
-               struct dc_link *link,
-               const struct link_training_settings *lt_settings)
-{
-       /* aux timeout is already set to extended */
-       /* RESET/SET lttpr mode to enable non transparent mode */
-       uint8_t repeater_cnt;
-       uint32_t aux_interval_address;
-       uint8_t repeater_id;
-       enum dc_status result = DC_ERROR_UNEXPECTED;
-       uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
-
-       enum dp_link_encoding encoding = link_dp_get_encoding_format(&lt_settings->link_settings);
-
-       if (encoding == DP_8b_10b_ENCODING) {
-               DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
-               result = core_link_write_dpcd(link,
-                               DP_PHY_REPEATER_MODE,
-                               (uint8_t *)&repeater_mode,
-                               sizeof(repeater_mode));
-
-       }
-
-       if (result == DC_OK) {
-               link->dpcd_caps.lttpr_caps.mode = repeater_mode;
-       }
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
-               DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
-
-               repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
-               result = core_link_write_dpcd(link,
-                               DP_PHY_REPEATER_MODE,
-                               (uint8_t *)&repeater_mode,
-                               sizeof(repeater_mode));
-
-               if (result == DC_OK) {
-                       link->dpcd_caps.lttpr_caps.mode = repeater_mode;
-               }
-
-               if (encoding == DP_8b_10b_ENCODING) {
-                       repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-                       /* Driver does not need to train the first hop. Skip DPCD read and clear
-                        * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
-                        */
-                       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
-                               link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
-
-                       for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
-                               aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
-                                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
-                               core_link_read_dpcd(
-                                               link,
-                                               aux_interval_address,
-                                               (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
-                                               sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
-                               link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
-                       }
-               }
-       }
-
-       return result;
-}
-
-enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
-{
-       enum dc_status status = DC_OK;
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
-               status = configure_lttpr_mode_transparent(link);
-
-       else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
-               status = configure_lttpr_mode_non_transparent(link, lt_settings);
-
-       return status;
-}
-
-void repeater_training_done(struct dc_link *link, uint32_t offset)
-{
-       union dpcd_training_pattern dpcd_pattern = {0};
-
-       const uint32_t dpcd_base_lt_offset =
-                       DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-       /* Set training not in progress*/
-       dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
-
-       core_link_write_dpcd(
-               link,
-               dpcd_base_lt_offset,
-               &dpcd_pattern.raw,
-               1);
-
-       DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
-               __func__,
-               offset,
-               dpcd_base_lt_offset,
-               dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-}
-
-static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
-{
-       uint8_t sink_status = 0;
-       uint8_t i;
-
-       /* clear training pattern set */
-       dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
-
-       if (encoding == DP_128b_132b_ENCODING) {
-               /* poll for intra-hop disable */
-               for (i = 0; i < 10; i++) {
-                       if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
-                                       (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
-                               break;
-                       udelay(1000);
-               }
-       }
-}
-
-enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
-               struct link_training_settings *lt_settings)
-{
-       enum dp_link_encoding encoding =
-                       link_dp_get_encoding_format(
-                                       &lt_settings->link_settings);
-       enum dc_status status;
-
-       status = core_link_write_dpcd(
-                       link,
-                       DP_MAIN_LINK_CHANNEL_CODING_SET,
-                       (uint8_t *) &encoding,
-                       1);
-       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
-                                       __func__,
-                                       DP_MAIN_LINK_CHANNEL_CODING_SET,
-                                       encoding);
-
-       return status;
-}
-
-void dpcd_set_training_pattern(
-       struct dc_link *link,
-       enum dc_dp_training_pattern training_pattern)
-{
-       union dpcd_training_pattern dpcd_pattern = {0};
-
-       dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
-                       dp_training_pattern_to_dpcd_training_pattern(
-                                       link, training_pattern);
-
-       core_link_write_dpcd(
-               link,
-               DP_TRAINING_PATTERN_SET,
-               &dpcd_pattern.raw,
-               1);
-
-       DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
-               __func__,
-               DP_TRAINING_PATTERN_SET,
-               dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-}
-
-enum dc_status dpcd_set_link_settings(
-       struct dc_link *link,
-       const struct link_training_settings *lt_settings)
-{
-       uint8_t rate;
-       enum dc_status status;
-
-       union down_spread_ctrl downspread = {0};
-       union lane_count_set lane_count_set = {0};
-
-       downspread.raw = (uint8_t)
-       (lt_settings->link_settings.link_spread);
-
-       lane_count_set.bits.LANE_COUNT_SET =
-       lt_settings->link_settings.lane_count;
-
-       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
-       lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
-
-
-       if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
-                       lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
-               lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
-                               link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
-       }
-
-       status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
-               &downspread.raw, sizeof(downspread));
-
-       status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
-               &lane_count_set.raw, 1);
-
-       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
-                       lt_settings->link_settings.use_link_rate_set == true) {
-               rate = 0;
-               /* WA for some MUX chips that will power down with eDP and lose supported
-                * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
-                * MUX chip gets link rate set back before link training.
-                */
-               if (link->connector_signal == SIGNAL_TYPE_EDP) {
-                       uint8_t supported_link_rates[16];
-
-                       core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
-                                       supported_link_rates, sizeof(supported_link_rates));
-               }
-               status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
-               status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
-                               &lt_settings->link_settings.link_rate_set, 1);
-       } else {
-               rate = get_dpcd_link_rate(&lt_settings->link_settings);
-
-               status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
-       }
-
-       if (rate) {
-               DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
-                       __func__,
-                       DP_LINK_BW_SET,
-                       lt_settings->link_settings.link_rate,
-                       DP_LANE_COUNT_SET,
-                       lt_settings->link_settings.lane_count,
-                       lt_settings->enhanced_framing,
-                       DP_DOWNSPREAD_CTRL,
-                       lt_settings->link_settings.link_spread);
-       } else {
-               DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
-                       __func__,
-                       DP_LINK_RATE_SET,
-                       lt_settings->link_settings.link_rate_set,
-                       DP_LANE_COUNT_SET,
-                       lt_settings->link_settings.lane_count,
-                       lt_settings->enhanced_framing,
-                       DP_DOWNSPREAD_CTRL,
-                       lt_settings->link_settings.link_spread);
-       }
-
-       return status;
-}
-
-enum dc_status dpcd_set_lane_settings(
-       struct dc_link *link,
-       const struct link_training_settings *link_training_setting,
-       uint32_t offset)
-{
-       unsigned int lane0_set_address;
-       enum dc_status status;
-       lane0_set_address = DP_TRAINING_LANE0_SET;
-
-       if (is_repeater(link_training_setting, offset))
-               lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
-               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
-       status = core_link_write_dpcd(link,
-               lane0_set_address,
-               (uint8_t *)(link_training_setting->dpcd_lane_settings),
-               link_training_setting->link_settings.lane_count);
-
-       if (is_repeater(link_training_setting, offset)) {
-               DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
-                               " 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
-                       __func__,
-                       offset,
-                       lane0_set_address,
-                       link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
-                       link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
-                       link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
-                       link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
-
-       } else {
-               DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
-                       __func__,
-                       lane0_set_address,
-                       link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
-                       link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
-                       link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
-                       link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
-       }
-
-       return status;
-}
-
-void dpcd_set_lt_pattern_and_lane_settings(
-       struct dc_link *link,
-       const struct link_training_settings *lt_settings,
-       enum dc_dp_training_pattern pattern,
-       uint32_t offset)
-{
-       uint32_t dpcd_base_lt_offset;
-       uint8_t dpcd_lt_buffer[5] = {0};
-       union dpcd_training_pattern dpcd_pattern = {0};
-       uint32_t size_in_bytes;
-       bool edp_workaround = false; /* TODO link_prop.INTERNAL */
-       dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
-
-       if (is_repeater(lt_settings, offset))
-               dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
-                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
-       /*****************************************************************
-       * DpcdAddress_TrainingPatternSet
-       *****************************************************************/
-       dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
-               dp_training_pattern_to_dpcd_training_pattern(link, pattern);
-
-       dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
-               dp_initialize_scrambling_data_symbols(link, pattern);
-
-       dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
-               = dpcd_pattern.raw;
-
-       if (is_repeater(lt_settings, offset)) {
-               DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
-                       __func__,
-                       offset,
-                       dpcd_base_lt_offset,
-                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-       } else {
-               DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
-                       __func__,
-                       dpcd_base_lt_offset,
-                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-       }
-
-       /* concatenate everything into one buffer*/
-       size_in_bytes = lt_settings->link_settings.lane_count *
-                       sizeof(lt_settings->dpcd_lane_settings[0]);
-
-        // 0x00103 - 0x00102
-       memmove(
-               &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
-               lt_settings->dpcd_lane_settings,
-               size_in_bytes);
-
-       if (is_repeater(lt_settings, offset)) {
-               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_128b_132b_ENCODING)
-                       DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
-                                       " 0x%X TX_FFE_PRESET_VALUE = %x\n",
-                                       __func__,
-                                       offset,
-                                       dpcd_base_lt_offset,
-                                       lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
-               else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_8b_10b_ENCODING)
-               DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
-                               " 0x%X VS set = %x PE set = %x max VS Reached = %x  max PE Reached = %x\n",
-                       __func__,
-                       offset,
-                       dpcd_base_lt_offset,
-                       lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
-                       lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
-                       lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
-                       lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
-       } else {
-               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_128b_132b_ENCODING)
-                       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
-                                       __func__,
-                                       dpcd_base_lt_offset,
-                                       lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
-               else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_8b_10b_ENCODING)
-                       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
-                                       __func__,
-                                       dpcd_base_lt_offset,
-                                       lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
-                                       lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
-                                       lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
-                                       lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
-       }
-       if (edp_workaround) {
-               /* for eDP write in 2 parts because the 5-byte burst is
-               * causing issues on some eDP panels (EPR#366724)
-               */
-               core_link_write_dpcd(
-                       link,
-                       DP_TRAINING_PATTERN_SET,
-                       &dpcd_pattern.raw,
-                       sizeof(dpcd_pattern.raw));
-
-               core_link_write_dpcd(
-                       link,
-                       DP_TRAINING_LANE0_SET,
-                       (uint8_t *)(lt_settings->dpcd_lane_settings),
-                       size_in_bytes);
-
-       } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                       DP_128b_132b_ENCODING) {
-               core_link_write_dpcd(
-                               link,
-                               dpcd_base_lt_offset,
-                               dpcd_lt_buffer,
-                               sizeof(dpcd_lt_buffer));
-       } else
-               /* write it all in (1 + number-of-lanes)-byte burst*/
-               core_link_write_dpcd(
-                               link,
-                               dpcd_base_lt_offset,
-                               dpcd_lt_buffer,
-                               size_in_bytes + sizeof(dpcd_pattern.raw));
-}
-
-void start_clock_recovery_pattern_early(struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings,
-               uint32_t offset)
-{
-       DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
-                       __func__);
-       dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
-       dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
-       udelay(400);
-}
-
-void dp_set_hw_test_pattern(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       enum dp_test_pattern test_pattern,
-       uint8_t *custom_pattern,
-       uint32_t custom_pattern_size)
-{
-       const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
-       struct encoder_set_dp_phy_pattern_param pattern_param = {0};
-
-       pattern_param.dp_phy_pattern = test_pattern;
-       pattern_param.custom_pattern = custom_pattern;
-       pattern_param.custom_pattern_size = custom_pattern_size;
-       pattern_param.dp_panel_mode = dp_get_panel_mode(link);
-
-       if (link_hwss->ext.set_dp_link_test_pattern)
-               link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
-}
-
-bool dp_set_hw_training_pattern(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       enum dc_dp_training_pattern pattern,
-       uint32_t offset)
-{
-       enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
-
-       switch (pattern) {
-       case DP_TRAINING_PATTERN_SEQUENCE_1:
-               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_2:
-               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_3:
-               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_4:
-               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
-               break;
-       case DP_128b_132b_TPS1:
-               test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
-               break;
-       case DP_128b_132b_TPS2:
-               test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
-               break;
-       default:
-               break;
-       }
-
-       dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
-
-       return true;
-}
-
-static bool perform_post_lt_adj_req_sequence(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       enum dc_lane_count lane_count =
-       lt_settings->link_settings.lane_count;
-
-       uint32_t adj_req_count;
-       uint32_t adj_req_timer;
-       bool req_drv_setting_changed;
-       uint32_t lane;
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
-       req_drv_setting_changed = false;
-       for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
-       adj_req_count++) {
-
-               req_drv_setting_changed = false;
-
-               for (adj_req_timer = 0;
-                       adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
-                       adj_req_timer++) {
-
-                       dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               DPRX);
-
-                       if (dpcd_lane_status_updated.bits.
-                                       POST_LT_ADJ_REQ_IN_PROGRESS == 0)
-                               return true;
-
-                       if (!dp_is_cr_done(lane_count, dpcd_lane_status))
-                               return false;
-
-                       if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
-                                       !dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
-                                       !dp_is_interlane_aligned(dpcd_lane_status_updated))
-                               return false;
-
-                       for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
-
-                               if (lt_settings->
-                               dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
-                               dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
-                               lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
-                               dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
-
-                                       req_drv_setting_changed = true;
-                                       break;
-                               }
-                       }
-
-                       if (req_drv_setting_changed) {
-                               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-
-                               dc_link_dp_set_drive_settings(link,
-                                               link_res,
-                                               lt_settings);
-                               break;
-                       }
-
-                       msleep(1);
-               }
-
-               if (!req_drv_setting_changed) {
-                       DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
-                               __func__);
-
-                       ASSERT(0);
-                       return true;
-               }
-       }
-       DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
-               __func__);
-
-       ASSERT(0);
-       return true;
-
-}
-
-static enum link_training_result dp_transition_to_video_idle(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings,
-       enum link_training_result status)
-{
-       union lane_count_set lane_count_set = {0};
-
-       /* 4. mainlink output idle pattern*/
-       dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-
-       /*
-        * 5. post training adjust if required
-        * If the upstream DPTX and downstream DPRX both support TPS4,
-        * TPS4 must be used instead of POST_LT_ADJ_REQ.
-        */
-       if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
-                       lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
-               /* delay 5ms after Main Link output idle pattern and then check
-                * DPCD 0202h.
-                */
-               if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
-                       msleep(5);
-                       status = dp_check_link_loss_status(link, lt_settings);
-               }
-               return status;
-       }
-
-       if (status == LINK_TRAINING_SUCCESS &&
-               perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
-               status = LINK_TRAINING_LQA_FAIL;
-
-       lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
-       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
-       lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
-
-       core_link_write_dpcd(
-               link,
-               DP_LANE_COUNT_SET,
-               &lane_count_set.raw,
-               sizeof(lane_count_set));
-
-       return status;
-}
-
-enum link_training_result dp_perform_link_training(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       const struct dc_link_settings *link_settings,
-       bool skip_video_pattern)
-{
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
-       struct link_training_settings lt_settings = {0};
-       enum dp_link_encoding encoding =
-                       link_dp_get_encoding_format(link_settings);
-
-       /* decide training settings */
-       dp_decide_training_settings(
-                       link,
-                       link_settings,
-                       &lt_settings);
-
-       override_training_settings(
-                       link,
-                       &link->preferred_training_settings,
-                       &lt_settings);
-
-       /* reset previous training states */
-       dpcd_exit_training_mode(link, encoding);
-
-       /* configure link prior to entering training mode */
-       dpcd_configure_lttpr_mode(link, &lt_settings);
-       dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
-       dpcd_configure_channel_coding(link, &lt_settings);
-
-       /* enter training mode:
-        * Per DP specs starting from here, DPTX device shall not issue
-        * Non-LT AUX transactions inside training mode.
-        */
-       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING)
-               status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
-       else if (encoding == DP_8b_10b_ENCODING)
-               status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
-       else if (encoding == DP_128b_132b_ENCODING)
-               status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
-       else
-               ASSERT(0);
-
-       /* exit training mode */
-       dpcd_exit_training_mode(link, encoding);
-
-       /* switch to video idle */
-       if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
-               status = dp_transition_to_video_idle(link,
-                               link_res,
-                               &lt_settings,
-                               status);
-
-       /* dump debug data */
-       dp_log_training_result(link, &lt_settings, status);
-       if (status != LINK_TRAINING_SUCCESS)
-               link->ctx->dc->debug_data.ltFailCount++;
-       return status;
-}
-
-bool perform_link_training_with_retries(
-       const struct dc_link_settings *link_setting,
-       bool skip_video_pattern,
-       int attempts,
-       struct pipe_ctx *pipe_ctx,
-       enum signal_type signal,
-       bool do_fallback)
-{
-       int j;
-       uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
-       struct dc_stream_state *stream = pipe_ctx->stream;
-       struct dc_link *link = stream->link;
-       enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
-       enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
-       struct dc_link_settings cur_link_settings = *link_setting;
-       struct dc_link_settings max_link_settings = *link_setting;
-       const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
-       int fail_count = 0;
-       bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
-       bool is_link_bw_min = /* RBR x 1 */
-               (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
-               (cur_link_settings.lane_count <= LANE_COUNT_ONE);
-
-       dp_trace_commit_lt_init(link);
-
-
-       if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
-               /* We need to do this before the link training to ensure the idle
-                * pattern in SST mode will be sent right after the link training
-                */
-               link_hwss->setup_stream_encoder(pipe_ctx);
-
-       dp_trace_set_lt_start_timestamp(link, false);
-       j = 0;
-       while (j < attempts && fail_count < (attempts * 10)) {
-
-               DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n",
-                       __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
-                       cur_link_settings.lane_count);
-
-               dp_enable_link_phy(
-                       link,
-                       &pipe_ctx->link_res,
-                       signal,
-                       pipe_ctx->clock_source->id,
-                       &cur_link_settings);
-
-               if (stream->sink_patches.dppowerup_delay > 0) {
-                       int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
-
-                       msleep(delay_dp_power_up_in_ms);
-               }
-
-#ifdef CONFIG_DRM_AMD_DC_HDCP
-               if (panel_mode == DP_PANEL_MODE_EDP) {
-                       struct cp_psp *cp_psp = &stream->ctx->cp_psp;
-
-                       if (cp_psp && cp_psp->funcs.enable_assr) {
-                               /* ASSR is bound to fail with unsigned PSP
-                                * verstage used during devlopment phase.
-                                * Report and continue with eDP panel mode to
-                                * perform eDP link training with right settings
-                                */
-                               bool result;
-                               result = cp_psp->funcs.enable_assr(cp_psp->handle, link);
-                       }
-               }
-#endif
-
-               dp_set_panel_mode(link, panel_mode);
-
-               if (link->aux_access_disabled) {
-                       dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
-                       return true;
-               } else {
-                       /** @todo Consolidate USB4 DP and DPx.x training. */
-                       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
-                               status = dc_link_dpia_perform_link_training(
-                                               link,
-                                               &pipe_ctx->link_res,
-                                               &cur_link_settings,
-                                               skip_video_pattern);
-
-                               /* Transmit idle pattern once training successful. */
-                               if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
-                                       dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-                                       // Update verified link settings to current one
-                                       // Because DPIA LT might fallback to lower link setting.
-                                       if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
-                                               link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
-                                               link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
-                                               dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
-                                       }
-                               }
-                       } else {
-                               status = dp_perform_link_training(
-                                               link,
-                                               &pipe_ctx->link_res,
-                                               &cur_link_settings,
-                                               skip_video_pattern);
-                       }
-
-                       dp_trace_lt_total_count_increment(link, false);
-                       dp_trace_lt_result_update(link, status, false);
-                       dp_trace_set_lt_end_timestamp(link, false);
-                       if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
-                               return true;
-               }
-
-               fail_count++;
-               dp_trace_lt_fail_count_update(link, fail_count, false);
-               if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
-                       /* latest link training still fail or link training is aborted
-                        * skip delay and keep PHY on
-                        */
-                       if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
-                               break;
-               }
-
-               DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n",
-                       __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
-                       cur_link_settings.lane_count, status);
-
-               dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
-
-               /* Abort link training if failure due to sink being unplugged. */
-               if (status == LINK_TRAINING_ABORT) {
-                       enum dc_connection_type type = dc_connection_none;
-
-                       dc_link_detect_sink(link, &type);
-                       if (type == dc_connection_none) {
-                               DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
-                               break;
-                       }
-               }
-
-               /* Try to train again at original settings if:
-                * - not falling back between training attempts;
-                * - aborted previous attempt due to reasons other than sink unplug;
-                * - successfully trained but at a link rate lower than that required by stream;
-                * - reached minimum link bandwidth.
-                */
-               if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
-                               (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
-                               is_link_bw_min) {
-                       j++;
-                       cur_link_settings = *link_setting;
-                       delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
-                       is_link_bw_low = false;
-                       is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
-                               (cur_link_settings.lane_count <= LANE_COUNT_ONE);
-
-               } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
-                       uint32_t req_bw;
-                       uint32_t link_bw;
-
-                       decide_fallback_link_setting(link, &max_link_settings,
-                                       &cur_link_settings, status);
-                       /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
-                        * minimum link bandwidth.
-                        */
-                       req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
-                       link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings);
-                       is_link_bw_low = (req_bw > link_bw);
-                       is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
-                               (cur_link_settings.lane_count <= LANE_COUNT_ONE));
-
-                       if (is_link_bw_low)
-                               DC_LOG_WARNING(
-                                       "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
-                                       __func__, link->link_index, req_bw, link_bw);
-               }
-
-               msleep(delay_between_attempts);
-       }
-
-       return false;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training.h
deleted file mode 100644 (file)
index 376d370..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_DP_TRAINING_H__
-#define __DC_LINK_DP_TRAINING_H__
-#include "link.h"
-
-bool perform_link_training_with_retries(
-       const struct dc_link_settings *link_setting,
-       bool skip_video_pattern,
-       int attempts,
-       struct pipe_ctx *pipe_ctx,
-       enum signal_type signal,
-       bool do_fallback);
-
-enum link_training_result dp_perform_link_training(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct dc_link_settings *link_settings,
-               bool skip_video_pattern);
-
-bool dp_set_hw_training_pattern(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               enum dc_dp_training_pattern pattern,
-               uint32_t offset);
-
-void dp_set_hw_test_pattern(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               enum dp_test_pattern test_pattern,
-               uint8_t *custom_pattern,
-               uint32_t custom_pattern_size);
-
-void dpcd_set_training_pattern(
-       struct dc_link *link,
-       enum dc_dp_training_pattern training_pattern);
-
-/* Write DPCD drive settings. */
-enum dc_status dpcd_set_lane_settings(
-       struct dc_link *link,
-       const struct link_training_settings *link_training_setting,
-       uint32_t offset);
-
-/* Write DPCD link configuration data. */
-enum dc_status dpcd_set_link_settings(
-       struct dc_link *link,
-       const struct link_training_settings *lt_settings);
-
-void dpcd_set_lt_pattern_and_lane_settings(
-       struct dc_link *link,
-       const struct link_training_settings *lt_settings,
-       enum dc_dp_training_pattern pattern,
-       uint32_t offset);
-
-/* Read training status and adjustment requests from DPCD. */
-enum dc_status dp_get_lane_status_and_lane_adjust(
-       struct dc_link *link,
-       const struct link_training_settings *link_training_setting,
-       union lane_status ln_status[LANE_COUNT_DP_MAX],
-       union lane_align_status_updated *ln_align,
-       union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
-       uint32_t offset);
-
-enum dc_status dpcd_configure_lttpr_mode(
-               struct dc_link *link,
-               struct link_training_settings *lt_settings);
-
-enum dc_status configure_lttpr_mode_transparent(struct dc_link *link);
-
-enum dc_status dpcd_configure_channel_coding(
-               struct dc_link *link,
-               struct link_training_settings *lt_settings);
-
-void repeater_training_done(struct dc_link *link, uint32_t offset);
-
-void start_clock_recovery_pattern_early(struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings,
-               uint32_t offset);
-
-void dp_decide_training_settings(
-               struct dc_link *link,
-               const struct dc_link_settings *link_settings,
-               struct link_training_settings *lt_settings);
-
-void dp_decide_lane_settings(
-       const struct link_training_settings *lt_settings,
-       const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
-       struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
-       union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
-
-enum dc_dp_training_pattern decide_cr_training_pattern(
-               const struct dc_link_settings *link_settings);
-
-enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
-               const struct dc_link_settings *link_settings);
-
-void dp_get_lttpr_mode_override(struct dc_link *link,
-               enum lttpr_mode *override);
-
-void override_training_settings(
-               struct dc_link *link,
-               const struct dc_link_training_overrides *overrides,
-               struct link_training_settings *lt_settings);
-
-/* Check DPCD training status registers to detect link loss. */
-enum link_training_result dp_check_link_loss_status(
-               struct dc_link *link,
-               const struct link_training_settings *link_training_setting);
-
-bool dp_is_cr_done(enum dc_lane_count ln_count,
-       union lane_status *dpcd_lane_status);
-
-bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
-       union lane_status *dpcd_lane_status);
-bool dp_is_symbol_locked(enum dc_lane_count ln_count,
-       union lane_status *dpcd_lane_status);
-bool dp_is_interlane_aligned(union lane_align_status_updated align_status);
-
-bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset);
-
-bool dp_is_max_vs_reached(
-       const struct link_training_settings *lt_settings);
-
-uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings);
-
-enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
-       union lane_status *dpcd_lane_status);
-
-void dp_hw_to_dpcd_lane_settings(
-       const struct link_training_settings *lt_settings,
-       const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
-       union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
-
-void dp_wait_for_training_aux_rd_interval(
-       struct dc_link *link,
-       uint32_t wait_in_micro_secs);
-
-enum dpcd_training_patterns
-       dp_training_pattern_to_dpcd_training_pattern(
-       struct dc_link *link,
-       enum dc_dp_training_pattern pattern);
-
-uint8_t dp_initialize_scrambling_data_symbols(
-       struct dc_link *link,
-       enum dc_dp_training_pattern pattern);
-
-void dp_log_training_result(
-       struct dc_link *link,
-       const struct link_training_settings *lt_settings,
-       enum link_training_result status);
-
-uint32_t dp_translate_training_aux_read_interval(
-               uint32_t dpcd_aux_read_interval);
-#endif /* __DC_LINK_DP_TRAINING_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.c
deleted file mode 100644 (file)
index bfabebe..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This file implements dp 128b/132b link training software policies and
- * sequences.
- */
-#include "link_dp_training_128b_132b.h"
-#include "link_dp_training_8b_10b.h"
-#include "link_dpcd.h"
-#include "link_dp_phy.h"
-#include "link_dp_capability.h"
-#include "dc_link_dp.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-
-static enum dc_status dpcd_128b_132b_set_lane_settings(
-               struct dc_link *link,
-               const struct link_training_settings *link_training_setting)
-{
-       enum dc_status status = core_link_write_dpcd(link,
-                       DP_TRAINING_LANE0_SET,
-                       (uint8_t *)(link_training_setting->dpcd_lane_settings),
-                       sizeof(link_training_setting->dpcd_lane_settings));
-
-       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
-                       __func__,
-                       DP_TRAINING_LANE0_SET,
-                       link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
-       return status;
-}
-
-static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
-               uint32_t *interval_in_us)
-{
-       union dp_128b_132b_training_aux_rd_interval dpcd_interval;
-       uint32_t interval_unit = 0;
-
-       dpcd_interval.raw = 0;
-       core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL,
-                       &dpcd_interval.raw, sizeof(dpcd_interval.raw));
-       interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
-       /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
-        * INTERVAL_UNIT. The maximum is 256 ms
-        */
-       *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
-}
-
-static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       uint8_t loop_count;
-       uint32_t aux_rd_interval = 0;
-       uint32_t wait_time = 0;
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-       enum dc_status status = DC_OK;
-       enum link_training_result result = LINK_TRAINING_SUCCESS;
-
-       /* Transmit 128b/132b_TPS1 over Main-Link */
-       dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX);
-
-       /* Set TRAINING_PATTERN_SET to 01h */
-       dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
-
-       /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
-       dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
-       dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
-                       &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
-       dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-       dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
-       dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX);
-
-       /* Set loop counter to start from 1 */
-       loop_count = 1;
-
-       /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
-       dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
-                       lt_settings->pattern_for_eq, DPRX);
-
-       /* poll for channel EQ done */
-       while (result == LINK_TRAINING_SUCCESS) {
-               dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
-               wait_time += aux_rd_interval;
-               status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
-                               &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-               dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-               } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count,
-                               dpcd_lane_status)) {
-                       /* pass */
-                       break;
-               } else if (loop_count >= lt_settings->eq_loop_count_limit) {
-                       result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
-               } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
-                       result = DP_128b_132b_LT_FAILED;
-               } else {
-                       dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
-                       dpcd_128b_132b_set_lane_settings(link, lt_settings);
-               }
-               loop_count++;
-       }
-
-       /* poll for EQ interlane align done */
-       while (result == LINK_TRAINING_SUCCESS) {
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-               } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
-                       /* pass */
-                       break;
-               } else if (wait_time >= lt_settings->eq_wait_time_limit) {
-                       result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
-               } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
-                       result = DP_128b_132b_LT_FAILED;
-               } else {
-                       dp_wait_for_training_aux_rd_interval(link,
-                                       lt_settings->eq_pattern_time);
-                       wait_time += lt_settings->eq_pattern_time;
-                       status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
-                                       &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
-               }
-       }
-
-       return result;
-}
-
-static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       /* Assumption: assume hardware has transmitted eq pattern */
-       enum dc_status status = DC_OK;
-       enum link_training_result result = LINK_TRAINING_SUCCESS;
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-       uint32_t wait_time = 0;
-
-       /* initiate CDS done sequence */
-       dpcd_set_training_pattern(link, lt_settings->pattern_for_cds);
-
-       /* poll for CDS interlane align done and symbol lock */
-       while (result == LINK_TRAINING_SUCCESS) {
-               dp_wait_for_training_aux_rd_interval(link,
-                               lt_settings->cds_pattern_time);
-               wait_time += lt_settings->cds_pattern_time;
-               status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
-                                               &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-               } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) &&
-                               dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) {
-                       /* pass */
-                       break;
-               } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
-                       result = DP_128b_132b_LT_FAILED;
-               } else if (wait_time >= lt_settings->cds_wait_time_limit) {
-                       result = DP_128b_132b_CDS_DONE_TIMEOUT;
-               }
-       }
-
-       return result;
-}
-
-enum link_training_result dp_perform_128b_132b_link_training(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       enum link_training_result result = LINK_TRAINING_SUCCESS;
-
-       /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
-       if (link->dc->debug.legacy_dp2_lt) {
-               struct link_training_settings legacy_settings;
-
-               decide_8b_10b_training_settings(link,
-                               &lt_settings->link_settings,
-                               &legacy_settings);
-               return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
-       }
-
-       dpcd_set_link_settings(link, lt_settings);
-
-       if (result == LINK_TRAINING_SUCCESS)
-               result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
-
-       if (result == LINK_TRAINING_SUCCESS)
-               result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
-
-       return result;
-}
-
-void decide_128b_132b_training_settings(struct dc_link *link,
-               const struct dc_link_settings *link_settings,
-               struct link_training_settings *lt_settings)
-{
-       memset(lt_settings, 0, sizeof(*lt_settings));
-
-       lt_settings->link_settings = *link_settings;
-       /* TODO: should decide link spread when populating link_settings */
-       lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
-                       LINK_SPREAD_05_DOWNSPREAD_30KHZ;
-
-       lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
-       lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
-       lt_settings->eq_pattern_time = 2500;
-       lt_settings->eq_wait_time_limit = 400000;
-       lt_settings->eq_loop_count_limit = 20;
-       lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
-       lt_settings->cds_pattern_time = 2500;
-       lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count(
-                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
-       lt_settings->disallow_per_lane_settings = true;
-       lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
-       dp_hw_to_dpcd_lane_settings(lt_settings,
-                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-}
-
-enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
-{
-       enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
-
-       if (dp_is_lttpr_present(link))
-               mode = LTTPR_MODE_NON_TRANSPARENT;
-
-       DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
-       return mode;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_128b_132b.h
deleted file mode 100644 (file)
index 2147f24..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_DP_TRAINING_128B_132B_H__
-#define __DC_LINK_DP_TRAINING_128B_132B_H__
-#include "link_dp_training.h"
-
-enum link_training_result dp_perform_128b_132b_link_training(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings);
-
-void decide_128b_132b_training_settings(struct dc_link *link,
-               const struct dc_link_settings *link_settings,
-               struct link_training_settings *lt_settings);
-
-enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link);
-
-#endif /* __DC_LINK_DP_TRAINING_128B_132B_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.c
deleted file mode 100644 (file)
index ec8b619..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This file implements dp 8b/10b link training software policies and
- * sequences.
- */
-#include "link_dp_training_8b_10b.h"
-#include "link_dpcd.h"
-#include "link_dp_phy.h"
-#include "link_dp_capability.h"
-#include "dc_link_dp.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-
-static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
-               const struct dc_link_settings *link_settings)
-{
-       union training_aux_rd_interval training_rd_interval;
-       uint32_t wait_in_micro_secs = 100;
-
-       memset(&training_rd_interval, 0, sizeof(training_rd_interval));
-       if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
-                       link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
-               core_link_read_dpcd(
-                               link,
-                               DP_TRAINING_AUX_RD_INTERVAL,
-                               (uint8_t *)&training_rd_interval,
-                               sizeof(training_rd_interval));
-               if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
-                       wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
-       }
-       return wait_in_micro_secs;
-}
-
-static uint32_t get_eq_training_aux_rd_interval(
-       struct dc_link *link,
-       const struct dc_link_settings *link_settings)
-{
-       union training_aux_rd_interval training_rd_interval;
-
-       memset(&training_rd_interval, 0, sizeof(training_rd_interval));
-       if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
-               core_link_read_dpcd(
-                               link,
-                               DP_128B132B_TRAINING_AUX_RD_INTERVAL,
-                               (uint8_t *)&training_rd_interval,
-                               sizeof(training_rd_interval));
-       } else if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
-                       link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
-               core_link_read_dpcd(
-                               link,
-                               DP_TRAINING_AUX_RD_INTERVAL,
-                               (uint8_t *)&training_rd_interval,
-                               sizeof(training_rd_interval));
-       }
-
-       switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
-       case 0: return 400;
-       case 1: return 4000;
-       case 2: return 8000;
-       case 3: return 12000;
-       case 4: return 16000;
-       case 5: return 32000;
-       case 6: return 64000;
-       default: return 400;
-       }
-}
-
-void decide_8b_10b_training_settings(
-        struct dc_link *link,
-       const struct dc_link_settings *link_setting,
-       struct link_training_settings *lt_settings)
-{
-       memset(lt_settings, '\0', sizeof(struct link_training_settings));
-
-       /* Initialize link settings */
-       lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
-       lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
-       lt_settings->link_settings.link_rate = link_setting->link_rate;
-       lt_settings->link_settings.lane_count = link_setting->lane_count;
-       /* TODO hard coded to SS for now
-        * lt_settings.link_settings.link_spread =
-        * dal_display_path_is_ss_supported(
-        * path_mode->display_path) ?
-        * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
-        * LINK_SPREAD_DISABLED;
-        */
-       lt_settings->link_settings.link_spread = link->dp_ss_off ?
-                       LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
-       lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
-       lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
-       lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
-       lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
-       lt_settings->enhanced_framing = 1;
-       lt_settings->should_set_fec_ready = true;
-       lt_settings->disallow_per_lane_settings = true;
-       lt_settings->always_match_dpcd_with_hw_lane_settings = true;
-       lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
-       dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-}
-
-enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
-{
-       bool is_lttpr_present = dp_is_lttpr_present(link);
-       bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
-       bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
-
-       if (!is_lttpr_present)
-               return LTTPR_MODE_NON_LTTPR;
-
-       if (vbios_lttpr_aware) {
-               if (vbios_lttpr_force_non_transparent) {
-                       DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
-                       return LTTPR_MODE_NON_TRANSPARENT;
-               } else {
-                       DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
-                       return LTTPR_MODE_TRANSPARENT;
-               }
-       }
-
-       if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
-                       link->dc->caps.extended_aux_timeout_support) {
-               DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
-               return LTTPR_MODE_NON_TRANSPARENT;
-       }
-
-       DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
-       return LTTPR_MODE_NON_LTTPR;
-}
-
-enum link_training_result perform_8b_10b_clock_recovery_sequence(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings,
-       uint32_t offset)
-{
-       uint32_t retries_cr;
-       uint32_t retry_count;
-       uint32_t wait_time_microsec;
-       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
-       union lane_align_status_updated dpcd_lane_status_updated;
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
-       retries_cr = 0;
-       retry_count = 0;
-
-       memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
-       memset(&dpcd_lane_status_updated, '\0',
-       sizeof(dpcd_lane_status_updated));
-
-       if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
-               dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
-
-       /* najeeb - The synaptics MST hub can put the LT in
-       * infinite loop by switching the VS
-       */
-       /* between level 0 and level 1 continuously, here
-       * we try for CR lock for LinkTrainingMaxCRRetry count*/
-       while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
-               (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
-
-
-               /* 1. call HWSS to set lane settings*/
-               dp_set_hw_lane_settings(
-                               link,
-                               link_res,
-                               lt_settings,
-                               offset);
-
-               /* 2. update DPCD of the receiver*/
-               if (!retry_count)
-                       /* EPR #361076 - write as a 5-byte burst,
-                        * but only for the 1-st iteration.*/
-                       dpcd_set_lt_pattern_and_lane_settings(
-                                       link,
-                                       lt_settings,
-                                       lt_settings->pattern_for_cr,
-                                       offset);
-               else
-                       dpcd_set_lane_settings(
-                                       link,
-                                       lt_settings,
-                                       offset);
-
-               /* 3. wait receiver to lock-on*/
-               wait_time_microsec = lt_settings->cr_pattern_time;
-
-               dp_wait_for_training_aux_rd_interval(
-                               link,
-                               wait_time_microsec);
-
-               /* 4. Read lane status and requested drive
-               * settings as set by the sink
-               */
-               dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               offset);
-
-               /* 5. check CR done*/
-               if (dp_is_cr_done(lane_count, dpcd_lane_status))
-                       return LINK_TRAINING_SUCCESS;
-
-               /* 6. max VS reached*/
-               if ((link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                               DP_8b_10b_ENCODING) &&
-                               dp_is_max_vs_reached(lt_settings))
-                       break;
-
-               /* 7. same lane settings*/
-               /* Note: settings are the same for all lanes,
-                * so comparing first lane is sufficient*/
-               if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING) &&
-                               lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
-                                               dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
-                       retries_cr++;
-               else if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
-                               lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
-                                               dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
-                       retries_cr++;
-               else
-                       retries_cr = 0;
-
-               /* 8. update VS/PE/PC2 in lt_settings*/
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-               retry_count++;
-       }
-
-       if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
-               ASSERT(0);
-               DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
-                       __func__,
-                       LINK_TRAINING_MAX_CR_RETRY);
-
-       }
-
-       return dp_get_cr_failure(lane_count, dpcd_lane_status);
-}
-
-enum link_training_result perform_8b_10b_channel_equalization_sequence(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings,
-       uint32_t offset)
-{
-       enum dc_dp_training_pattern tr_pattern;
-       uint32_t retries_ch_eq;
-       uint32_t wait_time_microsec;
-       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
-       /* Note: also check that TPS4 is a supported feature*/
-       tr_pattern = lt_settings->pattern_for_eq;
-
-       if (is_repeater(lt_settings, offset) && link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
-               tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
-
-       dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
-
-       for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
-               retries_ch_eq++) {
-
-               dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
-
-               /* 2. update DPCD*/
-               if (!retries_ch_eq)
-                       /* EPR #361076 - write as a 5-byte burst,
-                        * but only for the 1-st iteration
-                        */
-
-                       dpcd_set_lt_pattern_and_lane_settings(
-                               link,
-                               lt_settings,
-                               tr_pattern, offset);
-               else
-                       dpcd_set_lane_settings(link, lt_settings, offset);
-
-               /* 3. wait for receiver to lock-on*/
-               wait_time_microsec = lt_settings->eq_pattern_time;
-
-               if (is_repeater(lt_settings, offset))
-                       wait_time_microsec =
-                                       dp_translate_training_aux_read_interval(
-                                               link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
-
-               dp_wait_for_training_aux_rd_interval(
-                               link,
-                               wait_time_microsec);
-
-               /* 4. Read lane status and requested
-                * drive settings as set by the sink*/
-
-               dp_get_lane_status_and_lane_adjust(
-                       link,
-                       lt_settings,
-                       dpcd_lane_status,
-                       &dpcd_lane_status_updated,
-                       dpcd_lane_adjust,
-                       offset);
-
-               /* 5. check CR done*/
-               if (!dp_is_cr_done(lane_count, dpcd_lane_status))
-                       return dpcd_lane_status[0].bits.CR_DONE_0 ?
-                                       LINK_TRAINING_EQ_FAIL_CR_PARTIAL :
-                                       LINK_TRAINING_EQ_FAIL_CR;
-
-               /* 6. check CHEQ done*/
-               if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
-                               dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
-                               dp_is_interlane_aligned(dpcd_lane_status_updated))
-                       return LINK_TRAINING_SUCCESS;
-
-               /* 7. update VS/PE/PC2 in lt_settings*/
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-       }
-
-       return LINK_TRAINING_EQ_FAIL_EQ;
-
-}
-
-enum link_training_result dp_perform_8b_10b_link_training(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
-
-       uint8_t repeater_cnt;
-       uint8_t repeater_id;
-       uint8_t lane = 0;
-
-       if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
-               start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
-
-       /* 1. set link rate, lane count and spread. */
-       dpcd_set_link_settings(link, lt_settings);
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
-               /* 2. perform link training (set link training done
-                *  to false is done as well)
-                */
-               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-               for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
-                               repeater_id--) {
-                       status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
-
-                       if (status != LINK_TRAINING_SUCCESS) {
-                               repeater_training_done(link, repeater_id);
-                               break;
-                       }
-
-                       status = perform_8b_10b_channel_equalization_sequence(link,
-                                       link_res,
-                                       lt_settings,
-                                       repeater_id);
-
-                       repeater_training_done(link, repeater_id);
-
-                       if (status != LINK_TRAINING_SUCCESS)
-                               break;
-
-                       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-                               lt_settings->dpcd_lane_settings[lane].raw = 0;
-                               lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
-                               lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
-                       }
-               }
-       }
-
-       if (status == LINK_TRAINING_SUCCESS) {
-               status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
-               if (status == LINK_TRAINING_SUCCESS) {
-                       status = perform_8b_10b_channel_equalization_sequence(link,
-                                       link_res,
-                                       lt_settings,
-                                       DPRX);
-               }
-       }
-
-       return status;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_8b_10b.h
deleted file mode 100644 (file)
index d26de15..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_DP_TRAINING_8B_10B_H__
-#define __DC_LINK_DP_TRAINING_8B_10B_H__
-#include "link_dp_training.h"
-
-/* to avoid infinite loop where-in the receiver
- * switches between different VS
- */
-#define LINK_TRAINING_MAX_CR_RETRY 100
-#define LINK_TRAINING_MAX_RETRY_COUNT 5
-
-enum link_training_result dp_perform_8b_10b_link_training(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings);
-
-enum link_training_result perform_8b_10b_clock_recovery_sequence(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings,
-       uint32_t offset);
-
-enum link_training_result perform_8b_10b_channel_equalization_sequence(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings,
-       uint32_t offset);
-
-enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link);
-
-void decide_8b_10b_training_settings(
-        struct dc_link *link,
-       const struct dc_link_settings *link_setting,
-       struct link_training_settings *lt_settings);
-
-#endif /* __DC_LINK_DP_TRAINING_8B_10B_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.c
deleted file mode 100644 (file)
index f84b6ea..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- *
- */
-#include "link_dp_training_auxless.h"
-#include "link_dp_phy.h"
-#include "dc_link_dp.h"
-#define DC_LOGGER \
-       link->ctx->logger
-bool dc_link_dp_perform_link_training_skip_aux(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       const struct dc_link_settings *link_setting)
-{
-       struct link_training_settings lt_settings = {0};
-
-       dp_decide_training_settings(
-                       link,
-                       link_setting,
-                       &lt_settings);
-       override_training_settings(
-                       link,
-                       &link->preferred_training_settings,
-                       &lt_settings);
-
-       /* 1. Perform_clock_recovery_sequence. */
-
-       /* transmit training pattern for clock recovery */
-       dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX);
-
-       /* call HWSS to set lane settings*/
-       dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
-
-       /* wait receiver to lock-on*/
-       dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
-
-       /* 2. Perform_channel_equalization_sequence. */
-
-       /* transmit training pattern for channel equalization. */
-       dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX);
-
-       /* call HWSS to set lane settings*/
-       dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
-
-       /* wait receiver to lock-on. */
-       dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
-
-       /* 3. Perform_link_training_int. */
-
-       /* Mainlink output idle pattern. */
-       dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-
-       dp_log_training_result(link, &lt_settings, LINK_TRAINING_SUCCESS);
-
-       return true;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_auxless.h
deleted file mode 100644 (file)
index 413999c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_DP_TRAINING_AUXLESS_H__
-#define __DC_LINK_DP_TRAINING_AUXLESS_H__
-#include "link_dp_training.h"
-
-bool dc_link_dp_perform_link_training_skip_aux(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       const struct dc_link_settings *link_setting);
-#endif /* __DC_LINK_DP_TRAINING_AUXLESS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.c
deleted file mode 100644 (file)
index cf47db1..0000000
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This module implements functionality for training DPIA links.
- */
-#include "link_dp_training_dpia.h"
-#include "dc.h"
-#include "inc/core_status.h"
-#include "dc_link.h"
-#include "dc_link_dp.h"
-#include "dpcd_defs.h"
-
-#include "link_dp_dpia.h"
-#include "link_hwss.h"
-#include "dm_helpers.h"
-#include "dmub/inc/dmub_cmd.h"
-#include "link_dpcd.h"
-#include "link_dp_training_8b_10b.h"
-#include "link_dp_capability.h"
-#include "dc_dmub_srv.h"
-#define DC_LOGGER \
-       link->ctx->logger
-
-/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */
-#define DPIA_CLK_SYNC_DELAY 16000
-
-/* Extend interval between training status checks for manual testing. */
-#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000
-
-/* SET_CONFIG message types sent by driver. */
-enum dpia_set_config_type {
-       DPIA_SET_CFG_SET_LINK = 0x01,
-       DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05,
-       DPIA_SET_CFG_SET_TRAINING = 0x18,
-       DPIA_SET_CFG_SET_VSPE = 0x19
-};
-
-/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */
-enum dpia_set_config_ts {
-       DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */
-       DPIA_TS_TPS1 = 0x01,
-       DPIA_TS_TPS2 = 0x02,
-       DPIA_TS_TPS3 = 0x03,
-       DPIA_TS_TPS4 = 0x07,
-       DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */
-};
-
-/* SET_CONFIG message data associated with messages sent by driver. */
-union dpia_set_config_data {
-       struct {
-               uint8_t mode : 1;
-               uint8_t reserved : 7;
-       } set_link;
-       struct {
-               uint8_t stage;
-       } set_training;
-       struct {
-               uint8_t swing : 2;
-               uint8_t max_swing_reached : 1;
-               uint8_t pre_emph : 2;
-               uint8_t max_pre_emph_reached : 1;
-               uint8_t reserved : 2;
-       } set_vspe;
-       uint8_t raw;
-};
-
-
-/* Configure link as prescribed in link_setting; set LTTPR mode; and
- * Initialize link training settings.
- * Abort link training if sink unplug detected.
- *
- * @param link DPIA link being trained.
- * @param[in] link_setting Lane count, link rate and downspread control.
- * @param[out] lt_settings Link settings and drive settings (voltage swing and pre-emphasis).
- */
-static enum link_training_result dpia_configure_link(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct dc_link_settings *link_setting,
-               struct link_training_settings *lt_settings)
-{
-       enum dc_status status;
-       bool fec_enable;
-
-       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               lt_settings->lttpr_mode);
-
-       dp_decide_training_settings(
-               link,
-               link_setting,
-               lt_settings);
-
-       dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
-
-       status = dpcd_configure_channel_coding(link, lt_settings);
-       if (status != DC_OK && link->is_hpd_pending)
-               return LINK_TRAINING_ABORT;
-
-       /* Configure lttpr mode */
-       status = dpcd_configure_lttpr_mode(link, lt_settings);
-       if (status != DC_OK && link->is_hpd_pending)
-               return LINK_TRAINING_ABORT;
-
-       /* Set link rate, lane count and spread. */
-       status = dpcd_set_link_settings(link, lt_settings);
-       if (status != DC_OK && link->is_hpd_pending)
-               return LINK_TRAINING_ABORT;
-
-       if (link->preferred_training_settings.fec_enable != NULL)
-               fec_enable = *link->preferred_training_settings.fec_enable;
-       else
-               fec_enable = true;
-       status = dp_set_fec_ready(link, link_res, fec_enable);
-       if (status != DC_OK && link->is_hpd_pending)
-               return LINK_TRAINING_ABORT;
-
-       return LINK_TRAINING_SUCCESS;
-}
-
-static enum dc_status core_link_send_set_config(
-       struct dc_link *link,
-       uint8_t msg_type,
-       uint8_t msg_data)
-{
-       struct set_config_cmd_payload payload;
-       enum set_config_status set_config_result = SET_CONFIG_PENDING;
-
-       /* prepare set_config payload */
-       payload.msg_type = msg_type;
-       payload.msg_data = msg_data;
-
-       if (!link->ddc->ddc_pin && !link->aux_access_disabled &&
-                       (dm_helpers_dmub_set_config_sync(link->ctx,
-                       link, &payload, &set_config_result) == -1)) {
-               return DC_ERROR_UNEXPECTED;
-       }
-
-       /* set_config should return ACK if successful */
-       return (set_config_result == SET_CONFIG_ACK_RECEIVED) ? DC_OK : DC_ERROR_UNEXPECTED;
-}
-
-/* Build SET_CONFIG message data payload for specified message type. */
-static uint8_t dpia_build_set_config_data(
-               enum dpia_set_config_type type,
-               struct dc_link *link,
-               struct link_training_settings *lt_settings)
-{
-       union dpia_set_config_data data;
-
-       data.raw = 0;
-
-       switch (type) {
-       case DPIA_SET_CFG_SET_LINK:
-               data.set_link.mode = lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT ? 1 : 0;
-               break;
-       case DPIA_SET_CFG_SET_PHY_TEST_MODE:
-               break;
-       case DPIA_SET_CFG_SET_VSPE:
-               /* Assume all lanes have same drive settings. */
-               data.set_vspe.swing = lt_settings->hw_lane_settings[0].VOLTAGE_SWING;
-               data.set_vspe.pre_emph = lt_settings->hw_lane_settings[0].PRE_EMPHASIS;
-               data.set_vspe.max_swing_reached =
-                               lt_settings->hw_lane_settings[0].VOLTAGE_SWING == VOLTAGE_SWING_MAX_LEVEL ? 1 : 0;
-               data.set_vspe.max_pre_emph_reached =
-                               lt_settings->hw_lane_settings[0].PRE_EMPHASIS == PRE_EMPHASIS_MAX_LEVEL ? 1 : 0;
-               break;
-       default:
-               ASSERT(false); /* Message type not supported by helper function. */
-               break;
-       }
-
-       return data.raw;
-}
-
-/* Convert DC training pattern to DPIA training stage. */
-static enum dc_status convert_trng_ptn_to_trng_stg(enum dc_dp_training_pattern tps, enum dpia_set_config_ts *ts)
-{
-       enum dc_status status = DC_OK;
-
-       switch (tps) {
-       case DP_TRAINING_PATTERN_SEQUENCE_1:
-               *ts = DPIA_TS_TPS1;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_2:
-               *ts = DPIA_TS_TPS2;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_3:
-               *ts = DPIA_TS_TPS3;
-               break;
-       case DP_TRAINING_PATTERN_SEQUENCE_4:
-               *ts = DPIA_TS_TPS4;
-               break;
-       case DP_TRAINING_PATTERN_VIDEOIDLE:
-               *ts = DPIA_TS_DPRX_DONE;
-               break;
-       default: /* TPS not supported by helper function. */
-               ASSERT(false);
-               *ts = DPIA_TS_DPRX_DONE;
-               status = DC_UNSUPPORTED_VALUE;
-               break;
-       }
-
-       return status;
-}
-
-/* Write training pattern to DPCD. */
-static enum dc_status dpcd_set_lt_pattern(
-       struct dc_link *link,
-       enum dc_dp_training_pattern pattern,
-       uint32_t hop)
-{
-       union dpcd_training_pattern dpcd_pattern = {0};
-       uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
-       enum dc_status status;
-
-       if (hop != DPRX)
-               dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
-                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
-
-       /* DpcdAddress_TrainingPatternSet */
-       dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
-               dp_training_pattern_to_dpcd_training_pattern(link, pattern);
-
-       dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
-               dp_initialize_scrambling_data_symbols(link, pattern);
-
-       if (hop != DPRX) {
-               DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
-                       __func__,
-                       hop,
-                       dpcd_tps_offset,
-                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-       } else {
-               DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
-                       __func__,
-                       dpcd_tps_offset,
-                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-       }
-
-       status = core_link_write_dpcd(
-                       link,
-                       dpcd_tps_offset,
-                       &dpcd_pattern.raw,
-                       sizeof(dpcd_pattern.raw));
-
-       return status;
-}
-
-/* Execute clock recovery phase of link training for specified hop in display
- * path.in non-transparent mode:
- * - Driver issues both DPCD and SET_CONFIG transactions.
- * - TPS1 is transmitted for any hops downstream of DPOA.
- * - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
- * - CR for the first hop (DPTX-to-DPIA) is assumed to be successful.
- *
- * @param link DPIA link being trained.
- * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop Hop in display path. DPRX = 0.
- */
-static enum link_training_result dpia_training_cr_non_transparent(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
-       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
-       enum dc_status status;
-       uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
-       uint32_t retry_count = 0;
-       uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL; /* From DP spec, CR read interval is always 100us. */
-       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-       uint8_t set_cfg_data;
-       enum dpia_set_config_ts ts;
-
-       repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-       /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
-        * Fix inherited from perform_clock_recovery_sequence() -
-        * the DP equivalent of this function:
-        * Required for Synaptics MST hub which can put the LT in
-        * infinite loop by switching the VS between level 0 and level 1
-        * continuously.
-        */
-       while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
-                       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
-
-               /* DPTX-to-DPIA */
-               if (hop == repeater_cnt) {
-                       /* Send SET_CONFIG(SET_LINK:LC,LR,LTTPR) to notify DPOA that
-                        * non-transparent link training has started.
-                        * This also enables the transmission of clk_sync packets.
-                        */
-                       set_cfg_data = dpia_build_set_config_data(
-                                       DPIA_SET_CFG_SET_LINK,
-                                       link,
-                                       lt_settings);
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_LINK,
-                                       set_cfg_data);
-                       /* CR for this hop is considered successful as long as
-                        * SET_CONFIG message is acknowledged by DPOA.
-                        */
-                       if (status == DC_OK)
-                               result = LINK_TRAINING_SUCCESS;
-                       else
-                               result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               /* DPOA-to-x */
-               /* Instruct DPOA to transmit TPS1 then update DPCD. */
-               if (retry_count == 0) {
-                       status = convert_trng_ptn_to_trng_stg(lt_settings->pattern_for_cr, &ts);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_TRAINING,
-                                       ts);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-                       status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, hop);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-               }
-
-               /* Update DPOA drive settings then DPCD. DPOA does only adjusts
-                * drive settings for hops immediately downstream.
-                */
-               if (hop == repeater_cnt - 1) {
-                       set_cfg_data = dpia_build_set_config_data(
-                                       DPIA_SET_CFG_SET_VSPE,
-                                       link,
-                                       lt_settings);
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_VSPE,
-                                       set_cfg_data);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-               }
-               status = dpcd_set_lane_settings(link, lt_settings, hop);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
-
-               /* Read status and adjustment requests from DPCD. */
-               status = dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               hop);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               /* Check if clock recovery successful. */
-               if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
-                       result = LINK_TRAINING_SUCCESS;
-                       break;
-               }
-
-               result = dp_get_cr_failure(lane_count, dpcd_lane_status);
-
-               if (dp_is_max_vs_reached(lt_settings))
-                       break;
-
-               /* Count number of attempts with same drive settings.
-                * Note: settings are the same for all lanes,
-                * so comparing first lane is sufficient.
-                */
-               if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
-                               dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
-                               && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
-                                               dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
-                       retries_cr++;
-               else
-                       retries_cr = 0;
-
-               /* Update VS/PE. */
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings,
-                               lt_settings->dpcd_lane_settings);
-               retry_count++;
-       }
-
-       /* Abort link training if clock recovery failed due to HPD unplug. */
-       if (link->is_hpd_pending)
-               result = LINK_TRAINING_ABORT;
-
-       DC_LOG_HW_LINK_TRAINING(
-               "%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n - status(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               hop,
-               result,
-               retry_count,
-               status);
-
-       return result;
-}
-
-/* Execute clock recovery phase of link training in transparent LTTPR mode:
- * - Driver only issues DPCD transactions and leaves USB4 tunneling (SET_CONFIG) messages to DPIA.
- * - Driver writes TPS1 to DPCD to kick off training.
- * - Clock recovery (CR) for link is handled by DPOA, which reports result to DPIA on completion.
- * - DPIA communicates result to driver by updating CR status when driver reads DPCD.
- *
- * @param link DPIA link being trained.
- * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- */
-static enum link_training_result dpia_training_cr_transparent(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
-       enum dc_status status;
-       uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
-       uint32_t retry_count = 0;
-       uint32_t wait_time_microsec = lt_settings->cr_pattern_time;
-       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
-       /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
-        * Fix inherited from perform_clock_recovery_sequence() -
-        * the DP equivalent of this function:
-        * Required for Synaptics MST hub which can put the LT in
-        * infinite loop by switching the VS between level 0 and level 1
-        * continuously.
-        */
-       while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
-                       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
-
-               /* Write TPS1 (not VS or PE) to DPCD to start CR phase.
-                * DPIA sends SET_CONFIG(SET_LINK) to notify DPOA to
-                * start link training.
-                */
-               if (retry_count == 0) {
-                       status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, DPRX);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-               }
-
-               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
-
-               /* Read status and adjustment requests from DPCD. */
-               status = dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               DPRX);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               /* Check if clock recovery successful. */
-               if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
-                       result = LINK_TRAINING_SUCCESS;
-                       break;
-               }
-
-               result = dp_get_cr_failure(lane_count, dpcd_lane_status);
-
-               if (dp_is_max_vs_reached(lt_settings))
-                       break;
-
-               /* Count number of attempts with same drive settings.
-                * Note: settings are the same for all lanes,
-                * so comparing first lane is sufficient.
-                */
-               if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
-                               dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
-                               && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
-                                               dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
-                       retries_cr++;
-               else
-                       retries_cr = 0;
-
-               /* Update VS/PE. */
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-               retry_count++;
-       }
-
-       /* Abort link training if clock recovery failed due to HPD unplug. */
-       if (link->is_hpd_pending)
-               result = LINK_TRAINING_ABORT;
-
-       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               DPRX,
-               result,
-               retry_count);
-
-       return result;
-}
-
-/* Execute clock recovery phase of link training for specified hop in display
- * path.
- *
- * @param link DPIA link being trained.
- * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop Hop in display path. DPRX = 0.
- */
-static enum link_training_result dpia_training_cr_phase(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
-               result = dpia_training_cr_non_transparent(link, link_res, lt_settings, hop);
-       else
-               result = dpia_training_cr_transparent(link, link_res, lt_settings);
-
-       return result;
-}
-
-/* Return status read interval during equalization phase. */
-static uint32_t dpia_get_eq_aux_rd_interval(
-               const struct dc_link *link,
-               const struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       uint32_t wait_time_microsec;
-
-       if (hop == DPRX)
-               wait_time_microsec = lt_settings->eq_pattern_time;
-       else
-               wait_time_microsec =
-                               dp_translate_training_aux_read_interval(
-                                       link->dpcd_caps.lttpr_caps.aux_rd_interval[hop - 1]);
-
-       /* Check debug option for extending aux read interval. */
-       if (link->dc->debug.dpia_debug.bits.extend_aux_rd_interval)
-               wait_time_microsec = DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US;
-
-       return wait_time_microsec;
-}
-
-/* Execute equalization phase of link training for specified hop in display
- * path in non-transparent mode:
- * - driver issues both DPCD and SET_CONFIG transactions.
- * - TPSx is transmitted for any hops downstream of DPOA.
- * - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
- * - EQ for the first hop (DPTX-to-DPIA) is assumed to be successful.
- * - DPRX EQ only reported successful when both DPRX and DPIA requirements (clk sync packets sent) fulfilled.
- *
- * @param link DPIA link being trained.
- * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop Hop in display path. DPRX = 0.
- */
-static enum link_training_result dpia_training_eq_non_transparent(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
-       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
-       uint32_t retries_eq = 0;
-       enum dc_status status;
-       enum dc_dp_training_pattern tr_pattern;
-       uint32_t wait_time_microsec;
-       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-       uint8_t set_cfg_data;
-       enum dpia_set_config_ts ts;
-
-       /* Training pattern is TPS4 for repeater;
-        * TPS2/3/4 for DPRX depending on what it supports.
-        */
-       if (hop == DPRX)
-               tr_pattern = lt_settings->pattern_for_eq;
-       else
-               tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
-
-       repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-       for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
-
-               /* DPTX-to-DPIA equalization always successful. */
-               if (hop == repeater_cnt) {
-                       result = LINK_TRAINING_SUCCESS;
-                       break;
-               }
-
-               /* Instruct DPOA to transmit TPSn then update DPCD. */
-               if (retries_eq == 0) {
-                       status = convert_trng_ptn_to_trng_stg(tr_pattern, &ts);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_TRAINING,
-                                       ts);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-                       status = dpcd_set_lt_pattern(link, tr_pattern, hop);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-               }
-
-               /* Update DPOA drive settings then DPCD. DPOA only adjusts
-                * drive settings for hop immediately downstream.
-                */
-               if (hop == repeater_cnt - 1) {
-                       set_cfg_data = dpia_build_set_config_data(
-                                       DPIA_SET_CFG_SET_VSPE,
-                                       link,
-                                       lt_settings);
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_VSPE,
-                                       set_cfg_data);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-               }
-               status = dpcd_set_lane_settings(link, lt_settings, hop);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               /* Extend wait time on second equalisation attempt on final hop to
-                * ensure clock sync packets have been sent.
-                */
-               if (hop == DPRX && retries_eq == 1)
-                       wait_time_microsec = max(wait_time_microsec, (uint32_t) DPIA_CLK_SYNC_DELAY);
-               else
-                       wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, hop);
-
-               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
-
-               /* Read status and adjustment requests from DPCD. */
-               status = dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               hop);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               /* CR can still fail during EQ phase. Fail training if CR fails. */
-               if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
-                       result = LINK_TRAINING_EQ_FAIL_CR;
-                       break;
-               }
-
-               if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
-                               dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
-                               dp_is_interlane_aligned(dpcd_lane_status_updated)) {
-                       result =  LINK_TRAINING_SUCCESS;
-                       break;
-               }
-
-               /* Update VS/PE. */
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-       }
-
-       /* Abort link training if equalization failed due to HPD unplug. */
-       if (link->is_hpd_pending)
-               result = LINK_TRAINING_ABORT;
-
-       DC_LOG_HW_LINK_TRAINING(
-               "%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n - status(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               hop,
-               result,
-               retries_eq,
-               status);
-
-       return result;
-}
-
-/* Execute equalization phase of link training for specified hop in display
- * path in transparent LTTPR mode:
- * - driver only issues DPCD transactions leaves USB4 tunneling (SET_CONFIG) messages to DPIA.
- * - driver writes TPSx to DPCD to notify DPIA that is in equalization phase.
- * - equalization (EQ) for link is handled by DPOA, which reports result to DPIA on completion.
- * - DPIA communicates result to driver by updating EQ status when driver reads DPCD.
- *
- * @param link DPIA link being trained.
- * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop Hop in display path. DPRX = 0.
- */
-static enum link_training_result dpia_training_eq_transparent(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
-       uint32_t retries_eq = 0;
-       enum dc_status status;
-       enum dc_dp_training_pattern tr_pattern = lt_settings->pattern_for_eq;
-       uint32_t wait_time_microsec;
-       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-       union lane_align_status_updated dpcd_lane_status_updated = {0};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
-       wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX);
-
-       for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
-
-               if (retries_eq == 0) {
-                       status = dpcd_set_lt_pattern(link, tr_pattern, DPRX);
-                       if (status != DC_OK) {
-                               result = LINK_TRAINING_ABORT;
-                               break;
-                       }
-               }
-
-               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
-
-               /* Read status and adjustment requests from DPCD. */
-               status = dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               DPRX);
-               if (status != DC_OK) {
-                       result = LINK_TRAINING_ABORT;
-                       break;
-               }
-
-               /* CR can still fail during EQ phase. Fail training if CR fails. */
-               if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
-                       result = LINK_TRAINING_EQ_FAIL_CR;
-                       break;
-               }
-
-               if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
-                               dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status)) {
-                       /* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4
-                        * has to share encoders unlike DP and USBC
-                        */
-                       if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->is_automated && retries_eq)) {
-                               result =  LINK_TRAINING_SUCCESS;
-                               break;
-                       }
-               }
-
-               /* Update VS/PE. */
-               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-       }
-
-       /* Abort link training if equalization failed due to HPD unplug. */
-       if (link->is_hpd_pending)
-               result = LINK_TRAINING_ABORT;
-
-       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               DPRX,
-               result,
-               retries_eq);
-
-       return result;
-}
-
-/* Execute equalization phase of link training for specified hop in display
- * path.
- *
- * @param link DPIA link being trained.
- * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop Hop in display path. DPRX = 0.
- */
-static enum link_training_result dpia_training_eq_phase(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       enum link_training_result result;
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
-               result = dpia_training_eq_non_transparent(link, link_res, lt_settings, hop);
-       else
-               result = dpia_training_eq_transparent(link, link_res, lt_settings);
-
-       return result;
-}
-
-/* End training of specified hop in display path. */
-static enum dc_status dpcd_clear_lt_pattern(
-       struct dc_link *link,
-       uint32_t hop)
-{
-       union dpcd_training_pattern dpcd_pattern = {0};
-       uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
-       enum dc_status status;
-
-       if (hop != DPRX)
-               dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
-                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
-
-       status = core_link_write_dpcd(
-                       link,
-                       dpcd_tps_offset,
-                       &dpcd_pattern.raw,
-                       sizeof(dpcd_pattern.raw));
-
-       return status;
-}
-
-/* End training of specified hop in display path.
- *
- * In transparent LTTPR mode:
- * - driver clears training pattern for the specified hop in DPCD.
- * In non-transparent LTTPR mode:
- * - in addition to clearing training pattern, driver issues USB4 tunneling
- * (SET_CONFIG) messages to notify DPOA when training is done for first hop
- * (DPTX-to-DPIA) and last hop (DPRX).
- *
- * @param link DPIA link being trained.
- * @param hop Hop in display path. DPRX = 0.
- */
-static enum link_training_result dpia_training_end(
-               struct dc_link *link,
-               struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       enum link_training_result result = LINK_TRAINING_SUCCESS;
-       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
-       enum dc_status status;
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
-               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-               if (hop == repeater_cnt) { /* DPTX-to-DPIA */
-                       /* Send SET_CONFIG(SET_TRAINING:0xff) to notify DPOA that
-                        * DPTX-to-DPIA hop trained. No DPCD write needed for first hop.
-                        */
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_TRAINING,
-                                       DPIA_TS_UFP_DONE);
-                       if (status != DC_OK)
-                               result = LINK_TRAINING_ABORT;
-               } else { /* DPOA-to-x */
-                       /* Write 0x0 to TRAINING_PATTERN_SET */
-                       status = dpcd_clear_lt_pattern(link, hop);
-                       if (status != DC_OK)
-                               result = LINK_TRAINING_ABORT;
-               }
-
-               /* Notify DPOA that non-transparent link training of DPRX done. */
-               if (hop == DPRX && result != LINK_TRAINING_ABORT) {
-                       status = core_link_send_set_config(
-                                       link,
-                                       DPIA_SET_CFG_SET_TRAINING,
-                                       DPIA_TS_DPRX_DONE);
-                       if (status != DC_OK)
-                               result = LINK_TRAINING_ABORT;
-               }
-
-       } else { /* non-LTTPR or transparent LTTPR. */
-
-               /* Write 0x0 to TRAINING_PATTERN_SET */
-               status = dpcd_clear_lt_pattern(link, hop);
-               if (status != DC_OK)
-                       result = LINK_TRAINING_ABORT;
-
-       }
-
-       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) end\n - hop(%d)\n - result(%d)\n - LTTPR mode(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               hop,
-               result,
-               lt_settings->lttpr_mode);
-
-       return result;
-}
-
-/* When aborting training of specified hop in display path, clean up by:
- * - Attempting to clear DPCD TRAINING_PATTERN_SET, LINK_BW_SET and LANE_COUNT_SET.
- * - Sending SET_CONFIG(SET_LINK) with lane count and link rate set to 0.
- *
- * @param link DPIA link being trained.
- * @param hop Hop in display path. DPRX = 0.
- */
-static void dpia_training_abort(
-               struct dc_link *link,
-               struct link_training_settings *lt_settings,
-               uint32_t hop)
-{
-       uint8_t data = 0;
-       uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
-
-       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n",
-               __func__,
-               link->link_id.enum_id - ENUM_ID_1,
-               lt_settings->lttpr_mode,
-               link->is_hpd_pending);
-
-       /* Abandon clean-up if sink unplugged. */
-       if (link->is_hpd_pending)
-               return;
-
-       if (hop != DPRX)
-               dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
-                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
-
-       core_link_write_dpcd(link, dpcd_tps_offset, &data, 1);
-       core_link_write_dpcd(link, DP_LINK_BW_SET, &data, 1);
-       core_link_write_dpcd(link, DP_LANE_COUNT_SET, &data, 1);
-       core_link_send_set_config(link, DPIA_SET_CFG_SET_LINK, data);
-}
-
-enum link_training_result dc_link_dpia_perform_link_training(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       const struct dc_link_settings *link_setting,
-       bool skip_video_pattern)
-{
-       enum link_training_result result;
-       struct link_training_settings lt_settings = {0};
-       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
-       int8_t repeater_id; /* Current hop. */
-
-       struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in
-
-       lt_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link_settings);
-
-       /* Configure link as prescribed in link_setting and set LTTPR mode. */
-       result = dpia_configure_link(link, link_res, link_setting, &lt_settings);
-       if (result != LINK_TRAINING_SUCCESS)
-               return result;
-
-       if (lt_settings.lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
-               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-       /* Train each hop in turn starting with the one closest to DPTX.
-        * In transparent or non-LTTPR mode, train only the final hop (DPRX).
-        */
-       for (repeater_id = repeater_cnt; repeater_id >= 0; repeater_id--) {
-               /* Clock recovery. */
-               result = dpia_training_cr_phase(link, link_res, &lt_settings, repeater_id);
-               if (result != LINK_TRAINING_SUCCESS)
-                       break;
-
-               /* Equalization. */
-               result = dpia_training_eq_phase(link, link_res, &lt_settings, repeater_id);
-               if (result != LINK_TRAINING_SUCCESS)
-                       break;
-
-               /* Stop training hop. */
-               result = dpia_training_end(link, &lt_settings, repeater_id);
-               if (result != LINK_TRAINING_SUCCESS)
-                       break;
-       }
-
-       /* Double-check link status if training successful; gracefully abort
-        * training of current hop if training failed due to message tunneling
-        * failure; end training of hop if training ended conventionally and
-        * falling back to lower bandwidth settings possible.
-        */
-       if (result == LINK_TRAINING_SUCCESS) {
-               msleep(5);
-               if (!link->is_automated)
-                       result = dp_check_link_loss_status(link, &lt_settings);
-       } else if (result == LINK_TRAINING_ABORT)
-               dpia_training_abort(link, &lt_settings, repeater_id);
-       else
-               dpia_training_end(link, &lt_settings, repeater_id);
-
-       return result;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_dpia.h
deleted file mode 100644 (file)
index 0150f29..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_DP_TRAINING_DPIA_H__
-#define __DC_LINK_DP_TRAINING_DPIA_H__
-#include "link_dp_training.h"
-
-/* Train DP tunneling link for USB4 DPIA display endpoint.
- * DPIA equivalent of dc_link_dp_perfrorm_link_training.
- * Aborts link training upon detection of sink unplug.
- */
-enum link_training_result dc_link_dpia_perform_link_training(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       const struct dc_link_settings *link_setting,
-       bool skip_video_pattern);
-
-#endif /* __DC_LINK_DP_TRAINING_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.c
deleted file mode 100644 (file)
index 860b5ee..0000000
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- * This file implements 8b/10b link training specially modified to support an
- * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
- * Unlike native dp connection this chip requires a modified link training
- * protocol based on 8b/10b link training. Since this is a non standard sequence
- * and we must support this hardware, we decided to isolate it in its own
- * training sequence inside its own file.
- */
-#include "link_dp_training_fixed_vs_pe_retimer.h"
-#include "link_dp_training_8b_10b.h"
-#include "link_dpcd.h"
-#include "link_dp_phy.h"
-#include "link_dp_capability.h"
-#include "dc_link_dp.h"
-
-#define DC_LOGGER \
-       link->ctx->logger
-
-void dp_fixed_vs_pe_read_lane_adjust(
-       struct dc_link *link,
-       union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
-{
-       const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
-       const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
-       const uint8_t offset = dp_parse_lttpr_repeater_count(
-                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-       uint32_t vendor_lttpr_write_address = 0xF004F;
-       uint32_t vendor_lttpr_read_address = 0xF0053;
-       uint8_t dprx_vs = 0;
-       uint8_t dprx_pe = 0;
-       uint8_t lane;
-
-       if (offset != 0xFF) {
-               vendor_lttpr_write_address +=
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-               vendor_lttpr_read_address +=
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-       }
-
-       /* W/A to read lane settings requested by DPRX */
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_vs[0],
-                       sizeof(vendor_lttpr_write_data_vs));
-       core_link_read_dpcd(
-                       link,
-                       vendor_lttpr_read_address,
-                       &dprx_vs,
-                       1);
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_pe[0],
-                       sizeof(vendor_lttpr_write_data_pe));
-       core_link_read_dpcd(
-                       link,
-                       vendor_lttpr_read_address,
-                       &dprx_pe,
-                       1);
-
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET  = (dprx_vs >> (2 * lane)) & 0x3;
-               dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
-       }
-}
-
-
-void dp_fixed_vs_pe_set_retimer_lane_settings(
-       struct dc_link *link,
-       const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
-       uint8_t lane_count)
-{
-       const uint8_t offset = dp_parse_lttpr_repeater_count(
-                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-       const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
-       uint32_t vendor_lttpr_write_address = 0xF004F;
-       uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
-       uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
-       uint8_t lane = 0;
-
-       if (offset != 0xFF) {
-               vendor_lttpr_write_address +=
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-       }
-
-       for (lane = 0; lane < lane_count; lane++) {
-               vendor_lttpr_write_data_vs[3] |=
-                               dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
-               vendor_lttpr_write_data_pe[3] |=
-                               dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
-       }
-
-       /* Force LTTPR to output desired VS and PE */
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_reset[0],
-                       sizeof(vendor_lttpr_write_data_reset));
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_vs[0],
-                       sizeof(vendor_lttpr_write_data_vs));
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_pe[0],
-                       sizeof(vendor_lttpr_write_data_pe));
-}
-
-static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
-               struct dc_link *link,
-               const struct link_resource *link_res,
-               struct link_training_settings *lt_settings)
-{
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
-       uint8_t lane = 0;
-       uint8_t toggle_rate = 0x6;
-       uint8_t target_rate = 0x6;
-       bool apply_toggle_rate_wa = false;
-       uint8_t repeater_cnt;
-       uint8_t repeater_id;
-
-       /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
-       if (lt_settings->cr_pattern_time < 16000)
-               lt_settings->cr_pattern_time = 16000;
-
-       /* Fixed VS/PE specific: Toggle link rate */
-       apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate);
-       target_rate = get_dpcd_link_rate(&lt_settings->link_settings);
-       toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
-
-       if (apply_toggle_rate_wa)
-               lt_settings->link_settings.link_rate = toggle_rate;
-
-       if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
-               start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
-
-       /* 1. set link rate, lane count and spread. */
-       dpcd_set_link_settings(link, lt_settings);
-
-       /* Fixed VS/PE specific: Toggle link rate back*/
-       if (apply_toggle_rate_wa) {
-               core_link_write_dpcd(
-                               link,
-                               DP_LINK_BW_SET,
-                               &target_rate,
-                               1);
-       }
-
-       link->vendor_specific_lttpr_link_rate_wa = target_rate;
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
-               /* 2. perform link training (set link training done
-                *  to false is done as well)
-                */
-               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
-               for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
-                               repeater_id--) {
-                       status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
-
-                       if (status != LINK_TRAINING_SUCCESS) {
-                               repeater_training_done(link, repeater_id);
-                               break;
-                       }
-
-                       status = perform_8b_10b_channel_equalization_sequence(link,
-                                       link_res,
-                                       lt_settings,
-                                       repeater_id);
-
-                       repeater_training_done(link, repeater_id);
-
-                       if (status != LINK_TRAINING_SUCCESS)
-                               break;
-
-                       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-                               lt_settings->dpcd_lane_settings[lane].raw = 0;
-                               lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
-                               lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
-                       }
-               }
-       }
-
-       if (status == LINK_TRAINING_SUCCESS) {
-               status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
-               if (status == LINK_TRAINING_SUCCESS) {
-                       status = perform_8b_10b_channel_equalization_sequence(link,
-                                                                      link_res,
-                                                                      lt_settings,
-                                                                      DPRX);
-               }
-       }
-
-       return status;
-}
-
-
-enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings)
-{
-       const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
-       const uint8_t offset = dp_parse_lttpr_repeater_count(
-                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-       const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
-       const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
-       uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
-       uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
-       uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
-       uint32_t vendor_lttpr_write_address = 0xF004F;
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
-       uint8_t lane = 0;
-       union down_spread_ctrl downspread = {0};
-       union lane_count_set lane_count_set = {0};
-       uint8_t toggle_rate;
-       uint8_t rate;
-
-       /* Only 8b/10b is supported */
-       ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
-                       DP_8b_10b_ENCODING);
-
-       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-               status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
-               return status;
-       }
-
-       if (offset != 0xFF) {
-               vendor_lttpr_write_address +=
-                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
-               /* Certain display and cable configuration require extra delay */
-               if (offset > 2)
-                       pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
-       }
-
-       /* Vendor specific: Reset lane settings */
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_reset[0],
-                       sizeof(vendor_lttpr_write_data_reset));
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_vs[0],
-                       sizeof(vendor_lttpr_write_data_vs));
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_pe[0],
-                       sizeof(vendor_lttpr_write_data_pe));
-
-       /* Vendor specific: Enable intercept */
-       core_link_write_dpcd(
-                       link,
-                       vendor_lttpr_write_address,
-                       &vendor_lttpr_write_data_intercept_en[0],
-                       sizeof(vendor_lttpr_write_data_intercept_en));
-
-       /* 1. set link rate, lane count and spread. */
-
-       downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
-
-       lane_count_set.bits.LANE_COUNT_SET =
-       lt_settings->link_settings.lane_count;
-
-       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
-       lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
-
-
-       if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
-               lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
-                               link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
-       }
-
-       core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
-               &downspread.raw, sizeof(downspread));
-
-       core_link_write_dpcd(link, DP_LANE_COUNT_SET,
-               &lane_count_set.raw, 1);
-
-       rate = get_dpcd_link_rate(&lt_settings->link_settings);
-
-       /* Vendor specific: Toggle link rate */
-       toggle_rate = (rate == 0x6) ? 0xA : 0x6;
-
-       if (link->vendor_specific_lttpr_link_rate_wa == rate) {
-               core_link_write_dpcd(
-                               link,
-                               DP_LINK_BW_SET,
-                               &toggle_rate,
-                               1);
-       }
-
-       link->vendor_specific_lttpr_link_rate_wa = rate;
-
-       core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
-
-       DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
-               __func__,
-               DP_LINK_BW_SET,
-               lt_settings->link_settings.link_rate,
-               DP_LANE_COUNT_SET,
-               lt_settings->link_settings.lane_count,
-               lt_settings->enhanced_framing,
-               DP_DOWNSPREAD_CTRL,
-               lt_settings->link_settings.link_spread);
-
-       /* 2. Perform link training */
-
-       /* Perform Clock Recovery Sequence */
-       if (status == LINK_TRAINING_SUCCESS) {
-               const uint8_t max_vendor_dpcd_retries = 10;
-               uint32_t retries_cr;
-               uint32_t retry_count;
-               uint32_t wait_time_microsec;
-               enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-               union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
-               union lane_align_status_updated dpcd_lane_status_updated;
-               union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-               enum dc_status dpcd_status = DC_OK;
-               uint8_t i = 0;
-
-               retries_cr = 0;
-               retry_count = 0;
-
-               memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
-               memset(&dpcd_lane_status_updated, '\0',
-               sizeof(dpcd_lane_status_updated));
-
-               while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
-                       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
-
-
-                       /* 1. call HWSS to set lane settings */
-                       dp_set_hw_lane_settings(
-                                       link,
-                                       link_res,
-                                       lt_settings,
-                                       0);
-
-                       /* 2. update DPCD of the receiver */
-                       if (!retry_count) {
-                               /* EPR #361076 - write as a 5-byte burst,
-                                * but only for the 1-st iteration.
-                                */
-                               dpcd_set_lt_pattern_and_lane_settings(
-                                               link,
-                                               lt_settings,
-                                               lt_settings->pattern_for_cr,
-                                               0);
-                               /* Vendor specific: Disable intercept */
-                               for (i = 0; i < max_vendor_dpcd_retries; i++) {
-                                       msleep(pre_disable_intercept_delay_ms);
-                                       dpcd_status = core_link_write_dpcd(
-                                                       link,
-                                                       vendor_lttpr_write_address,
-                                                       &vendor_lttpr_write_data_intercept_dis[0],
-                                                       sizeof(vendor_lttpr_write_data_intercept_dis));
-
-                                       if (dpcd_status == DC_OK)
-                                               break;
-
-                                       core_link_write_dpcd(
-                                                       link,
-                                                       vendor_lttpr_write_address,
-                                                       &vendor_lttpr_write_data_intercept_en[0],
-                                                       sizeof(vendor_lttpr_write_data_intercept_en));
-                               }
-                       } else {
-                               vendor_lttpr_write_data_vs[3] = 0;
-                               vendor_lttpr_write_data_pe[3] = 0;
-
-                               for (lane = 0; lane < lane_count; lane++) {
-                                       vendor_lttpr_write_data_vs[3] |=
-                                                       lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
-                                       vendor_lttpr_write_data_pe[3] |=
-                                                       lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
-                               }
-
-                               /* Vendor specific: Update VS and PE to DPRX requested value */
-                               core_link_write_dpcd(
-                                               link,
-                                               vendor_lttpr_write_address,
-                                               &vendor_lttpr_write_data_vs[0],
-                                               sizeof(vendor_lttpr_write_data_vs));
-                               core_link_write_dpcd(
-                                               link,
-                                               vendor_lttpr_write_address,
-                                               &vendor_lttpr_write_data_pe[0],
-                                               sizeof(vendor_lttpr_write_data_pe));
-
-                               dpcd_set_lane_settings(
-                                               link,
-                                               lt_settings,
-                                               0);
-                       }
-
-                       /* 3. wait receiver to lock-on*/
-                       wait_time_microsec = lt_settings->cr_pattern_time;
-
-                       dp_wait_for_training_aux_rd_interval(
-                                       link,
-                                       wait_time_microsec);
-
-                       /* 4. Read lane status and requested drive
-                        * settings as set by the sink
-                        */
-                       dp_get_lane_status_and_lane_adjust(
-                                       link,
-                                       lt_settings,
-                                       dpcd_lane_status,
-                                       &dpcd_lane_status_updated,
-                                       dpcd_lane_adjust,
-                                       0);
-
-                       /* 5. check CR done*/
-                       if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
-                               status = LINK_TRAINING_SUCCESS;
-                               break;
-                       }
-
-                       /* 6. max VS reached*/
-                       if (dp_is_max_vs_reached(lt_settings))
-                               break;
-
-                       /* 7. same lane settings */
-                       /* Note: settings are the same for all lanes,
-                        * so comparing first lane is sufficient
-                        */
-                       if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
-                                       dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
-                               retries_cr++;
-                       else
-                               retries_cr = 0;
-
-                       /* 8. update VS/PE/PC2 in lt_settings*/
-                       dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-                       retry_count++;
-               }
-
-               if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
-                       ASSERT(0);
-                       DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
-                               __func__,
-                               LINK_TRAINING_MAX_CR_RETRY);
-
-               }
-
-               status = dp_get_cr_failure(lane_count, dpcd_lane_status);
-       }
-
-       /* Perform Channel EQ Sequence */
-       if (status == LINK_TRAINING_SUCCESS) {
-               enum dc_dp_training_pattern tr_pattern;
-               uint32_t retries_ch_eq;
-               uint32_t wait_time_microsec;
-               enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
-               union lane_align_status_updated dpcd_lane_status_updated = {0};
-               union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
-               union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
-               /* Note: also check that TPS4 is a supported feature*/
-               tr_pattern = lt_settings->pattern_for_eq;
-
-               dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
-
-               status = LINK_TRAINING_EQ_FAIL_EQ;
-
-               for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
-                       retries_ch_eq++) {
-
-                       dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
-
-                       vendor_lttpr_write_data_vs[3] = 0;
-                       vendor_lttpr_write_data_pe[3] = 0;
-
-                       for (lane = 0; lane < lane_count; lane++) {
-                               vendor_lttpr_write_data_vs[3] |=
-                                               lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
-                               vendor_lttpr_write_data_pe[3] |=
-                                               lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
-                       }
-
-                       /* Vendor specific: Update VS and PE to DPRX requested value */
-                       core_link_write_dpcd(
-                                       link,
-                                       vendor_lttpr_write_address,
-                                       &vendor_lttpr_write_data_vs[0],
-                                       sizeof(vendor_lttpr_write_data_vs));
-                       core_link_write_dpcd(
-                                       link,
-                                       vendor_lttpr_write_address,
-                                       &vendor_lttpr_write_data_pe[0],
-                                       sizeof(vendor_lttpr_write_data_pe));
-
-                       /* 2. update DPCD*/
-                       if (!retries_ch_eq)
-                               /* EPR #361076 - write as a 5-byte burst,
-                                * but only for the 1-st iteration
-                                */
-
-                               dpcd_set_lt_pattern_and_lane_settings(
-                                       link,
-                                       lt_settings,
-                                       tr_pattern, 0);
-                       else
-                               dpcd_set_lane_settings(link, lt_settings, 0);
-
-                       /* 3. wait for receiver to lock-on*/
-                       wait_time_microsec = lt_settings->eq_pattern_time;
-
-                       dp_wait_for_training_aux_rd_interval(
-                                       link,
-                                       wait_time_microsec);
-
-                       /* 4. Read lane status and requested
-                        * drive settings as set by the sink
-                        */
-                       dp_get_lane_status_and_lane_adjust(
-                               link,
-                               lt_settings,
-                               dpcd_lane_status,
-                               &dpcd_lane_status_updated,
-                               dpcd_lane_adjust,
-                               0);
-
-                       /* 5. check CR done*/
-                       if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
-                               status = LINK_TRAINING_EQ_FAIL_CR;
-                               break;
-                       }
-
-                       /* 6. check CHEQ done*/
-                       if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
-                                       dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
-                                       dp_is_interlane_aligned(dpcd_lane_status_updated)) {
-                               status = LINK_TRAINING_SUCCESS;
-                               break;
-                       }
-
-                       /* 7. update VS/PE/PC2 in lt_settings*/
-                       dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
-                                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-               }
-       }
-
-       return status;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_training_fixed_vs_pe_retimer.h
deleted file mode 100644 (file)
index e61970e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
-#define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
-#include "link_dp_training.h"
-
-enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
-       struct dc_link *link,
-       const struct link_resource *link_res,
-       struct link_training_settings *lt_settings);
-
-void dp_fixed_vs_pe_set_retimer_lane_settings(
-       struct dc_link *link,
-       const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
-       uint8_t lane_count);
-
-void dp_fixed_vs_pe_read_lane_adjust(
-       struct dc_link *link,
-       union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]);
-
-#endif /* __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.c
deleted file mode 100644 (file)
index 5c9a302..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2021 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 basic dpcd read/write functionality. It also does basic
- * dpcd range check to ensure that every dpcd request is compliant with specs
- * range requirements.
- */
-
-#include "link_dpcd.h"
-#include <drm/display/drm_dp_helper.h>
-#include "dm_helpers.h"
-
-#define END_ADDRESS(start, size) (start + size - 1)
-#define ADDRESS_RANGE_SIZE(start, end) (end - start + 1)
-struct dpcd_address_range {
-       uint32_t start;
-       uint32_t end;
-};
-
-static enum dc_status internal_link_read_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       uint8_t *data,
-       uint32_t size)
-{
-       if (!link->aux_access_disabled &&
-                       !dm_helpers_dp_read_dpcd(link->ctx,
-                       link, address, data, size)) {
-               return DC_ERROR_UNEXPECTED;
-       }
-
-       return DC_OK;
-}
-
-static enum dc_status internal_link_write_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       const uint8_t *data,
-       uint32_t size)
-{
-       if (!link->aux_access_disabled &&
-                       !dm_helpers_dp_write_dpcd(link->ctx,
-                       link, address, data, size)) {
-               return DC_ERROR_UNEXPECTED;
-       }
-
-       return DC_OK;
-}
-
-/*
- * Partition the entire DPCD address space
- * XXX: This partitioning must cover the entire DPCD address space,
- * and must contain no gaps or overlapping address ranges.
- */
-static const struct dpcd_address_range mandatory_dpcd_partitions[] = {
-       { 0, DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1) - 1},
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8) - 1 },
-       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
-       /*
-        * The FEC registers are contiguous
-        */
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
-       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR8), DP_LTTPR_MAX_ADD },
-       /* all remaining DPCD addresses */
-       { DP_LTTPR_MAX_ADD + 1, DP_DPCD_MAX_ADD } };
-
-static inline bool do_addresses_intersect_with_range(
-               const struct dpcd_address_range *range,
-               const uint32_t start_address,
-               const uint32_t end_address)
-{
-       return start_address <= range->end && end_address >= range->start;
-}
-
-static uint32_t dpcd_get_next_partition_size(const uint32_t address, const uint32_t size)
-{
-       const uint32_t end_address = END_ADDRESS(address, size);
-       uint32_t partition_iterator = 0;
-
-       /*
-        * find current partition
-        * this loop spins forever if partition map above is not surjective
-        */
-       while (!do_addresses_intersect_with_range(&mandatory_dpcd_partitions[partition_iterator],
-                               address, end_address))
-               partition_iterator++;
-       if (end_address < mandatory_dpcd_partitions[partition_iterator].end)
-               return size;
-       return ADDRESS_RANGE_SIZE(address, mandatory_dpcd_partitions[partition_iterator].end);
-}
-
-/*
- * Ranges of DPCD addresses that must be read in a single transaction
- * XXX: Do not allow any two address ranges in this array to overlap
- */
-static const struct dpcd_address_range mandatory_dpcd_blocks[] = {
-       { DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT }};
-
-/*
- * extend addresses to read all mandatory blocks together
- */
-static void dpcd_extend_address_range(
-               const uint32_t in_address,
-               uint8_t * const in_data,
-               const uint32_t in_size,
-               uint32_t *out_address,
-               uint8_t **out_data,
-               uint32_t *out_size)
-{
-       const uint32_t end_address = END_ADDRESS(in_address, in_size);
-       const struct dpcd_address_range *addr_range;
-       struct dpcd_address_range new_addr_range;
-       uint32_t i;
-
-       new_addr_range.start = in_address;
-       new_addr_range.end = end_address;
-       for (i = 0; i < ARRAY_SIZE(mandatory_dpcd_blocks); i++) {
-               addr_range = &mandatory_dpcd_blocks[i];
-               if (addr_range->start <= in_address && addr_range->end >= in_address)
-                       new_addr_range.start = addr_range->start;
-
-               if (addr_range->start <= end_address && addr_range->end >= end_address)
-                       new_addr_range.end = addr_range->end;
-       }
-       *out_address = in_address;
-       *out_size = in_size;
-       *out_data = in_data;
-       if (new_addr_range.start != in_address || new_addr_range.end != end_address) {
-               *out_address = new_addr_range.start;
-               *out_size = ADDRESS_RANGE_SIZE(new_addr_range.start, new_addr_range.end);
-               *out_data = kzalloc(*out_size * sizeof(**out_data), GFP_KERNEL);
-       }
-}
-
-/*
- * Reduce the AUX reply down to the values the caller requested
- */
-static void dpcd_reduce_address_range(
-               const uint32_t extended_address,
-               uint8_t * const extended_data,
-               const uint32_t extended_size,
-               const uint32_t reduced_address,
-               uint8_t * const reduced_data,
-               const uint32_t reduced_size)
-{
-       const uint32_t offset = reduced_address - extended_address;
-
-       /*
-        * If the address is same, address was not extended.
-        * So we do not need to free any memory.
-        * The data is in original buffer(reduced_data).
-        */
-       if (extended_data == reduced_data)
-               return;
-
-       memcpy(&extended_data[offset], reduced_data, reduced_size);
-       kfree(extended_data);
-}
-
-enum dc_status core_link_read_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       uint8_t *data,
-       uint32_t size)
-{
-       uint32_t extended_address;
-       uint32_t partitioned_address;
-       uint8_t *extended_data;
-       uint32_t extended_size;
-       /* size of the remaining partitioned address space */
-       uint32_t size_left_to_read;
-       enum dc_status status;
-       /* size of the next partition to be read from */
-       uint32_t partition_size;
-       uint32_t data_index = 0;
-
-       dpcd_extend_address_range(address, data, size, &extended_address, &extended_data, &extended_size);
-       partitioned_address = extended_address;
-       size_left_to_read = extended_size;
-       while (size_left_to_read) {
-               partition_size = dpcd_get_next_partition_size(partitioned_address, size_left_to_read);
-               status = internal_link_read_dpcd(link, partitioned_address, &extended_data[data_index], partition_size);
-               if (status != DC_OK)
-                       break;
-               partitioned_address += partition_size;
-               data_index += partition_size;
-               size_left_to_read -= partition_size;
-       }
-       dpcd_reduce_address_range(extended_address, extended_data, extended_size, address, data, size);
-       return status;
-}
-
-enum dc_status core_link_write_dpcd(
-       struct dc_link *link,
-       uint32_t address,
-       const uint8_t *data,
-       uint32_t size)
-{
-       uint32_t partition_size;
-       uint32_t data_index = 0;
-       enum dc_status status;
-
-       while (size) {
-               partition_size = dpcd_get_next_partition_size(address, size);
-               status = internal_link_write_dpcd(link, address, &data[data_index], partition_size);
-               if (status != DC_OK)
-                       break;
-               address += partition_size;
-               data_index += partition_size;
-               size -= partition_size;
-       }
-       return status;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/link/link_dpcd.h
deleted file mode 100644 (file)
index 08d787a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2021 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_DPCD_H__
-#define __LINK_DPCD_H__
-#include "link.h"
-#include "dpcd_defs.h"
-
-enum dc_status core_link_read_dpcd(
-               struct dc_link *link,
-               uint32_t address,
-               uint8_t *data,
-               uint32_t size);
-
-enum dc_status core_link_write_dpcd(
-               struct dc_link *link,
-               uint32_t address,
-               const uint8_t *data,
-               uint32_t size);
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hpd.c b/drivers/gpu/drm/amd/display/dc/link/link_hpd.c
deleted file mode 100644 (file)
index 5f39dfe..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-/* FILE POLICY AND INTENDED USAGE:
- *
- * This file implements functions that manage basic HPD components such as gpio.
- * It also provides wrapper functions to execute HPD related programming. This
- * file only manages basic HPD functionality. It doesn't manage detection or
- * feature or signal specific HPD behaviors.
- */
-#include "link_hpd.h"
-#include "gpio_service_interface.h"
-
-bool dc_link_get_hpd_state(struct dc_link *dc_link)
-{
-       uint32_t state;
-
-       dal_gpio_lock_pin(dc_link->hpd_gpio);
-       dal_gpio_get_value(dc_link->hpd_gpio, &state);
-       dal_gpio_unlock_pin(dc_link->hpd_gpio);
-
-       return state;
-}
-
-void dc_link_enable_hpd(const struct dc_link *link)
-{
-       struct link_encoder *encoder = link->link_enc;
-
-       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
-               encoder->funcs->enable_hpd(encoder);
-}
-
-void dc_link_disable_hpd(const struct dc_link *link)
-{
-       struct link_encoder *encoder = link->link_enc;
-
-       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
-               encoder->funcs->disable_hpd(encoder);
-}
-
-void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
-{
-       struct gpio *hpd;
-
-       if (enable) {
-               link->is_hpd_filter_disabled = false;
-               program_hpd_filter(link);
-       } else {
-               link->is_hpd_filter_disabled = true;
-               /* Obtain HPD handle */
-               hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
-
-               if (!hpd)
-                       return;
-
-               /* Setup HPD filtering */
-               if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
-                       struct gpio_hpd_config config;
-
-                       config.delay_on_connect = 0;
-                       config.delay_on_disconnect = 0;
-
-                       dal_irq_setup_hpd_filter(hpd, &config);
-
-                       dal_gpio_close(hpd);
-               } else {
-                       ASSERT_CRITICAL(false);
-               }
-               /* Release HPD handle */
-               dal_gpio_destroy_irq(&hpd);
-       }
-}
-
-struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
-                         struct graphics_object_id link_id,
-                         struct gpio_service *gpio_service)
-{
-       enum bp_result bp_result;
-       struct graphics_object_hpd_info hpd_info;
-       struct gpio_pin_info pin_info;
-
-       if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
-               return NULL;
-
-       bp_result = dcb->funcs->get_gpio_pin_info(dcb,
-               hpd_info.hpd_int_gpio_uid, &pin_info);
-
-       if (bp_result != BP_RESULT_OK) {
-               ASSERT(bp_result == BP_RESULT_NORECORD);
-               return NULL;
-       }
-
-       return dal_gpio_service_create_irq(gpio_service,
-                                          pin_info.offset,
-                                          pin_info.mask);
-}
-
-bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high)
-{
-       struct gpio *hpd_pin = link_get_hpd_gpio(
-                       link->ctx->dc_bios, link->link_id,
-                       link->ctx->gpio_service);
-       if (!hpd_pin)
-               return false;
-
-       dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
-       dal_gpio_get_value(hpd_pin, is_hpd_high);
-       dal_gpio_close(hpd_pin);
-       dal_gpio_destroy_irq(&hpd_pin);
-       return true;
-}
-
-enum hpd_source_id get_hpd_line(struct dc_link *link)
-{
-       struct gpio *hpd;
-       enum hpd_source_id hpd_id;
-
-               hpd_id = HPD_SOURCEID_UNKNOWN;
-
-       hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
-                          link->ctx->gpio_service);
-
-       if (hpd) {
-               switch (dal_irq_get_source(hpd)) {
-               case DC_IRQ_SOURCE_HPD1:
-                       hpd_id = HPD_SOURCEID1;
-               break;
-               case DC_IRQ_SOURCE_HPD2:
-                       hpd_id = HPD_SOURCEID2;
-               break;
-               case DC_IRQ_SOURCE_HPD3:
-                       hpd_id = HPD_SOURCEID3;
-               break;
-               case DC_IRQ_SOURCE_HPD4:
-                       hpd_id = HPD_SOURCEID4;
-               break;
-               case DC_IRQ_SOURCE_HPD5:
-                       hpd_id = HPD_SOURCEID5;
-               break;
-               case DC_IRQ_SOURCE_HPD6:
-                       hpd_id = HPD_SOURCEID6;
-               break;
-               default:
-                       BREAK_TO_DEBUGGER();
-               break;
-               }
-
-               dal_gpio_destroy_irq(&hpd);
-       }
-
-       return hpd_id;
-}
-
-bool program_hpd_filter(const struct dc_link *link)
-{
-       bool result = false;
-       struct gpio *hpd;
-       int delay_on_connect_in_ms = 0;
-       int delay_on_disconnect_in_ms = 0;
-
-       if (link->is_hpd_filter_disabled)
-               return false;
-       /* Verify feature is supported */
-       switch (link->connector_signal) {
-       case SIGNAL_TYPE_DVI_SINGLE_LINK:
-       case SIGNAL_TYPE_DVI_DUAL_LINK:
-       case SIGNAL_TYPE_HDMI_TYPE_A:
-               /* Program hpd filter */
-               delay_on_connect_in_ms = 500;
-               delay_on_disconnect_in_ms = 100;
-               break;
-       case SIGNAL_TYPE_DISPLAY_PORT:
-       case SIGNAL_TYPE_DISPLAY_PORT_MST:
-               /* Program hpd filter to allow DP signal to settle */
-               /* 500: not able to detect MST <-> SST switch as HPD is low for
-                * only 100ms on DELL U2413
-                * 0: some passive dongle still show aux mode instead of i2c
-                * 20-50: not enough to hide bouncing HPD with passive dongle.
-                * also see intermittent i2c read issues.
-                */
-               delay_on_connect_in_ms = 80;
-               delay_on_disconnect_in_ms = 0;
-               break;
-       case SIGNAL_TYPE_LVDS:
-       case SIGNAL_TYPE_EDP:
-       default:
-               /* Don't program hpd filter */
-               return false;
-       }
-
-       /* Obtain HPD handle */
-       hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
-                          link->ctx->gpio_service);
-
-       if (!hpd)
-               return result;
-
-       /* Setup HPD filtering */
-       if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
-               struct gpio_hpd_config config;
-
-               config.delay_on_connect = delay_on_connect_in_ms;
-               config.delay_on_disconnect = delay_on_disconnect_in_ms;
-
-               dal_irq_setup_hpd_filter(hpd, &config);
-
-               dal_gpio_close(hpd);
-
-               result = true;
-       } else {
-               ASSERT_CRITICAL(false);
-       }
-
-       /* Release HPD handle */
-       dal_gpio_destroy_irq(&hpd);
-
-       return result;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hpd.h b/drivers/gpu/drm/amd/display/dc/link/link_hpd.h
deleted file mode 100644 (file)
index 3d122de..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-
-
-#ifndef __DC_LINK_HPD_H__
-#define __DC_LINK_HPD_H__
-#include "link.h"
-
-enum hpd_source_id get_hpd_line(struct dc_link *link);
-/*
- *  Function: program_hpd_filter
- *
- *  @brief
- *     Programs HPD filter on associated HPD line to default values.
- *
- *  @return
- *     true on success, false otherwise
- */
-bool program_hpd_filter(const struct dc_link *link);
-/* Query hot plug status of USB4 DP tunnel.
- * Returns true if HPD high.
- */
-bool dpia_query_hpd_status(struct dc_link *link);
-bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high);
-#endif /* __DC_LINK_HPD_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
deleted file mode 100644 (file)
index 33148b7..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#include "link_hwss_dio.h"
-#include "core_types.h"
-#include "dc_link_dp.h"
-#include "link_enc_cfg.h"
-
-void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
-               struct fixed31_32 throttled_vcp_size)
-{
-       struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
-
-       stream_encoder->funcs->set_throttled_vcp_size(
-                               stream_encoder,
-                               throttled_vcp_size);
-}
-
-void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
-{
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
-       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
-
-       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,
-                               DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
-       if (stream_enc->funcs->enable_fifo)
-               stream_enc->funcs->enable_fifo(stream_enc);
-}
-
-void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
-{
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
-       struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
-
-       if (stream_enc && stream_enc->funcs->disable_fifo)
-               stream_enc->funcs->disable_fifo(stream_enc);
-
-       link_enc->funcs->connect_dig_be_to_fe(
-                       link_enc,
-                       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,
-                               DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
-
-}
-
-void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx)
-{
-       struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
-       struct dc_stream_state *stream = pipe_ctx->stream;
-       struct dc_link *link = stream->link;
-
-       if (!dc_is_virtual_signal(stream->signal))
-               stream_encoder->funcs->setup_stereo_sync(
-                               stream_encoder,
-                               pipe_ctx->stream_res.tg->inst,
-                               stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
-
-       if (dc_is_dp_signal(stream->signal))
-               stream_encoder->funcs->dp_set_stream_attribute(
-                               stream_encoder,
-                               &stream->timing,
-                               stream->output_color_space,
-                               stream->use_vsc_sdp_for_colorimetry,
-                               link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
-       else if (dc_is_hdmi_tmds_signal(stream->signal))
-               stream_encoder->funcs->hdmi_set_stream_attribute(
-                               stream_encoder,
-                               &stream->timing,
-                               stream->phy_pix_clk,
-                               pipe_ctx->stream_res.audio != NULL);
-       else if (dc_is_dvi_signal(stream->signal))
-               stream_encoder->funcs->dvi_set_stream_attribute(
-                               stream_encoder,
-                               &stream->timing,
-                               (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
-                                               true : false);
-       else if (dc_is_lvds_signal(stream->signal))
-               stream_encoder->funcs->lvds_set_stream_attribute(
-                               stream_encoder,
-                               &stream->timing);
-
-       if (dc_is_dp_signal(stream->signal))
-               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
-}
-
-void enable_dio_dp_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal,
-               enum clock_source_id clock_source,
-               const struct dc_link_settings *link_settings)
-{
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
-
-       if (dc_is_dp_sst_signal(signal))
-               link_enc->funcs->enable_dp_output(
-                               link_enc,
-                               link_settings,
-                               clock_source);
-       else
-               link_enc->funcs->enable_dp_mst_output(
-                               link_enc,
-                               link_settings,
-                               clock_source);
-       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
-}
-
-void disable_dio_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal)
-{
-       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);
-}
-
-void set_dio_dp_link_test_pattern(struct dc_link *link,
-               const struct link_resource *link_res,
-               struct encoder_set_dp_phy_pattern_param *tp_params)
-{
-       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);
-}
-
-void set_dio_dp_lane_settings(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct dc_link_settings *link_settings,
-               const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
-{
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
-
-       link_enc->funcs->dp_set_lane_settings(link_enc, link_settings, lane_settings);
-}
-
-static void update_dio_stream_allocation_table(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct link_mst_stream_allocation_table *table)
-{
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
-
-       ASSERT(link_enc);
-       link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
-}
-
-void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
-               struct audio_output *audio_output, uint32_t audio_inst)
-{
-       if (dc_is_dp_signal(pipe_ctx->stream->signal))
-               pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
-                               pipe_ctx->stream_res.stream_enc,
-                               audio_inst,
-                               &pipe_ctx->stream->audio_info);
-       else
-               pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
-                               pipe_ctx->stream_res.stream_enc,
-                               audio_inst,
-                               &pipe_ctx->stream->audio_info,
-                               &audio_output->crtc_info);
-}
-
-void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
-{
-       if (dc_is_dp_signal(pipe_ctx->stream->signal))
-               pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(
-                               pipe_ctx->stream_res.stream_enc);
-
-       pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
-                       pipe_ctx->stream_res.stream_enc, false);
-
-       if (dc_is_dp_signal(pipe_ctx->stream->signal))
-               dp_source_sequence_trace(pipe_ctx->stream->link,
-                               DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
-}
-
-void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
-{
-       pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
-                       pipe_ctx->stream_res.stream_enc, true);
-
-       if (pipe_ctx->stream_res.audio) {
-               if (dc_is_dp_signal(pipe_ctx->stream->signal))
-                       pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
-                                       pipe_ctx->stream_res.stream_enc);
-               else
-                       pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
-                                       pipe_ctx->stream_res.stream_enc);
-       }
-
-       if (dc_is_dp_signal(pipe_ctx->stream->signal))
-               dp_source_sequence_trace(pipe_ctx->stream->link,
-                               DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
-}
-
-static const struct link_hwss dio_link_hwss = {
-       .setup_stream_encoder = setup_dio_stream_encoder,
-       .reset_stream_encoder = reset_dio_stream_encoder,
-       .setup_stream_attribute = setup_dio_stream_attribute,
-       .disable_link_output = disable_dio_link_output,
-       .setup_audio_output = setup_dio_audio_output,
-       .enable_audio_packet = enable_dio_audio_packet,
-       .disable_audio_packet = disable_dio_audio_packet,
-       .ext = {
-               .set_throttled_vcp_size = set_dio_throttled_vcp_size,
-               .enable_dp_link_output = enable_dio_dp_link_output,
-               .set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
-               .set_dp_lane_settings = set_dio_dp_lane_settings,
-               .update_stream_allocation_table = update_dio_stream_allocation_table,
-       },
-};
-
-bool can_use_dio_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res)
-{
-       return link->link_enc != NULL;
-}
-
-const struct link_hwss *get_dio_link_hwss(void)
-{
-       return &dio_link_hwss;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
deleted file mode 100644 (file)
index 9a108c3..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#ifndef __LINK_HWSS_DIO_H__
-#define __LINK_HWSS_DIO_H__
-
-#include "link_hwss.h"
-
-const struct link_hwss *get_dio_link_hwss(void);
-bool can_use_dio_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res);
-void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
-               struct fixed31_32 throttled_vcp_size);
-void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx);
-void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx);
-void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx);
-void enable_dio_dp_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal,
-               enum clock_source_id clock_source,
-               const struct dc_link_settings *link_settings);
-void disable_dio_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal);
-void set_dio_dp_link_test_pattern(struct dc_link *link,
-               const struct link_resource *link_res,
-               struct encoder_set_dp_phy_pattern_param *tp_params);
-void set_dio_dp_lane_settings(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct dc_link_settings *link_settings,
-               const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
-void setup_dio_audio_output(struct pipe_ctx *pipe_ctx,
-               struct audio_output *audio_output, uint32_t audio_inst);
-void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
-void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx);
-
-#endif /* __LINK_HWSS_DIO_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
deleted file mode 100644 (file)
index 861f3cd..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#include "link_hwss_dpia.h"
-#include "core_types.h"
-#include "link_hwss_dio.h"
-#include "link_enc_cfg.h"
-
-#define DC_LOGGER_INIT(logger)
-
-static void update_dpia_stream_allocation_table(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct link_mst_stream_allocation_table *table)
-{
-       struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
-       static enum dc_status status;
-       uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF;
-       int i;
-       DC_LOGGER_INIT(link->ctx->logger);
-
-       for (i = 0; i < table->stream_count; i++)
-               mst_alloc_slots += table->stream_allocations[i].slot_count;
-
-       status = dc_process_dmub_set_mst_slots(link->dc, link->link_index,
-                       mst_alloc_slots, &prev_mst_slots_in_use);
-       ASSERT(status == DC_OK);
-       DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n",
-                       status, mst_alloc_slots, prev_mst_slots_in_use);
-
-       ASSERT(link_enc);
-       link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
-}
-
-static const struct link_hwss dpia_link_hwss = {
-       .setup_stream_encoder = setup_dio_stream_encoder,
-       .reset_stream_encoder = reset_dio_stream_encoder,
-       .setup_stream_attribute = setup_dio_stream_attribute,
-       .disable_link_output = disable_dio_link_output,
-       .setup_audio_output = setup_dio_audio_output,
-       .enable_audio_packet = enable_dio_audio_packet,
-       .disable_audio_packet = disable_dio_audio_packet,
-       .ext = {
-               .set_throttled_vcp_size = set_dio_throttled_vcp_size,
-               .enable_dp_link_output = enable_dio_dp_link_output,
-               .set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
-               .set_dp_lane_settings = set_dio_dp_lane_settings,
-               .update_stream_allocation_table = update_dpia_stream_allocation_table,
-       },
-};
-
-bool can_use_dpia_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res)
-{
-       return link->is_dig_mapping_flexible &&
-                       link->dc->res_pool->funcs->link_encs_assign;
-}
-
-const struct link_hwss *get_dpia_link_hwss(void)
-{
-       return &dpia_link_hwss;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h
deleted file mode 100644 (file)
index ad16ec5..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#ifndef __LINK_HWSS_DPIA_H__
-#define __LINK_HWSS_DPIA_H__
-
-#include "link_hwss.h"
-
-const struct link_hwss *get_dpia_link_hwss(void);
-bool can_use_dpia_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res);
-
-#endif /* __LINK_HWSS_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
deleted file mode 100644 (file)
index 164d631..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#include "link_hwss_hpo_dp.h"
-#include "dm_helpers.h"
-#include "core_types.h"
-#include "dccg.h"
-#include "dc_link_dp.h"
-#include "clk_mgr.h"
-
-static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
-{
-       switch (link->link_enc->transmitter) {
-       case TRANSMITTER_UNIPHY_A:
-               return PHYD32CLKA;
-       case TRANSMITTER_UNIPHY_B:
-               return PHYD32CLKB;
-       case TRANSMITTER_UNIPHY_C:
-               return PHYD32CLKC;
-       case TRANSMITTER_UNIPHY_D:
-               return PHYD32CLKD;
-       case TRANSMITTER_UNIPHY_E:
-               return PHYD32CLKE;
-       default:
-               return PHYD32CLKA;
-       }
-}
-
-static void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
-               struct fixed31_32 throttled_vcp_size)
-{
-       struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
-                       pipe_ctx->stream_res.hpo_dp_stream_enc;
-       struct hpo_dp_link_encoder *hpo_dp_link_encoder =
-                       pipe_ctx->link_res.hpo_dp_link_enc;
-
-       hpo_dp_link_encoder->funcs->set_throttled_vcp_size(hpo_dp_link_encoder,
-                       hpo_dp_stream_encoder->inst,
-                       throttled_vcp_size);
-}
-
-static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
-               const struct dc_link_settings *link_settings,
-               struct fixed31_32 throttled_vcp_size)
-{
-       struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
-                       pipe_ctx->stream_res.hpo_dp_stream_enc;
-       struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
-       struct fixed31_32 h_blank_in_ms, time_slot_in_ms, mtp_cnt_per_h_blank;
-       uint32_t link_bw_in_kbps =
-                       dc_link_bandwidth_kbps(pipe_ctx->stream->link, link_settings);
-       uint16_t hblank_min_symbol_width = 0;
-
-       if (link_bw_in_kbps > 0) {
-               h_blank_in_ms = dc_fixpt_div(dc_fixpt_from_int(
-                               timing->h_total - timing->h_addressable),
-                               dc_fixpt_from_fraction(timing->pix_clk_100hz, 10));
-               time_slot_in_ms = dc_fixpt_from_fraction(32 * 4, link_bw_in_kbps);
-               mtp_cnt_per_h_blank = dc_fixpt_div(h_blank_in_ms,
-                               dc_fixpt_mul_int(time_slot_in_ms, 64));
-               hblank_min_symbol_width = dc_fixpt_floor(
-                               dc_fixpt_mul(mtp_cnt_per_h_blank, throttled_vcp_size));
-       }
-
-       hpo_dp_stream_encoder->funcs->set_hblank_min_symbol_width(hpo_dp_stream_encoder,
-                       hblank_min_symbol_width);
-}
-
-static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
-{
-       struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
-       struct hpo_dp_link_encoder *link_enc = pipe_ctx->link_res.hpo_dp_link_enc;
-
-       stream_enc->funcs->enable_stream(stream_enc);
-       stream_enc->funcs->map_stream_to_link(stream_enc, stream_enc->inst, link_enc->inst);
-}
-
-static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
-{
-       struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
-
-       stream_enc->funcs->disable(stream_enc);
-}
-
-static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
-{
-       struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
-       struct dc_stream_state *stream = pipe_ctx->stream;
-       struct dc_link *link = stream->link;
-
-       stream_enc->funcs->set_stream_attribute(
-                       stream_enc,
-                       &stream->timing,
-                       stream->output_color_space,
-                       stream->use_vsc_sdp_for_colorimetry,
-                       stream->timing.flags.DSC,
-                       false);
-       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
-}
-
-static void enable_hpo_dp_fpga_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal,
-               enum clock_source_id clock_source,
-               const struct dc_link_settings *link_settings)
-{
-       const struct dc *dc = link->dc;
-       enum phyd32clk_clock_source phyd32clk = get_phyd32clk_src(link);
-       int phyd32clk_freq_khz = link_settings->link_rate == LINK_RATE_UHBR10 ? 312500 :
-                       link_settings->link_rate == LINK_RATE_UHBR13_5 ? 412875 :
-                       link_settings->link_rate == LINK_RATE_UHBR20 ? 625000 : 0;
-
-       dm_set_phyd32clk(dc->ctx, phyd32clk_freq_khz);
-       dc->res_pool->dccg->funcs->set_physymclk(
-                       dc->res_pool->dccg,
-                       link->link_enc_hw_inst,
-                       PHYSYMCLK_FORCE_SRC_PHYD32CLK,
-                       true);
-       dc->res_pool->dccg->funcs->enable_symclk32_le(
-                       dc->res_pool->dccg,
-                       link_res->hpo_dp_link_enc->inst,
-                       phyd32clk);
-       link_res->hpo_dp_link_enc->funcs->link_enable(
-                       link_res->hpo_dp_link_enc,
-                       link_settings->lane_count);
-
-}
-
-static void enable_hpo_dp_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal,
-               enum clock_source_id clock_source,
-               const struct dc_link_settings *link_settings)
-{
-       if (IS_FPGA_MAXIMUS_DC(link->dc->ctx->dce_environment))
-               enable_hpo_dp_fpga_link_output(link, link_res, signal,
-                               clock_source, link_settings);
-       else
-               link_res->hpo_dp_link_enc->funcs->enable_link_phy(
-                               link_res->hpo_dp_link_enc,
-                               link_settings,
-                               link->link_enc->transmitter,
-                               link->link_enc->hpd_source);
-}
-
-
-static void disable_hpo_dp_fpga_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal)
-{
-       const struct dc *dc = link->dc;
-
-       link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
-       dc->res_pool->dccg->funcs->disable_symclk32_le(
-                       dc->res_pool->dccg,
-                       link_res->hpo_dp_link_enc->inst);
-       dc->res_pool->dccg->funcs->set_physymclk(
-                       dc->res_pool->dccg,
-                       link->link_enc_hw_inst,
-                       PHYSYMCLK_FORCE_SRC_SYMCLK,
-                       false);
-       dm_set_phyd32clk(dc->ctx, 0);
-}
-
-static void disable_hpo_dp_link_output(struct dc_link *link,
-               const struct link_resource *link_res,
-               enum signal_type signal)
-{
-       if (IS_FPGA_MAXIMUS_DC(link->dc->ctx->dce_environment)) {
-               disable_hpo_dp_fpga_link_output(link, link_res, signal);
-       } else {
-               link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
-               link_res->hpo_dp_link_enc->funcs->disable_link_phy(
-                               link_res->hpo_dp_link_enc, signal);
-       }
-}
-
-static void set_hpo_dp_link_test_pattern(struct dc_link *link,
-               const struct link_resource *link_res,
-               struct encoder_set_dp_phy_pattern_param *tp_params)
-{
-       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);
-}
-
-static void set_hpo_dp_lane_settings(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct dc_link_settings *link_settings,
-               const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
-{
-       link_res->hpo_dp_link_enc->funcs->set_ffe(
-                       link_res->hpo_dp_link_enc,
-                       link_settings,
-                       lane_settings[0].FFE_PRESET.raw);
-}
-
-static void update_hpo_dp_stream_allocation_table(struct dc_link *link,
-               const struct link_resource *link_res,
-               const struct link_mst_stream_allocation_table *table)
-{
-       link_res->hpo_dp_link_enc->funcs->update_stream_allocation_table(
-                       link_res->hpo_dp_link_enc,
-                       table);
-}
-
-static void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx,
-               struct audio_output *audio_output, uint32_t audio_inst)
-{
-       pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
-                       pipe_ctx->stream_res.hpo_dp_stream_enc,
-                       audio_inst,
-                       &pipe_ctx->stream->audio_info);
-}
-
-static void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
-{
-       pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(
-                       pipe_ctx->stream_res.hpo_dp_stream_enc);
-}
-
-static void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx)
-{
-       if (pipe_ctx->stream_res.audio)
-               pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
-                               pipe_ctx->stream_res.hpo_dp_stream_enc);
-}
-
-static const struct link_hwss hpo_dp_link_hwss = {
-       .setup_stream_encoder = setup_hpo_dp_stream_encoder,
-       .reset_stream_encoder = reset_hpo_dp_stream_encoder,
-       .setup_stream_attribute = setup_hpo_dp_stream_attribute,
-       .disable_link_output = disable_hpo_dp_link_output,
-       .setup_audio_output = setup_hpo_dp_audio_output,
-       .enable_audio_packet = enable_hpo_dp_audio_packet,
-       .disable_audio_packet = disable_hpo_dp_audio_packet,
-       .ext = {
-               .set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size,
-               .set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width,
-               .enable_dp_link_output = enable_hpo_dp_link_output,
-               .set_dp_link_test_pattern  = set_hpo_dp_link_test_pattern,
-               .set_dp_lane_settings = set_hpo_dp_lane_settings,
-               .update_stream_allocation_table = update_hpo_dp_stream_allocation_table,
-       },
-};
-
-bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res)
-{
-       return link_res->hpo_dp_link_enc != NULL;
-}
-
-const struct link_hwss *get_hpo_dp_link_hwss(void)
-{
-       return &hpo_dp_link_hwss;
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h
deleted file mode 100644 (file)
index 57d447e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#ifndef __LINK_HWSS_HPO_DP_H__
-#define __LINK_HWSS_HPO_DP_H__
-
-#include "link_hwss.h"
-
-bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res);
-const struct link_hwss *get_hpo_dp_link_hwss(void);
-
-
-#endif /* __LINK_HWSS_HPO_DP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h
deleted file mode 100644 (file)
index ea8d976..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2022 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
-#ifndef __LINK_HWSS_HPO_FRL_H__
-#define __LINK_HWSS_HPO_FRL_H__
-
-#include "link_hwss.h"
-
-bool can_use_hpo_frl_link_hwss(const struct dc_link *link,
-               const struct link_resource *link_res);
-const struct link_hwss *get_hpo_frl_link_hwss(void);
-
-#endif /* __LINK_HWSS_HPO_FRL_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c
new file mode 100644 (file)
index 0000000..5269125
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2012-15 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 generic display communication protocols such as i2c, aux
+ * and scdc. The file should not contain any specific applications of these
+ * protocols such as display capability query, detection, or handshaking such as
+ * link training.
+ */
+#include "link_ddc.h"
+#include "vector.h"
+#include "dce/dce_aux.h"
+#include "dal_asic_id.h"
+#include "link_dpcd.h"
+#include "dm_helpers.h"
+#include "atomfirmware.h"
+
+#define DC_LOGGER_INIT(logger)
+
+static const uint8_t DP_VGA_DONGLE_BRANCH_DEV_NAME[] = "DpVga";
+/* DP to Dual link DVI converter */
+static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa";
+static const uint8_t DP_DVI_CONVERTER_ID_5[] = "3393N2";
+
+struct i2c_payloads {
+       struct vector payloads;
+};
+
+struct aux_payloads {
+       struct vector payloads;
+};
+
+static bool dal_ddc_i2c_payloads_create(
+               struct dc_context *ctx,
+               struct i2c_payloads *payloads,
+               uint32_t count)
+{
+       if (dal_vector_construct(
+               &payloads->payloads, ctx, count, sizeof(struct i2c_payload)))
+               return true;
+
+       return false;
+}
+
+static struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p)
+{
+       return (struct i2c_payload *)p->payloads.container;
+}
+
+static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p)
+{
+       return p->payloads.count;
+}
+
+#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+static void i2c_payloads_add(
+       struct i2c_payloads *payloads,
+       uint32_t address,
+       uint32_t len,
+       uint8_t *data,
+       bool write)
+{
+       uint32_t payload_size = EDID_SEGMENT_SIZE;
+       uint32_t pos;
+
+       for (pos = 0; pos < len; pos += payload_size) {
+               struct i2c_payload payload = {
+                       .write = write,
+                       .address = address,
+                       .length = DDC_MIN(payload_size, len - pos),
+                       .data = data + pos };
+               dal_vector_append(&payloads->payloads, &payload);
+       }
+
+}
+
+static void ddc_service_construct(
+       struct ddc_service *ddc_service,
+       struct ddc_service_init_data *init_data)
+{
+       enum connector_id connector_id =
+               dal_graphics_object_id_get_connector_id(init_data->id);
+
+       struct gpio_service *gpio_service = init_data->ctx->gpio_service;
+       struct graphics_object_i2c_info i2c_info;
+       struct gpio_ddc_hw_info hw_info;
+       struct dc_bios *dcb = init_data->ctx->dc_bios;
+
+       ddc_service->link = init_data->link;
+       ddc_service->ctx = init_data->ctx;
+
+       if (init_data->is_dpia_link ||
+           dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info) != BP_RESULT_OK) {
+               ddc_service->ddc_pin = NULL;
+       } else {
+               DC_LOGGER_INIT(ddc_service->ctx->logger);
+               DC_LOG_DC("BIOS object table - i2c_line: %d", i2c_info.i2c_line);
+               DC_LOG_DC("BIOS object table - i2c_engine_id: %d", i2c_info.i2c_engine_id);
+
+               hw_info.ddc_channel = i2c_info.i2c_line;
+               if (ddc_service->link != NULL)
+                       hw_info.hw_supported = i2c_info.i2c_hw_assist;
+               else
+                       hw_info.hw_supported = false;
+
+               ddc_service->ddc_pin = dal_gpio_create_ddc(
+                       gpio_service,
+                       i2c_info.gpio_info.clk_a_register_index,
+                       1 << i2c_info.gpio_info.clk_a_shift,
+                       &hw_info);
+       }
+
+       ddc_service->flags.EDID_QUERY_DONE_ONCE = false;
+       ddc_service->flags.FORCE_READ_REPEATED_START = false;
+       ddc_service->flags.EDID_STRESS_READ = false;
+
+       ddc_service->flags.IS_INTERNAL_DISPLAY =
+               connector_id == CONNECTOR_ID_EDP ||
+               connector_id == CONNECTOR_ID_LVDS;
+
+       ddc_service->wa.raw = 0;
+}
+
+struct ddc_service *link_create_ddc_service(
+       struct ddc_service_init_data *init_data)
+{
+       struct ddc_service *ddc_service;
+
+       ddc_service = kzalloc(sizeof(struct ddc_service), GFP_KERNEL);
+
+       if (!ddc_service)
+               return NULL;
+
+       ddc_service_construct(ddc_service, init_data);
+       return ddc_service;
+}
+
+static void ddc_service_destruct(struct ddc_service *ddc)
+{
+       if (ddc->ddc_pin)
+               dal_gpio_destroy_ddc(&ddc->ddc_pin);
+}
+
+void link_destroy_ddc_service(struct ddc_service **ddc)
+{
+       if (!ddc || !*ddc) {
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+       ddc_service_destruct(*ddc);
+       kfree(*ddc);
+       *ddc = NULL;
+}
+
+void set_ddc_transaction_type(
+       struct ddc_service *ddc,
+       enum ddc_transaction_type type)
+{
+       ddc->transaction_type = type;
+}
+
+bool link_is_in_aux_transaction_mode(struct ddc_service *ddc)
+{
+       switch (ddc->transaction_type) {
+       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
+       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
+       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+void set_dongle_type(struct ddc_service *ddc,
+               enum display_dongle_type dongle_type)
+{
+       ddc->dongle_type = dongle_type;
+}
+
+static uint32_t defer_delay_converter_wa(
+       struct ddc_service *ddc,
+       uint32_t defer_delay)
+{
+       struct dc_link *link = ddc->link;
+
+       if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER &&
+               link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
+               (link->dpcd_caps.branch_fw_revision[0] < 0x01 ||
+                               (link->dpcd_caps.branch_fw_revision[0] == 0x01 &&
+                               link->dpcd_caps.branch_fw_revision[1] < 0x40)) &&
+               !memcmp(link->dpcd_caps.branch_dev_name,
+                   DP_VGA_DONGLE_BRANCH_DEV_NAME,
+                       sizeof(link->dpcd_caps.branch_dev_name)))
+
+               return defer_delay > DPVGA_DONGLE_AUX_DEFER_WA_DELAY ?
+                       defer_delay : DPVGA_DONGLE_AUX_DEFER_WA_DELAY;
+
+       if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
+           !memcmp(link->dpcd_caps.branch_dev_name,
+                   DP_DVI_CONVERTER_ID_4,
+                   sizeof(link->dpcd_caps.branch_dev_name)))
+               return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ?
+                       defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY;
+       if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_006037 &&
+           !memcmp(link->dpcd_caps.branch_dev_name,
+                   DP_DVI_CONVERTER_ID_5,
+                   sizeof(link->dpcd_caps.branch_dev_name)))
+               return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY_1MS ?
+                       I2C_OVER_AUX_DEFER_WA_DELAY_1MS : defer_delay;
+
+       return defer_delay;
+}
+
+#define DP_TRANSLATOR_DELAY 5
+
+uint32_t link_get_aux_defer_delay(struct ddc_service *ddc)
+{
+       uint32_t defer_delay = 0;
+
+       switch (ddc->transaction_type) {
+       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
+               if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) ||
+                       (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) ||
+                       (DISPLAY_DONGLE_DP_HDMI_CONVERTER ==
+                               ddc->dongle_type)) {
+
+                       defer_delay = DP_TRANSLATOR_DELAY;
+
+                       defer_delay =
+                               defer_delay_converter_wa(ddc, defer_delay);
+
+               } else /*sink has a delay different from an Active Converter*/
+                       defer_delay = 0;
+               break;
+       case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
+               defer_delay = DP_TRANSLATOR_DELAY;
+               break;
+       default:
+               break;
+       }
+       return defer_delay;
+}
+
+static bool submit_aux_command(struct ddc_service *ddc,
+               struct aux_payload *payload)
+{
+       uint32_t retrieved = 0;
+       bool ret = false;
+
+       if (!ddc)
+               return false;
+
+       if (!payload)
+               return false;
+
+       do {
+               struct aux_payload current_payload;
+               bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >=
+                               payload->length;
+               uint32_t payload_length = is_end_of_payload ?
+                               payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE;
+
+               current_payload.address = payload->address;
+               current_payload.data = &payload->data[retrieved];
+               current_payload.defer_delay = payload->defer_delay;
+               current_payload.i2c_over_aux = payload->i2c_over_aux;
+               current_payload.length = payload_length;
+               /* set mot (middle of transaction) to false if it is the last payload */
+               current_payload.mot = is_end_of_payload ? payload->mot:true;
+               current_payload.write_status_update = false;
+               current_payload.reply = payload->reply;
+               current_payload.write = payload->write;
+
+               ret = link_aux_transfer_with_retries_no_mutex(ddc, &current_payload);
+
+               retrieved += payload_length;
+       } while (retrieved < payload->length && ret == true);
+
+       return ret;
+}
+
+bool link_query_ddc_data(
+       struct ddc_service *ddc,
+       uint32_t address,
+       uint8_t *write_buf,
+       uint32_t write_size,
+       uint8_t *read_buf,
+       uint32_t read_size)
+{
+       bool success = true;
+       uint32_t payload_size =
+               link_is_in_aux_transaction_mode(ddc) ?
+                       DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
+
+       uint32_t write_payloads =
+               (write_size + payload_size - 1) / payload_size;
+
+       uint32_t read_payloads =
+               (read_size + payload_size - 1) / payload_size;
+
+       uint32_t payloads_num = write_payloads + read_payloads;
+
+       if (!payloads_num)
+               return false;
+
+       if (link_is_in_aux_transaction_mode(ddc)) {
+               struct aux_payload payload;
+
+               payload.i2c_over_aux = true;
+               payload.address = address;
+               payload.reply = NULL;
+               payload.defer_delay = link_get_aux_defer_delay(ddc);
+               payload.write_status_update = false;
+
+               if (write_size != 0) {
+                       payload.write = true;
+                       /* should not set mot (middle of transaction) to 0
+                        * if there are pending read payloads
+                        */
+                       payload.mot = !(read_size == 0);
+                       payload.length = write_size;
+                       payload.data = write_buf;
+
+                       success = submit_aux_command(ddc, &payload);
+               }
+
+               if (read_size != 0 && success) {
+                       payload.write = false;
+                       /* should set mot (middle of transaction) to 0
+                        * since it is the last payload to send
+                        */
+                       payload.mot = false;
+                       payload.length = read_size;
+                       payload.data = read_buf;
+
+                       success = submit_aux_command(ddc, &payload);
+               }
+       } else {
+               struct i2c_command command = {0};
+               struct i2c_payloads payloads;
+
+               if (!dal_ddc_i2c_payloads_create(ddc->ctx, &payloads, payloads_num))
+                       return false;
+
+               command.payloads = dal_ddc_i2c_payloads_get(&payloads);
+               command.number_of_payloads = 0;
+               command.engine = DDC_I2C_COMMAND_ENGINE;
+               command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
+
+               i2c_payloads_add(
+                       &payloads, address, write_size, write_buf, true);
+
+               i2c_payloads_add(
+                       &payloads, address, read_size, read_buf, false);
+
+               command.number_of_payloads =
+                       dal_ddc_i2c_payloads_get_count(&payloads);
+
+               success = dm_helpers_submit_i2c(
+                               ddc->ctx,
+                               ddc->link,
+                               &command);
+
+               dal_vector_destruct(&payloads.payloads);
+       }
+
+       return success;
+}
+
+int dc_link_aux_transfer_raw(struct ddc_service *ddc,
+               struct aux_payload *payload,
+               enum aux_return_code_type *operation_result)
+{
+       if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc ||
+           !ddc->ddc_pin) {
+               return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
+       } else {
+               return dce_aux_transfer_raw(ddc, payload, operation_result);
+       }
+}
+
+bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc,
+               struct aux_payload *payload)
+{
+       return dce_aux_transfer_with_retries(ddc, payload);
+}
+
+
+bool try_to_configure_aux_timeout(struct ddc_service *ddc,
+               uint32_t timeout)
+{
+       bool result = false;
+       struct ddc *ddc_pin = ddc->ddc_pin;
+
+       if ((ddc->link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+                       !ddc->link->dc->debug.disable_fixed_vs_aux_timeout_wa &&
+                       ASICREV_IS_YELLOW_CARP(ddc->ctx->asic_id.hw_internal_rev)) {
+               /* Fixed VS workaround for AUX timeout */
+               const uint32_t fixed_vs_address = 0xF004F;
+               const uint8_t fixed_vs_data[4] = {0x1, 0x22, 0x63, 0xc};
+
+               core_link_write_dpcd(ddc->link,
+                               fixed_vs_address,
+                               fixed_vs_data,
+                               sizeof(fixed_vs_data));
+
+               timeout = 3072;
+       }
+
+       /* Do not try to access nonexistent DDC pin. */
+       if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY)
+               return true;
+
+       if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) {
+               ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout);
+               result = true;
+       }
+
+       return result;
+}
+
+struct ddc *get_ddc_pin(struct ddc_service *ddc_service)
+{
+       return ddc_service->ddc_pin;
+}
+
+void write_scdc_data(struct ddc_service *ddc_service,
+               uint32_t pix_clk,
+               bool lte_340_scramble)
+{
+       bool over_340_mhz = pix_clk > 340000 ? 1 : 0;
+       uint8_t slave_address = HDMI_SCDC_ADDRESS;
+       uint8_t offset = HDMI_SCDC_SINK_VERSION;
+       uint8_t sink_version = 0;
+       uint8_t write_buffer[2] = {0};
+       /*Lower than 340 Scramble bit from SCDC caps*/
+
+       if (ddc_service->link->local_sink &&
+               ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
+               return;
+
+       link_query_ddc_data(ddc_service, slave_address, &offset,
+                       sizeof(offset), &sink_version, sizeof(sink_version));
+       if (sink_version == 1) {
+               /*Source Version = 1*/
+               write_buffer[0] = HDMI_SCDC_SOURCE_VERSION;
+               write_buffer[1] = 1;
+               link_query_ddc_data(ddc_service, slave_address,
+                               write_buffer, sizeof(write_buffer), NULL, 0);
+               /*Read Request from SCDC caps*/
+       }
+       write_buffer[0] = HDMI_SCDC_TMDS_CONFIG;
+
+       if (over_340_mhz) {
+               write_buffer[1] = 3;
+       } else if (lte_340_scramble) {
+               write_buffer[1] = 1;
+       } else {
+               write_buffer[1] = 0;
+       }
+       link_query_ddc_data(ddc_service, slave_address, write_buffer,
+                       sizeof(write_buffer), NULL, 0);
+}
+
+void read_scdc_data(struct ddc_service *ddc_service)
+{
+       uint8_t slave_address = HDMI_SCDC_ADDRESS;
+       uint8_t offset = HDMI_SCDC_TMDS_CONFIG;
+       uint8_t tmds_config = 0;
+
+       if (ddc_service->link->local_sink &&
+               ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
+               return;
+
+       link_query_ddc_data(ddc_service, slave_address, &offset,
+                       sizeof(offset), &tmds_config, sizeof(tmds_config));
+       if (tmds_config & 0x1) {
+               union hdmi_scdc_status_flags_data status_data = {0};
+               uint8_t scramble_status = 0;
+
+               offset = HDMI_SCDC_SCRAMBLER_STATUS;
+               link_query_ddc_data(ddc_service, slave_address,
+                               &offset, sizeof(offset), &scramble_status,
+                               sizeof(scramble_status));
+               offset = HDMI_SCDC_STATUS_FLAGS;
+               link_query_ddc_data(ddc_service, slave_address,
+                               &offset, sizeof(offset), &status_data.byte,
+                               sizeof(status_data.byte));
+       }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h
new file mode 100644 (file)
index 0000000..86e9d2e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012-15 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 __DAL_DDC_SERVICE_H__
+#define __DAL_DDC_SERVICE_H__
+
+#include "link.h"
+
+#define AUX_POWER_UP_WA_DELAY 500
+#define I2C_OVER_AUX_DEFER_WA_DELAY 70
+#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40
+#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1
+#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
+
+#define EDID_SEGMENT_SIZE 256
+
+void set_ddc_transaction_type(
+               struct ddc_service *ddc,
+               enum ddc_transaction_type type);
+
+bool try_to_configure_aux_timeout(struct ddc_service *ddc,
+               uint32_t timeout);
+
+void write_scdc_data(
+               struct ddc_service *ddc_service,
+               uint32_t pix_clk,
+               bool lte_340_scramble);
+
+void read_scdc_data(
+               struct ddc_service *ddc_service);
+
+void set_dongle_type(struct ddc_service *ddc,
+               enum display_dongle_type dongle_type);
+
+struct ddc *get_ddc_pin(struct ddc_service *ddc_service);
+
+#endif /* __DAL_DDC_SERVICE_H__ */
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
new file mode 100644 (file)
index 0000000..138e568
--- /dev/null
@@ -0,0 +1,2186 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements dp specific link capability retrieval sequence. It is
+ * responsible for retrieving, parsing, overriding, deciding capability obtained
+ * from dp link. Link capability consists of encoders, DPRXs, cables, retimers,
+ * usb and all other possible backend capabilities. Other components should
+ * include this header file in order to access link capability. Accessing link
+ * capability by dereferencing dc_link outside dp_link_capability is not a
+ * recommended method as it makes the component dependent on the underlying data
+ * structure used to represent link capability instead of function interfaces.
+ */
+
+#include "link_dp_capability.h"
+#include "link_ddc.h"
+#include "link_dpcd.h"
+#include "link_dp_dpia.h"
+#include "link_dp_phy.h"
+#include "link_edp_panel_control.h"
+#include "link_dp_irq_handler.h"
+#include "link/accessories/link_dp_trace.h"
+#include "link_dp_training.h"
+#include "atomfirmware.h"
+#include "resource.h"
+#include "link_enc_cfg.h"
+#include "dc_dmub_srv.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
+
+#ifndef MAX
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#endif
+#ifndef MIN
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
+#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
+
+struct dp_lt_fallback_entry {
+       enum dc_lane_count lane_count;
+       enum dc_link_rate link_rate;
+};
+
+static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = {
+               /* This link training fallback array is ordered by
+                * link bandwidth from highest to lowest.
+                * DP specs makes it a normative policy to always
+                * choose the next highest link bandwidth during
+                * link training fallback.
+                */
+               {LANE_COUNT_FOUR, LINK_RATE_UHBR20},
+               {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5},
+               {LANE_COUNT_TWO, LINK_RATE_UHBR20},
+               {LANE_COUNT_FOUR, LINK_RATE_UHBR10},
+               {LANE_COUNT_TWO, LINK_RATE_UHBR13_5},
+               {LANE_COUNT_FOUR, LINK_RATE_HIGH3},
+               {LANE_COUNT_ONE, LINK_RATE_UHBR20},
+               {LANE_COUNT_TWO, LINK_RATE_UHBR10},
+               {LANE_COUNT_FOUR, LINK_RATE_HIGH2},
+               {LANE_COUNT_ONE, LINK_RATE_UHBR13_5},
+               {LANE_COUNT_TWO, LINK_RATE_HIGH3},
+               {LANE_COUNT_ONE, LINK_RATE_UHBR10},
+               {LANE_COUNT_TWO, LINK_RATE_HIGH2},
+               {LANE_COUNT_FOUR, LINK_RATE_HIGH},
+               {LANE_COUNT_ONE, LINK_RATE_HIGH3},
+               {LANE_COUNT_FOUR, LINK_RATE_LOW},
+               {LANE_COUNT_ONE, LINK_RATE_HIGH2},
+               {LANE_COUNT_TWO, LINK_RATE_HIGH},
+               {LANE_COUNT_TWO, LINK_RATE_LOW},
+               {LANE_COUNT_ONE, LINK_RATE_HIGH},
+               {LANE_COUNT_ONE, LINK_RATE_LOW},
+};
+
+static const struct dc_link_settings fail_safe_link_settings = {
+               .lane_count = LANE_COUNT_ONE,
+               .link_rate = LINK_RATE_LOW,
+               .link_spread = LINK_SPREAD_DISABLED,
+};
+
+bool is_dp_active_dongle(const struct dc_link *link)
+{
+       return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) &&
+                               (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER);
+}
+
+bool is_dp_branch_device(const struct dc_link *link)
+{
+       return link->dpcd_caps.is_branch_dev;
+}
+
+static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc)
+{
+       switch (bpc) {
+       case DOWN_STREAM_MAX_8BPC:
+               return 8;
+       case DOWN_STREAM_MAX_10BPC:
+               return 10;
+       case DOWN_STREAM_MAX_12BPC:
+               return 12;
+       case DOWN_STREAM_MAX_16BPC:
+               return 16;
+       default:
+               break;
+       }
+
+       return -1;
+}
+
+uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count)
+{
+       switch (lttpr_repeater_count) {
+       case 0x80: // 1 lttpr repeater
+               return 1;
+       case 0x40: // 2 lttpr repeaters
+               return 2;
+       case 0x20: // 3 lttpr repeaters
+               return 3;
+       case 0x10: // 4 lttpr repeaters
+               return 4;
+       case 0x08: // 5 lttpr repeaters
+               return 5;
+       case 0x04: // 6 lttpr repeaters
+               return 6;
+       case 0x02: // 7 lttpr repeaters
+               return 7;
+       case 0x01: // 8 lttpr repeaters
+               return 8;
+       default:
+               break;
+       }
+       return 0; // invalid value
+}
+
+uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
+{
+       switch (bw) {
+       case 0b001:
+               return 9000000;
+       case 0b010:
+               return 18000000;
+       case 0b011:
+               return 24000000;
+       case 0b100:
+               return 32000000;
+       case 0b101:
+               return 40000000;
+       case 0b110:
+               return 48000000;
+       }
+
+       return 0;
+}
+
+static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
+{
+       enum dc_link_rate link_rate;
+       // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation.
+       switch (link_rate_in_khz) {
+       case 1620000:
+               link_rate = LINK_RATE_LOW;      // Rate_1 (RBR) - 1.62 Gbps/Lane
+               break;
+       case 2160000:
+               link_rate = LINK_RATE_RATE_2;   // Rate_2       - 2.16 Gbps/Lane
+               break;
+       case 2430000:
+               link_rate = LINK_RATE_RATE_3;   // Rate_3       - 2.43 Gbps/Lane
+               break;
+       case 2700000:
+               link_rate = LINK_RATE_HIGH;     // Rate_4 (HBR) - 2.70 Gbps/Lane
+               break;
+       case 3240000:
+               link_rate = LINK_RATE_RBR2;     // Rate_5 (RBR2)- 3.24 Gbps/Lane
+               break;
+       case 4320000:
+               link_rate = LINK_RATE_RATE_6;   // Rate_6       - 4.32 Gbps/Lane
+               break;
+       case 5400000:
+               link_rate = LINK_RATE_HIGH2;    // Rate_7 (HBR2)- 5.40 Gbps/Lane
+               break;
+       case 8100000:
+               link_rate = LINK_RATE_HIGH3;    // Rate_8 (HBR3)- 8.10 Gbps/Lane
+               break;
+       default:
+               link_rate = LINK_RATE_UNKNOWN;
+               break;
+       }
+       return link_rate;
+}
+
+static union dp_cable_id intersect_cable_id(
+               union dp_cable_id *a, union dp_cable_id *b)
+{
+       union dp_cable_id out;
+
+       out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,
+                       b->bits.UHBR10_20_CAPABILITY);
+       out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,
+                       b->bits.UHBR13_5_CAPABILITY);
+       out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE);
+
+       return out;
+}
+
+/*
+ * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw.
+ */
+static uint32_t intersect_frl_link_bw_support(
+       const uint32_t max_supported_frl_bw_in_kbps,
+       const union hdmi_encoded_link_bw hdmi_encoded_link_bw)
+{
+       uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
+
+       // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
+       if (hdmi_encoded_link_bw.bits.FRL_MODE) {
+               if (hdmi_encoded_link_bw.bits.BW_48Gbps)
+                       supported_bw_in_kbps = 48000000;
+               else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
+                       supported_bw_in_kbps = 40000000;
+               else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
+                       supported_bw_in_kbps = 32000000;
+               else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
+                       supported_bw_in_kbps = 24000000;
+               else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
+                       supported_bw_in_kbps = 18000000;
+               else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
+                       supported_bw_in_kbps = 9000000;
+       }
+
+       return supported_bw_in_kbps;
+}
+
+static enum clock_source_id get_clock_source_id(struct dc_link *link)
+{
+       enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
+       struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
+
+       if (dp_cs != NULL) {
+               dp_cs_id = dp_cs->id;
+       } else {
+               /*
+                * dp clock source is not initialized for some reason.
+                * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
+                */
+               ASSERT(dp_cs);
+       }
+
+       return dp_cs_id;
+}
+
+static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
+               int length)
+{
+       int retry = 0;
+       union dp_downstream_port_present ds_port = { 0 };
+
+       if (!link->dpcd_caps.dpcd_rev.raw) {
+               do {
+                       dc_link_dp_receiver_power_ctrl(link, true);
+                       core_link_read_dpcd(link, DP_DPCD_REV,
+                                                       dpcd_data, length);
+                       link->dpcd_caps.dpcd_rev.raw = dpcd_data[
+                               DP_DPCD_REV -
+                               DP_DPCD_REV];
+               } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw);
+       }
+
+       ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
+                                DP_DPCD_REV];
+
+       if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
+               switch (link->dpcd_caps.branch_dev_id) {
+               /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down
+                * all internal circuits including AUX communication preventing
+                * reading DPCD table and EDID (spec violation).
+                * Encoder will skip DP RX power down on disable_output to
+                * keep receiver powered all the time.*/
+               case DP_BRANCH_DEVICE_ID_0010FA:
+               case DP_BRANCH_DEVICE_ID_0080E1:
+               case DP_BRANCH_DEVICE_ID_00E04C:
+                       link->wa_flags.dp_keep_receiver_powered = true;
+                       break;
+
+               /* TODO: May need work around for other dongles. */
+               default:
+                       link->wa_flags.dp_keep_receiver_powered = false;
+                       break;
+               }
+       } else
+               link->wa_flags.dp_keep_receiver_powered = false;
+}
+
+bool dc_link_is_fec_supported(const struct dc_link *link)
+{
+       /* TODO - use asic cap instead of link_enc->features
+        * we no longer know which link enc to use for this link before commit
+        */
+       struct link_encoder *link_enc = NULL;
+
+       link_enc = link_enc_cfg_get_link_enc(link);
+       ASSERT(link_enc);
+
+       return (dc_is_dp_signal(link->connector_signal) && link_enc &&
+                       link_enc->features.fec_supported &&
+                       link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
+                       !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment));
+}
+
+bool dc_link_should_enable_fec(const struct dc_link *link)
+{
+       bool force_disable = false;
+
+       if (link->fec_state == dc_link_fec_enabled)
+               force_disable = false;
+       else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST &&
+                       link->local_sink &&
+                       link->local_sink->edid_caps.panel_patch.disable_fec)
+               force_disable = true;
+       else if (link->connector_signal == SIGNAL_TYPE_EDP
+                       && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.
+                        dsc_support.DSC_SUPPORT == false
+                               || link->panel_config.dsc.disable_dsc_edp
+                               || !link->dc->caps.edp_dsc_support))
+               force_disable = true;
+
+       return !force_disable && dc_link_is_fec_supported(link);
+}
+
+bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
+{
+       /* If this assert is hit then we have a link encoder dynamic management issue */
+       ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true);
+       return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
+                       pipe_ctx->link_res.hpo_dp_link_enc &&
+                       dc_is_dp_signal(pipe_ctx->stream->signal));
+}
+
+bool dp_is_lttpr_present(struct dc_link *link)
+{
+       return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
+                       link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
+                       link->dpcd_caps.lttpr_caps.max_lane_count <= 4 &&
+                       link->dpcd_caps.lttpr_caps.revision.raw >= 0x14);
+}
+
+/* in DP compliance test, DPR-120 may have
+ * a random value in its MAX_LINK_BW dpcd field.
+ * We map it to the maximum supported link rate that
+ * is smaller than MAX_LINK_BW in this case.
+ */
+static enum dc_link_rate get_link_rate_from_max_link_bw(
+                uint8_t max_link_bw)
+{
+       enum dc_link_rate link_rate;
+
+       if (max_link_bw >= LINK_RATE_HIGH3) {
+               link_rate = LINK_RATE_HIGH3;
+       } else if (max_link_bw < LINK_RATE_HIGH3
+                       && max_link_bw >= LINK_RATE_HIGH2) {
+               link_rate = LINK_RATE_HIGH2;
+       } else if (max_link_bw < LINK_RATE_HIGH2
+                       && max_link_bw >= LINK_RATE_HIGH) {
+               link_rate = LINK_RATE_HIGH;
+       } else if (max_link_bw < LINK_RATE_HIGH
+                       && max_link_bw >= LINK_RATE_LOW) {
+               link_rate = LINK_RATE_LOW;
+       } else {
+               link_rate = LINK_RATE_UNKNOWN;
+       }
+
+       return link_rate;
+}
+
+static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
+{
+       enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
+
+       if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20)
+               lttpr_max_link_rate = LINK_RATE_UHBR20;
+       else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5)
+               lttpr_max_link_rate = LINK_RATE_UHBR13_5;
+       else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10)
+               lttpr_max_link_rate = LINK_RATE_UHBR10;
+
+       return lttpr_max_link_rate;
+}
+
+static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link)
+{
+       enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN;
+
+       if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
+               cable_max_link_rate = LINK_RATE_UHBR20;
+       else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY)
+               cable_max_link_rate = LINK_RATE_UHBR13_5;
+       else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10)
+               cable_max_link_rate = LINK_RATE_UHBR10;
+
+       return cable_max_link_rate;
+}
+
+static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count)
+{
+       return lane_count <= LANE_COUNT_ONE;
+}
+
+static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate)
+{
+       return link_rate <= LINK_RATE_LOW;
+}
+
+static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
+{
+       switch (lane_count) {
+       case LANE_COUNT_FOUR:
+               return LANE_COUNT_TWO;
+       case LANE_COUNT_TWO:
+               return LANE_COUNT_ONE;
+       case LANE_COUNT_ONE:
+               return LANE_COUNT_UNKNOWN;
+       default:
+               return LANE_COUNT_UNKNOWN;
+       }
+}
+
+static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
+{
+       switch (link_rate) {
+       case LINK_RATE_UHBR20:
+               return LINK_RATE_UHBR13_5;
+       case LINK_RATE_UHBR13_5:
+               return LINK_RATE_UHBR10;
+       case LINK_RATE_UHBR10:
+               return LINK_RATE_HIGH3;
+       case LINK_RATE_HIGH3:
+               return LINK_RATE_HIGH2;
+       case LINK_RATE_HIGH2:
+               return LINK_RATE_HIGH;
+       case LINK_RATE_HIGH:
+               return LINK_RATE_LOW;
+       case LINK_RATE_LOW:
+               return LINK_RATE_UNKNOWN;
+       default:
+               return LINK_RATE_UNKNOWN;
+       }
+}
+
+static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count)
+{
+       switch (lane_count) {
+       case LANE_COUNT_ONE:
+               return LANE_COUNT_TWO;
+       case LANE_COUNT_TWO:
+               return LANE_COUNT_FOUR;
+       default:
+               return LANE_COUNT_UNKNOWN;
+       }
+}
+
+static enum dc_link_rate increase_link_rate(struct dc_link *link,
+               enum dc_link_rate link_rate)
+{
+       switch (link_rate) {
+       case LINK_RATE_LOW:
+               return LINK_RATE_HIGH;
+       case LINK_RATE_HIGH:
+               return LINK_RATE_HIGH2;
+       case LINK_RATE_HIGH2:
+               return LINK_RATE_HIGH3;
+       case LINK_RATE_HIGH3:
+               return LINK_RATE_UHBR10;
+       case LINK_RATE_UHBR10:
+               /* upto DP2.x specs UHBR13.5 is the only link rate that could be
+                * not supported by DPRX when higher link rate is supported.
+                * so we treat it as a special case for code simplicity. When we
+                * have new specs with more link rates like this, we should
+                * consider a more generic solution to handle discrete link
+                * rate capabilities.
+                */
+               return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ?
+                               LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20;
+       case LINK_RATE_UHBR13_5:
+               return LINK_RATE_UHBR20;
+       default:
+               return LINK_RATE_UNKNOWN;
+       }
+}
+
+static bool decide_fallback_link_setting_max_bw_policy(
+               struct dc_link *link,
+               const struct dc_link_settings *max,
+               struct dc_link_settings *cur,
+               enum link_training_result training_result)
+{
+       uint8_t cur_idx = 0, next_idx;
+       bool found = false;
+
+       if (training_result == LINK_TRAINING_ABORT)
+               return false;
+
+       while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks))
+               /* find current index */
+               if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count &&
+                               dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate)
+                       break;
+               else
+                       cur_idx++;
+
+       next_idx = cur_idx + 1;
+
+       while (next_idx < ARRAY_SIZE(dp_lt_fallbacks))
+               /* find next index */
+               if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count ||
+                               dp_lt_fallbacks[next_idx].link_rate > max->link_rate)
+                       next_idx++;
+               else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 &&
+                               link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0)
+                       /* upto DP2.x specs UHBR13.5 is the only link rate that
+                        * could be not supported by DPRX when higher link rate
+                        * is supported. so we treat it as a special case for
+                        * code simplicity. When we have new specs with more
+                        * link rates like this, we should consider a more
+                        * generic solution to handle discrete link rate
+                        * capabilities.
+                        */
+                       next_idx++;
+               else
+                       break;
+
+       if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) {
+               cur->lane_count = dp_lt_fallbacks[next_idx].lane_count;
+               cur->link_rate = dp_lt_fallbacks[next_idx].link_rate;
+               found = true;
+       }
+
+       return found;
+}
+
+/*
+ * function: set link rate and lane count fallback based
+ * on current link setting and last link training result
+ * return value:
+ *                     true - link setting could be set
+ *                     false - has reached minimum setting
+ *                                     and no further fallback could be done
+ */
+bool decide_fallback_link_setting(
+               struct dc_link *link,
+               struct dc_link_settings *max,
+               struct dc_link_settings *cur,
+               enum link_training_result training_result)
+{
+       if (link_dp_get_encoding_format(max) == DP_128b_132b_ENCODING ||
+                       link->dc->debug.force_dp2_lt_fallback_method)
+               return decide_fallback_link_setting_max_bw_policy(link, max,
+                               cur, training_result);
+
+       switch (training_result) {
+       case LINK_TRAINING_CR_FAIL_LANE0:
+       case LINK_TRAINING_CR_FAIL_LANE1:
+       case LINK_TRAINING_CR_FAIL_LANE23:
+       case LINK_TRAINING_LQA_FAIL:
+       {
+               if (!reached_minimum_link_rate(cur->link_rate)) {
+                       cur->link_rate = reduce_link_rate(cur->link_rate);
+               } else if (!reached_minimum_lane_count(cur->lane_count)) {
+                       cur->link_rate = max->link_rate;
+                       if (training_result == LINK_TRAINING_CR_FAIL_LANE0)
+                               return false;
+                       else if (training_result == LINK_TRAINING_CR_FAIL_LANE1)
+                               cur->lane_count = LANE_COUNT_ONE;
+                       else if (training_result == LINK_TRAINING_CR_FAIL_LANE23)
+                               cur->lane_count = LANE_COUNT_TWO;
+                       else
+                               cur->lane_count = reduce_lane_count(cur->lane_count);
+               } else {
+                       return false;
+               }
+               break;
+       }
+       case LINK_TRAINING_EQ_FAIL_EQ:
+       case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
+       {
+               if (!reached_minimum_lane_count(cur->lane_count)) {
+                       cur->lane_count = reduce_lane_count(cur->lane_count);
+               } else if (!reached_minimum_link_rate(cur->link_rate)) {
+                       cur->link_rate = reduce_link_rate(cur->link_rate);
+                       /* Reduce max link rate to avoid potential infinite loop.
+                        * Needed so that any subsequent CR_FAIL fallback can't
+                        * re-set the link rate higher than the link rate from
+                        * the latest EQ_FAIL fallback.
+                        */
+                       max->link_rate = cur->link_rate;
+                       cur->lane_count = max->lane_count;
+               } else {
+                       return false;
+               }
+               break;
+       }
+       case LINK_TRAINING_EQ_FAIL_CR:
+       {
+               if (!reached_minimum_link_rate(cur->link_rate)) {
+                       cur->link_rate = reduce_link_rate(cur->link_rate);
+                       /* Reduce max link rate to avoid potential infinite loop.
+                        * Needed so that any subsequent CR_FAIL fallback can't
+                        * re-set the link rate higher than the link rate from
+                        * the latest EQ_FAIL fallback.
+                        */
+                       max->link_rate = cur->link_rate;
+                       cur->lane_count = max->lane_count;
+               } else {
+                       return false;
+               }
+               break;
+       }
+       default:
+               return false;
+       }
+       return true;
+}
+static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
+{
+       struct dc_link_settings initial_link_setting = {
+               LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0};
+       struct dc_link_settings current_link_setting =
+                       initial_link_setting;
+       uint32_t link_bw;
+
+       if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
+               return false;
+
+       /* search for the minimum link setting that:
+        * 1. is supported according to the link training result
+        * 2. could support the b/w requested by the timing
+        */
+       while (current_link_setting.link_rate <=
+                       link->verified_link_cap.link_rate) {
+               link_bw = dc_link_bandwidth_kbps(
+                               link,
+                               &current_link_setting);
+               if (req_bw <= link_bw) {
+                       *link_setting = current_link_setting;
+                       return true;
+               }
+
+               if (current_link_setting.lane_count <
+                               link->verified_link_cap.lane_count) {
+                       current_link_setting.lane_count =
+                                       increase_lane_count(
+                                                       current_link_setting.lane_count);
+               } else {
+                       current_link_setting.link_rate =
+                                       increase_link_rate(link,
+                                                       current_link_setting.link_rate);
+                       current_link_setting.lane_count =
+                                       initial_link_setting.lane_count;
+               }
+       }
+
+       return false;
+}
+
+bool dc_link_decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
+{
+       struct dc_link_settings initial_link_setting;
+       struct dc_link_settings current_link_setting;
+       uint32_t link_bw;
+
+       /*
+        * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
+        * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
+        */
+       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
+                       link->dpcd_caps.edp_supported_link_rates_count == 0) {
+               *link_setting = link->verified_link_cap;
+               return true;
+       }
+
+       memset(&initial_link_setting, 0, sizeof(initial_link_setting));
+       initial_link_setting.lane_count = LANE_COUNT_ONE;
+       initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
+       initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
+       initial_link_setting.use_link_rate_set = true;
+       initial_link_setting.link_rate_set = 0;
+       current_link_setting = initial_link_setting;
+
+       /* search for the minimum link setting that:
+        * 1. is supported according to the link training result
+        * 2. could support the b/w requested by the timing
+        */
+       while (current_link_setting.link_rate <=
+                       link->verified_link_cap.link_rate) {
+               link_bw = dc_link_bandwidth_kbps(
+                               link,
+                               &current_link_setting);
+               if (req_bw <= link_bw) {
+                       *link_setting = current_link_setting;
+                       return true;
+               }
+
+               if (current_link_setting.lane_count <
+                               link->verified_link_cap.lane_count) {
+                       current_link_setting.lane_count =
+                                       increase_lane_count(
+                                                       current_link_setting.lane_count);
+               } else {
+                       if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
+                               current_link_setting.link_rate_set++;
+                               current_link_setting.link_rate =
+                                       link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+                               current_link_setting.lane_count =
+                                                                       initial_link_setting.lane_count;
+                       } else
+                               break;
+               }
+       }
+       return false;
+}
+
+bool decide_edp_link_settings_with_dsc(struct dc_link *link,
+               struct dc_link_settings *link_setting,
+               uint32_t req_bw,
+               enum dc_link_rate max_link_rate)
+{
+       struct dc_link_settings initial_link_setting;
+       struct dc_link_settings current_link_setting;
+       uint32_t link_bw;
+
+       unsigned int policy = 0;
+
+       policy = link->panel_config.dsc.force_dsc_edp_policy;
+       if (max_link_rate == LINK_RATE_UNKNOWN)
+               max_link_rate = link->verified_link_cap.link_rate;
+       /*
+        * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
+        * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
+        */
+       if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
+                       link->dpcd_caps.edp_supported_link_rates_count == 0)) {
+               /* for DSC enabled case, we search for minimum lane count */
+               memset(&initial_link_setting, 0, sizeof(initial_link_setting));
+               initial_link_setting.lane_count = LANE_COUNT_ONE;
+               initial_link_setting.link_rate = LINK_RATE_LOW;
+               initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
+               initial_link_setting.use_link_rate_set = false;
+               initial_link_setting.link_rate_set = 0;
+               current_link_setting = initial_link_setting;
+               if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
+                       return false;
+
+               /* search for the minimum link setting that:
+                * 1. is supported according to the link training result
+                * 2. could support the b/w requested by the timing
+                */
+               while (current_link_setting.link_rate <=
+                               max_link_rate) {
+                       link_bw = dc_link_bandwidth_kbps(
+                                       link,
+                                       &current_link_setting);
+                       if (req_bw <= link_bw) {
+                               *link_setting = current_link_setting;
+                               return true;
+                       }
+                       if (policy) {
+                               /* minimize lane */
+                               if (current_link_setting.link_rate < max_link_rate) {
+                                       current_link_setting.link_rate =
+                                                       increase_link_rate(link,
+                                                                       current_link_setting.link_rate);
+                               } else {
+                                       if (current_link_setting.lane_count <
+                                                                       link->verified_link_cap.lane_count) {
+                                               current_link_setting.lane_count =
+                                                               increase_lane_count(
+                                                                               current_link_setting.lane_count);
+                                               current_link_setting.link_rate = initial_link_setting.link_rate;
+                                       } else
+                                               break;
+                               }
+                       } else {
+                               /* minimize link rate */
+                               if (current_link_setting.lane_count <
+                                               link->verified_link_cap.lane_count) {
+                                       current_link_setting.lane_count =
+                                                       increase_lane_count(
+                                                                       current_link_setting.lane_count);
+                               } else {
+                                       current_link_setting.link_rate =
+                                                       increase_link_rate(link,
+                                                                       current_link_setting.link_rate);
+                                       current_link_setting.lane_count =
+                                                       initial_link_setting.lane_count;
+                               }
+                       }
+               }
+               return false;
+       }
+
+       /* if optimize edp link is supported */
+       memset(&initial_link_setting, 0, sizeof(initial_link_setting));
+       initial_link_setting.lane_count = LANE_COUNT_ONE;
+       initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
+       initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
+       initial_link_setting.use_link_rate_set = true;
+       initial_link_setting.link_rate_set = 0;
+       current_link_setting = initial_link_setting;
+
+       /* search for the minimum link setting that:
+        * 1. is supported according to the link training result
+        * 2. could support the b/w requested by the timing
+        */
+       while (current_link_setting.link_rate <=
+                       max_link_rate) {
+               link_bw = dc_link_bandwidth_kbps(
+                               link,
+                               &current_link_setting);
+               if (req_bw <= link_bw) {
+                       *link_setting = current_link_setting;
+                       return true;
+               }
+               if (policy) {
+                       /* minimize lane */
+                       if (current_link_setting.link_rate_set <
+                                       link->dpcd_caps.edp_supported_link_rates_count
+                                       && current_link_setting.link_rate < max_link_rate) {
+                               current_link_setting.link_rate_set++;
+                               current_link_setting.link_rate =
+                                       link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+                       } else {
+                               if (current_link_setting.lane_count < link->verified_link_cap.lane_count) {
+                                       current_link_setting.lane_count =
+                                                       increase_lane_count(
+                                                                       current_link_setting.lane_count);
+                                       current_link_setting.link_rate_set = initial_link_setting.link_rate_set;
+                                       current_link_setting.link_rate =
+                                               link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+                               } else
+                                       break;
+                       }
+               } else {
+                       /* minimize link rate */
+                       if (current_link_setting.lane_count <
+                                       link->verified_link_cap.lane_count) {
+                               current_link_setting.lane_count =
+                                               increase_lane_count(
+                                                               current_link_setting.lane_count);
+                       } else {
+                               if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
+                                       current_link_setting.link_rate_set++;
+                                       current_link_setting.link_rate =
+                                               link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+                                       current_link_setting.lane_count =
+                                               initial_link_setting.lane_count;
+                               } else
+                                       break;
+                       }
+               }
+       }
+       return false;
+}
+
+static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting)
+{
+       *link_setting = link->verified_link_cap;
+       return true;
+}
+
+bool link_decide_link_settings(struct dc_stream_state *stream,
+       struct dc_link_settings *link_setting)
+{
+       struct dc_link *link = stream->link;
+       uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
+
+       memset(link_setting, 0, sizeof(*link_setting));
+
+       /* if preferred is specified through AMDDP, use it, if it's enough
+        * to drive the mode
+        */
+       if (link->preferred_link_setting.lane_count !=
+                       LANE_COUNT_UNKNOWN &&
+                       link->preferred_link_setting.link_rate !=
+                                       LINK_RATE_UNKNOWN) {
+               *link_setting = link->preferred_link_setting;
+               return true;
+       }
+
+       /* MST doesn't perform link training for now
+        * TODO: add MST specific link training routine
+        */
+       if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+               decide_mst_link_settings(link, link_setting);
+       } else if (link->connector_signal == SIGNAL_TYPE_EDP) {
+               /* enable edp link optimization for DSC eDP case */
+               if (stream->timing.flags.DSC) {
+                       enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN;
+
+                       if (link->panel_config.dsc.force_dsc_edp_policy) {
+                               /* calculate link max link rate cap*/
+                               struct dc_link_settings tmp_link_setting;
+                               struct dc_crtc_timing tmp_timing = stream->timing;
+                               uint32_t orig_req_bw;
+
+                               tmp_link_setting.link_rate = LINK_RATE_UNKNOWN;
+                               tmp_timing.flags.DSC = 0;
+                               orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing);
+                               dc_link_decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw);
+                               max_link_rate = tmp_link_setting.link_rate;
+                       }
+                       decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate);
+               } else {
+                       dc_link_decide_edp_link_settings(link, link_setting, req_bw);
+               }
+       } else {
+               decide_dp_link_settings(link, link_setting, req_bw);
+       }
+
+       return link_setting->lane_count != LANE_COUNT_UNKNOWN &&
+                       link_setting->link_rate != LINK_RATE_UNKNOWN;
+}
+
+enum dp_link_encoding link_dp_get_encoding_format(const struct dc_link_settings *link_settings)
+{
+       if ((link_settings->link_rate >= LINK_RATE_LOW) &&
+                       (link_settings->link_rate <= LINK_RATE_HIGH3))
+               return DP_8b_10b_ENCODING;
+       else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
+                       (link_settings->link_rate <= LINK_RATE_UHBR20))
+               return DP_128b_132b_ENCODING;
+       return DP_UNKNOWN_ENCODING;
+}
+
+enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link)
+{
+       struct dc_link_settings link_settings = {0};
+
+       if (!dc_is_dp_signal(link->connector_signal))
+               return DP_UNKNOWN_ENCODING;
+
+       if (link->preferred_link_setting.lane_count !=
+                       LANE_COUNT_UNKNOWN &&
+                       link->preferred_link_setting.link_rate !=
+                                       LINK_RATE_UNKNOWN) {
+               link_settings = link->preferred_link_setting;
+       } else {
+               decide_mst_link_settings(link, &link_settings);
+       }
+
+       return link_dp_get_encoding_format(&link_settings);
+}
+
+static void read_dp_device_vendor_id(struct dc_link *link)
+{
+       struct dp_device_vendor_id dp_id;
+
+       /* read IEEE branch device id */
+       core_link_read_dpcd(
+               link,
+               DP_BRANCH_OUI,
+               (uint8_t *)&dp_id,
+               sizeof(dp_id));
+
+       link->dpcd_caps.branch_dev_id =
+               (dp_id.ieee_oui[0] << 16) +
+               (dp_id.ieee_oui[1] << 8) +
+               dp_id.ieee_oui[2];
+
+       memmove(
+               link->dpcd_caps.branch_dev_name,
+               dp_id.ieee_device_id,
+               sizeof(dp_id.ieee_device_id));
+}
+
+static enum dc_status wake_up_aux_channel(struct dc_link *link)
+{
+       enum dc_status status = DC_ERROR_UNEXPECTED;
+       uint32_t aux_channel_retry_cnt = 0;
+       uint8_t dpcd_power_state = '\0';
+
+       while (status != DC_OK && aux_channel_retry_cnt < 10) {
+               status = core_link_read_dpcd(link, DP_SET_POWER,
+                               &dpcd_power_state, sizeof(dpcd_power_state));
+
+               /* Delay 1 ms if AUX CH is in power down state. Based on spec
+                * section 2.3.1.2, if AUX CH may be powered down due to
+                * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
+                * signal and may need up to 1 ms before being able to reply.
+                */
+               if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
+                       udelay(1000);
+                       aux_channel_retry_cnt++;
+               }
+       }
+
+       if (status != DC_OK) {
+               dpcd_power_state = DP_SET_POWER_D0;
+               status = core_link_write_dpcd(
+                               link,
+                               DP_SET_POWER,
+                               &dpcd_power_state,
+                               sizeof(dpcd_power_state));
+
+               dpcd_power_state = DP_SET_POWER_D3;
+               status = core_link_write_dpcd(
+                               link,
+                               DP_SET_POWER,
+                               &dpcd_power_state,
+                               sizeof(dpcd_power_state));
+               return DC_ERROR_UNEXPECTED;
+       }
+
+       return DC_OK;
+}
+
+static void get_active_converter_info(
+       uint8_t data, struct dc_link *link)
+{
+       union dp_downstream_port_present ds_port = { .byte = data };
+       memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
+
+       /* decode converter info*/
+       if (!ds_port.fields.PORT_PRESENT) {
+               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
+               set_dongle_type(link->ddc,
+                               link->dpcd_caps.dongle_type);
+               link->dpcd_caps.is_branch_dev = false;
+               return;
+       }
+
+       /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */
+       link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT;
+
+       switch (ds_port.fields.PORT_TYPE) {
+       case DOWNSTREAM_VGA:
+               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
+               break;
+       case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS:
+               /* At this point we don't know is it DVI or HDMI or DP++,
+                * assume DVI.*/
+               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
+               break;
+       default:
+               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
+               break;
+       }
+
+       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) {
+               uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/
+               union dwnstream_port_caps_byte0 *port_caps =
+                       (union dwnstream_port_caps_byte0 *)det_caps;
+               if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0,
+                               det_caps, sizeof(det_caps)) == DC_OK) {
+
+                       switch (port_caps->bits.DWN_STRM_PORTX_TYPE) {
+                       /*Handle DP case as DONGLE_NONE*/
+                       case DOWN_STREAM_DETAILED_DP:
+                               link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
+                               break;
+                       case DOWN_STREAM_DETAILED_VGA:
+                               link->dpcd_caps.dongle_type =
+                                       DISPLAY_DONGLE_DP_VGA_CONVERTER;
+                               break;
+                       case DOWN_STREAM_DETAILED_DVI:
+                               link->dpcd_caps.dongle_type =
+                                       DISPLAY_DONGLE_DP_DVI_CONVERTER;
+                               break;
+                       case DOWN_STREAM_DETAILED_HDMI:
+                       case DOWN_STREAM_DETAILED_DP_PLUS_PLUS:
+                               /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/
+                               link->dpcd_caps.dongle_type =
+                                       DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+
+                               link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type;
+                               if (ds_port.fields.DETAILED_CAPS) {
+
+                                       union dwnstream_port_caps_byte3_hdmi
+                                               hdmi_caps = {.raw = det_caps[3] };
+                                       union dwnstream_port_caps_byte2
+                                               hdmi_color_caps = {.raw = det_caps[2] };
+                                       link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz =
+                                               det_caps[1] * 2500;
+
+                                       link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter =
+                                               hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK;
+                                       /*YCBCR capability only for HDMI case*/
+                                       if (port_caps->bits.DWN_STRM_PORTX_TYPE
+                                                       == DOWN_STREAM_DETAILED_HDMI) {
+                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through =
+                                                               hdmi_caps.bits.YCrCr422_PASS_THROUGH;
+                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through =
+                                                               hdmi_caps.bits.YCrCr420_PASS_THROUGH;
+                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter =
+                                                               hdmi_caps.bits.YCrCr422_CONVERSION;
+                                               link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter =
+                                                               hdmi_caps.bits.YCrCr420_CONVERSION;
+                                       }
+
+                                       link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc =
+                                               translate_dpcd_max_bpc(
+                                                       hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
+
+                                       if (link->dc->caps.dp_hdmi21_pcon_support) {
+                                               union hdmi_encoded_link_bw hdmi_encoded_link_bw;
+
+                                               link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps =
+                                                               dc_link_bw_kbps_from_raw_frl_link_rate_data(
+                                                                               hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT);
+
+                                               // Intersect reported max link bw support with the supported link rate post FRL link training
+                                               if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS,
+                                                               &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) {
+                                                       link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support(
+                                                                       link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps,
+                                                                       hdmi_encoded_link_bw);
+                                               }
+
+                                               if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0)
+                                                       link->dpcd_caps.dongle_caps.extendedCapValid = true;
+                                       }
+
+                                       if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0)
+                                               link->dpcd_caps.dongle_caps.extendedCapValid = true;
+                               }
+
+                               break;
+                       }
+               }
+       }
+
+       set_dongle_type(link->ddc, link->dpcd_caps.dongle_type);
+
+       {
+               struct dp_sink_hw_fw_revision dp_hw_fw_revision;
+
+               core_link_read_dpcd(
+                       link,
+                       DP_BRANCH_REVISION_START,
+                       (uint8_t *)&dp_hw_fw_revision,
+                       sizeof(dp_hw_fw_revision));
+
+               link->dpcd_caps.branch_hw_revision =
+                       dp_hw_fw_revision.ieee_hw_rev;
+
+               memmove(
+                       link->dpcd_caps.branch_fw_revision,
+                       dp_hw_fw_revision.ieee_fw_rev,
+                       sizeof(dp_hw_fw_revision.ieee_fw_rev));
+       }
+       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
+                       link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
+               union dp_dfp_cap_ext dfp_cap_ext;
+               memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext));
+               core_link_read_dpcd(
+                               link,
+                               DP_DFP_CAPABILITY_EXTENSION_SUPPORT,
+                               dfp_cap_ext.raw,
+                               sizeof(dfp_cap_ext.raw));
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported;
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps =
+                               dfp_cap_ext.fields.max_pixel_rate_in_mps[0] +
+                               (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8);
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width =
+                               dfp_cap_ext.fields.max_video_h_active_width[0] +
+                               (dfp_cap_ext.fields.max_video_h_active_width[1] << 8);
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height =
+                               dfp_cap_ext.fields.max_video_v_active_height[0] +
+                               (dfp_cap_ext.fields.max_video_v_active_height[1] << 8);
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps =
+                               dfp_cap_ext.fields.encoding_format_caps;
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps =
+                               dfp_cap_ext.fields.rgb_color_depth_caps;
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps =
+                               dfp_cap_ext.fields.ycbcr444_color_depth_caps;
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps =
+                               dfp_cap_ext.fields.ycbcr422_color_depth_caps;
+               link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps =
+                               dfp_cap_ext.fields.ycbcr420_color_depth_caps;
+               DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index);
+               DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false");
+               DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps);
+               DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width);
+               DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height);
+       }
+}
+
+static void apply_usbc_combo_phy_reset_wa(struct dc_link *link,
+               struct dc_link_settings *link_settings)
+{
+       /* Temporary Renoir-specific workaround PHY will sometimes be in bad
+        * state on hotplugging display from certain USB-C dongle, so add extra
+        * cycle of enabling and disabling the PHY before first link training.
+        */
+       struct link_resource link_res = {0};
+       enum clock_source_id dp_cs_id = get_clock_source_id(link);
+
+       dp_enable_link_phy(link, &link_res, link->connector_signal,
+                       dp_cs_id, link_settings);
+       dp_disable_link_phy(link, &link_res, link->connector_signal);
+}
+
+static bool dp_overwrite_extended_receiver_cap(struct dc_link *link)
+{
+       uint8_t dpcd_data[16];
+       uint32_t read_dpcd_retry_cnt = 3;
+       enum dc_status status = DC_ERROR_UNEXPECTED;
+       union dp_downstream_port_present ds_port = { 0 };
+       union down_stream_port_count down_strm_port_count;
+       union edp_configuration_cap edp_config_cap;
+
+       int i;
+
+       for (i = 0; i < read_dpcd_retry_cnt; i++) {
+               status = core_link_read_dpcd(
+                               link,
+                               DP_DPCD_REV,
+                               dpcd_data,
+                               sizeof(dpcd_data));
+               if (status == DC_OK)
+                       break;
+       }
+
+       link->dpcd_caps.dpcd_rev.raw =
+               dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
+
+       if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
+               return false;
+
+       ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
+                       DP_DPCD_REV];
+
+       get_active_converter_info(ds_port.byte, link);
+
+       down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
+                       DP_DPCD_REV];
+
+       link->dpcd_caps.allow_invalid_MSA_timing_param =
+               down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
+
+       link->dpcd_caps.max_ln_count.raw = dpcd_data[
+               DP_MAX_LANE_COUNT - DP_DPCD_REV];
+
+       link->dpcd_caps.max_down_spread.raw = dpcd_data[
+               DP_MAX_DOWNSPREAD - DP_DPCD_REV];
+
+       link->reported_link_cap.lane_count =
+               link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
+       link->reported_link_cap.link_rate = dpcd_data[
+               DP_MAX_LINK_RATE - DP_DPCD_REV];
+       link->reported_link_cap.link_spread =
+               link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
+               LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
+
+       edp_config_cap.raw = dpcd_data[
+               DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
+       link->dpcd_caps.panel_mode_edp =
+               edp_config_cap.bits.ALT_SCRAMBLER_RESET;
+       link->dpcd_caps.dpcd_display_control_capable =
+               edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
+
+       return true;
+}
+
+void dc_link_overwrite_extended_receiver_cap(
+               struct dc_link *link)
+{
+       dp_overwrite_extended_receiver_cap(link);
+}
+
+void dpcd_set_source_specific_data(struct dc_link *link)
+{
+       if (!link->dc->vendor_signature.is_valid) {
+               enum dc_status result_write_min_hblank = DC_NOT_SUPPORTED;
+               struct dpcd_amd_signature amd_signature = {0};
+               struct dpcd_amd_device_id amd_device_id = {0};
+
+               amd_device_id.device_id_byte1 =
+                               (uint8_t)(link->ctx->asic_id.chip_id);
+               amd_device_id.device_id_byte2 =
+                               (uint8_t)(link->ctx->asic_id.chip_id >> 8);
+               amd_device_id.dce_version =
+                               (uint8_t)(link->ctx->dce_version);
+               amd_device_id.dal_version_byte1 = 0x0; // needed? where to get?
+               amd_device_id.dal_version_byte2 = 0x0; // needed? where to get?
+
+               core_link_read_dpcd(link, DP_SOURCE_OUI,
+                               (uint8_t *)(&amd_signature),
+                               sizeof(amd_signature));
+
+               if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) &&
+                       (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) &&
+                       (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) {
+
+                       amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0;
+                       amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0;
+                       amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A;
+
+                       core_link_write_dpcd(link, DP_SOURCE_OUI,
+                               (uint8_t *)(&amd_signature),
+                               sizeof(amd_signature));
+               }
+
+               core_link_write_dpcd(link, DP_SOURCE_OUI+0x03,
+                               (uint8_t *)(&amd_device_id),
+                               sizeof(amd_device_id));
+
+               if (link->ctx->dce_version >= DCN_VERSION_2_0 &&
+                       link->dc->caps.min_horizontal_blanking_period != 0) {
+
+                       uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period;
+
+                       result_write_min_hblank = core_link_write_dpcd(link,
+                               DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size),
+                               sizeof(hblank_size));
+               }
+               DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
+                                                       WPP_BIT_FLAG_DC_DETECTION_DP_CAPS,
+                                                       "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'",
+                                                       result_write_min_hblank,
+                                                       link->link_index,
+                                                       link->ctx->dce_version,
+                                                       DP_SOURCE_MINIMUM_HBLANK_SUPPORTED,
+                                                       link->dc->caps.min_horizontal_blanking_period,
+                                                       link->dpcd_caps.branch_dev_id,
+                                                       link->dpcd_caps.branch_dev_name[0],
+                                                       link->dpcd_caps.branch_dev_name[1],
+                                                       link->dpcd_caps.branch_dev_name[2],
+                                                       link->dpcd_caps.branch_dev_name[3],
+                                                       link->dpcd_caps.branch_dev_name[4],
+                                                       link->dpcd_caps.branch_dev_name[5]);
+       } else {
+               core_link_write_dpcd(link, DP_SOURCE_OUI,
+                               link->dc->vendor_signature.data.raw,
+                               sizeof(link->dc->vendor_signature.data.raw));
+       }
+}
+
+void dpcd_write_cable_id_to_dprx(struct dc_link *link)
+{
+       if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED ||
+                       link->dpcd_caps.cable_id.raw == 0 ||
+                       link->dprx_states.cable_id_written)
+               return;
+
+       core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX,
+                       &link->dpcd_caps.cable_id.raw,
+                       sizeof(link->dpcd_caps.cable_id.raw));
+
+       link->dprx_states.cable_id_written = 1;
+}
+
+static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id)
+{
+       union dmub_rb_cmd cmd;
+
+       if (!link->ctx->dmub_srv ||
+                       link->ep_type != DISPLAY_ENDPOINT_PHY ||
+                       link->link_enc->features.flags.bits.DP_IS_USB_C == 0)
+               return false;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID;
+       cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data);
+       cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx(
+                       link->dc, link->link_enc->transmitter);
+       if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) &&
+                       cmd.cable_id.header.ret_status == 1) {
+               cable_id->raw = cmd.cable_id.data.output_raw;
+               DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw);
+       }
+       return cmd.cable_id.header.ret_status == 1;
+}
+
+static void retrieve_cable_id(struct dc_link *link)
+{
+       union dp_cable_id usbc_cable_id;
+
+       link->dpcd_caps.cable_id.raw = 0;
+       core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
+                       &link->dpcd_caps.cable_id.raw, sizeof(uint8_t));
+
+       if (get_usbc_cable_id(link, &usbc_cable_id))
+               link->dpcd_caps.cable_id = intersect_cable_id(
+                               &link->dpcd_caps.cable_id, &usbc_cable_id);
+}
+
+bool read_is_mst_supported(struct dc_link *link)
+{
+       bool mst          = false;
+       enum dc_status st = DC_OK;
+       union dpcd_rev rev;
+       union mstm_cap cap;
+
+       if (link->preferred_training_settings.mst_enable &&
+               *link->preferred_training_settings.mst_enable == false) {
+               return false;
+       }
+
+       rev.raw  = 0;
+       cap.raw  = 0;
+
+       st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw,
+                       sizeof(rev));
+
+       if (st == DC_OK && rev.raw >= DPCD_REV_12) {
+
+               st = core_link_read_dpcd(link, DP_MSTM_CAP,
+                               &cap.raw, sizeof(cap));
+               if (st == DC_OK && cap.bits.MST_CAP == 1)
+                       mst = true;
+       }
+       return mst;
+
+}
+
+/* Read additional sink caps defined in source specific DPCD area
+ * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP)
+ * TODO: Add FS caps and read from DP_SOURCE_SINK_FS_CAP as well
+ */
+static bool dpcd_read_sink_ext_caps(struct dc_link *link)
+{
+       uint8_t dpcd_data;
+
+       if (!link)
+               return false;
+
+       if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK)
+               return false;
+
+       link->dpcd_sink_ext_caps.raw = dpcd_data;
+       return true;
+}
+
+enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
+{
+       uint8_t lttpr_dpcd_data[8];
+       enum dc_status status;
+       bool is_lttpr_present;
+
+       /* Logic to determine LTTPR support*/
+       bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
+
+       if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support)
+               return DC_NOT_SUPPORTED;
+
+       /* By reading LTTPR capability, RX assumes that we will enable
+        * LTTPR extended aux timeout if LTTPR is present.
+        */
+       status = core_link_read_dpcd(
+                       link,
+                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
+                       lttpr_dpcd_data,
+                       sizeof(lttpr_dpcd_data));
+
+       link->dpcd_caps.lttpr_caps.revision.raw =
+                       lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       link->dpcd_caps.lttpr_caps.max_link_rate =
+                       lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       link->dpcd_caps.lttpr_caps.phy_repeater_cnt =
+                       lttpr_dpcd_data[DP_PHY_REPEATER_CNT -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       link->dpcd_caps.lttpr_caps.max_lane_count =
+                       lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       link->dpcd_caps.lttpr_caps.mode =
+                       lttpr_dpcd_data[DP_PHY_REPEATER_MODE -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       link->dpcd_caps.lttpr_caps.max_ext_timeout =
+                       lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+       link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw =
+                       lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw =
+                       lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES -
+                                                       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+       /* If this chip cap is set, at least one retimer must exist in the chain
+        * Override count to 1 if we receive a known bad count (0 or an invalid value) */
+       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+                       (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) {
+               ASSERT(0);
+               link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80;
+               DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+       }
+
+       /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
+       is_lttpr_present = dp_is_lttpr_present(link);
+
+       if (is_lttpr_present)
+               CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
+
+       DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present);
+       return status;
+}
+
+static bool retrieve_link_cap(struct dc_link *link)
+{
+       /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
+        * which means size 16 will be good for both of those DPCD register block reads
+        */
+       uint8_t dpcd_data[16];
+       /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
+        */
+       uint8_t dpcd_dprx_data = '\0';
+
+       struct dp_device_vendor_id sink_id;
+       union down_stream_port_count down_strm_port_count;
+       union edp_configuration_cap edp_config_cap;
+       union dp_downstream_port_present ds_port = { 0 };
+       enum dc_status status = DC_ERROR_UNEXPECTED;
+       uint32_t read_dpcd_retry_cnt = 3;
+       int i;
+       struct dp_sink_hw_fw_revision dp_hw_fw_revision;
+       const uint32_t post_oui_delay = 30; // 30ms
+
+       memset(dpcd_data, '\0', sizeof(dpcd_data));
+       memset(&down_strm_port_count,
+               '\0', sizeof(union down_stream_port_count));
+       memset(&edp_config_cap, '\0',
+               sizeof(union edp_configuration_cap));
+
+       /* if extended timeout is supported in hardware,
+        * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer
+        * CTS 4.2.1.1 regression introduced by CTS specs requirement update.
+        */
+       try_to_configure_aux_timeout(link->ddc,
+                       LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
+
+       status = dp_retrieve_lttpr_cap(link);
+
+       if (status != DC_OK) {
+               status = wake_up_aux_channel(link);
+               if (status == DC_OK)
+                       dp_retrieve_lttpr_cap(link);
+               else
+                       return false;
+       }
+
+       if (dp_is_lttpr_present(link))
+               configure_lttpr_mode_transparent(link);
+
+       /* Read DP tunneling information. */
+       status = dpcd_get_tunneling_device_data(link);
+
+       dpcd_set_source_specific_data(link);
+       /* Sink may need to configure internals based on vendor, so allow some
+        * time before proceeding with possibly vendor specific transactions
+        */
+       msleep(post_oui_delay);
+
+       for (i = 0; i < read_dpcd_retry_cnt; i++) {
+               status = core_link_read_dpcd(
+                               link,
+                               DP_DPCD_REV,
+                               dpcd_data,
+                               sizeof(dpcd_data));
+               if (status == DC_OK)
+                       break;
+       }
+
+
+       if (status != DC_OK) {
+               dm_error("%s: Read receiver caps dpcd data failed.\n", __func__);
+               return false;
+       }
+
+       if (!dp_is_lttpr_present(link))
+               try_to_configure_aux_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
+
+
+       {
+               union training_aux_rd_interval aux_rd_interval;
+
+               aux_rd_interval.raw =
+                       dpcd_data[DP_TRAINING_AUX_RD_INTERVAL];
+
+               link->dpcd_caps.ext_receiver_cap_field_present =
+                               aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1 ? true:false;
+
+               if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) {
+                       uint8_t ext_cap_data[16];
+
+                       memset(ext_cap_data, '\0', sizeof(ext_cap_data));
+                       for (i = 0; i < read_dpcd_retry_cnt; i++) {
+                               status = core_link_read_dpcd(
+                               link,
+                               DP_DP13_DPCD_REV,
+                               ext_cap_data,
+                               sizeof(ext_cap_data));
+                               if (status == DC_OK) {
+                                       memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data));
+                                       break;
+                               }
+                       }
+                       if (status != DC_OK)
+                               dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__);
+               }
+       }
+
+       link->dpcd_caps.dpcd_rev.raw =
+                       dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
+
+       if (link->dpcd_caps.ext_receiver_cap_field_present) {
+               for (i = 0; i < read_dpcd_retry_cnt; i++) {
+                       status = core_link_read_dpcd(
+                                       link,
+                                       DP_DPRX_FEATURE_ENUMERATION_LIST,
+                                       &dpcd_dprx_data,
+                                       sizeof(dpcd_dprx_data));
+                       if (status == DC_OK)
+                               break;
+               }
+
+               link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data;
+
+               if (status != DC_OK)
+                       dm_error("%s: Read DPRX caps data failed.\n", __func__);
+
+               /* AdaptiveSyncCapability  */
+               dpcd_dprx_data = 0;
+               for (i = 0; i < read_dpcd_retry_cnt; i++) {
+                       status = core_link_read_dpcd(
+                                       link, DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1,
+                                       &dpcd_dprx_data, sizeof(dpcd_dprx_data));
+                       if (status == DC_OK)
+                               break;
+               }
+
+               link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.raw = dpcd_dprx_data;
+
+               if (status != DC_OK)
+                       dm_error("%s: Read DPRX caps data failed. Addr:%#x\n",
+                                       __func__, DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1);
+       }
+
+       else {
+               link->dpcd_caps.dprx_feature.raw = 0;
+       }
+
+
+       /* Error condition checking...
+        * It is impossible for Sink to report Max Lane Count = 0.
+        * It is possible for Sink to report Max Link Rate = 0, if it is
+        * an eDP device that is reporting specialized link rates in the
+        * SUPPORTED_LINK_RATE table.
+        */
+       if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
+               return false;
+
+       ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
+                                DP_DPCD_REV];
+
+       read_dp_device_vendor_id(link);
+
+       /* TODO - decouple raw mst capability from policy decision */
+       link->dpcd_caps.is_mst_capable = read_is_mst_supported(link);
+
+       get_active_converter_info(ds_port.byte, link);
+
+       dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
+
+       down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
+                                DP_DPCD_REV];
+
+       link->dpcd_caps.allow_invalid_MSA_timing_param =
+               down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
+
+       link->dpcd_caps.max_ln_count.raw = dpcd_data[
+               DP_MAX_LANE_COUNT - DP_DPCD_REV];
+
+       link->dpcd_caps.max_down_spread.raw = dpcd_data[
+               DP_MAX_DOWNSPREAD - DP_DPCD_REV];
+
+       link->reported_link_cap.lane_count =
+               link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
+       link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw(
+                       dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]);
+       link->reported_link_cap.link_spread =
+               link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
+               LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
+
+       edp_config_cap.raw = dpcd_data[
+               DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
+       link->dpcd_caps.panel_mode_edp =
+               edp_config_cap.bits.ALT_SCRAMBLER_RESET;
+       link->dpcd_caps.dpcd_display_control_capable =
+               edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
+       link->dpcd_caps.channel_coding_cap.raw =
+                       dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV];
+       link->test_pattern_enabled = false;
+       link->compliance_test_state.raw = 0;
+
+       /* read sink count */
+       core_link_read_dpcd(link,
+                       DP_SINK_COUNT,
+                       &link->dpcd_caps.sink_count.raw,
+                       sizeof(link->dpcd_caps.sink_count.raw));
+
+       /* read sink ieee oui */
+       core_link_read_dpcd(link,
+                       DP_SINK_OUI,
+                       (uint8_t *)(&sink_id),
+                       sizeof(sink_id));
+
+       link->dpcd_caps.sink_dev_id =
+                       (sink_id.ieee_oui[0] << 16) +
+                       (sink_id.ieee_oui[1] << 8) +
+                       (sink_id.ieee_oui[2]);
+
+       memmove(
+               link->dpcd_caps.sink_dev_id_str,
+               sink_id.ieee_device_id,
+               sizeof(sink_id.ieee_device_id));
+
+       core_link_read_dpcd(
+               link,
+               DP_SINK_HW_REVISION_START,
+               (uint8_t *)&dp_hw_fw_revision,
+               sizeof(dp_hw_fw_revision));
+
+       link->dpcd_caps.sink_hw_revision =
+               dp_hw_fw_revision.ieee_hw_rev;
+
+       memmove(
+               link->dpcd_caps.sink_fw_revision,
+               dp_hw_fw_revision.ieee_fw_rev,
+               sizeof(dp_hw_fw_revision.ieee_fw_rev));
+
+       /* Quirk for Retina panels: wrong DP_MAX_LINK_RATE */
+       {
+               uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
+               uint8_t fwrev_mbp_2018[] = { 7, 4 };
+               uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
+
+               /* We also check for the firmware revision as 16,1 models have an
+                * identical device id and are incorrectly quirked otherwise.
+                */
+               if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+                   !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
+                            sizeof(str_mbp_2018)) &&
+                   (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
+                            sizeof(fwrev_mbp_2018)) ||
+                   !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
+                            sizeof(fwrev_mbp_2018_vega)))) {
+                       link->reported_link_cap.link_rate = LINK_RATE_RBR2;
+               }
+       }
+
+       memset(&link->dpcd_caps.dsc_caps, '\0',
+                       sizeof(link->dpcd_caps.dsc_caps));
+       memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
+       /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
+       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
+               status = core_link_read_dpcd(
+                               link,
+                               DP_FEC_CAPABILITY,
+                               &link->dpcd_caps.fec_cap.raw,
+                               sizeof(link->dpcd_caps.fec_cap.raw));
+               status = core_link_read_dpcd(
+                               link,
+                               DP_DSC_SUPPORT,
+                               link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
+                               sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
+               if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
+                       status = core_link_read_dpcd(
+                                       link,
+                                       DP_DSC_BRANCH_OVERALL_THROUGHPUT_0,
+                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
+                                       sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw));
+                       DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index);
+                       DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x",
+                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0);
+                       DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x",
+                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1);
+                       DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x",
+                                       link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH);
+               }
+
+               /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode
+                * only if required.
+                */
+               if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+                               link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around &&
+                               link->dpcd_caps.is_branch_dev &&
+                               link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
+                               link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 &&
+                               (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE ||
+                               link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) {
+                       /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA.
+                        * Clear FEC and DSC capabilities as a work around if that is not the case.
+                        */
+                       link->wa_flags.dpia_forced_tbt3_mode = true;
+                       memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps));
+                       memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
+                       DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index);
+               } else
+                       link->wa_flags.dpia_forced_tbt3_mode = false;
+       }
+
+       if (!dpcd_read_sink_ext_caps(link))
+               link->dpcd_sink_ext_caps.raw = 0;
+
+       if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
+               DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index);
+
+               core_link_read_dpcd(link,
+                               DP_128B132B_SUPPORTED_LINK_RATES,
+                               &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw,
+                               sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw));
+               if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20)
+                       link->reported_link_cap.link_rate = LINK_RATE_UHBR20;
+               else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5)
+                       link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5;
+               else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10)
+                       link->reported_link_cap.link_rate = LINK_RATE_UHBR10;
+               else
+                       dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__);
+               DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index);
+               DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz",
+                               link->reported_link_cap.link_rate / 100,
+                               link->reported_link_cap.link_rate % 100);
+
+               core_link_read_dpcd(link,
+                               DP_SINK_VIDEO_FALLBACK_FORMATS,
+                               &link->dpcd_caps.fallback_formats.raw,
+                               sizeof(link->dpcd_caps.fallback_formats.raw));
+               DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index);
+               if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support)
+                       DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported");
+               if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support)
+                       DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported");
+               if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support)
+                       DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported");
+               if (link->dpcd_caps.fallback_formats.raw == 0) {
+                       DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported");
+                       link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1;
+               }
+
+               core_link_read_dpcd(link,
+                               DP_FEC_CAPABILITY_1,
+                               &link->dpcd_caps.fec_cap1.raw,
+                               sizeof(link->dpcd_caps.fec_cap1.raw));
+               DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index);
+               if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE)
+                       DC_LOG_DP2("\tFEC aggregated error counters are supported");
+       }
+
+       retrieve_cable_id(link);
+       dpcd_write_cable_id_to_dprx(link);
+
+       /* Connectivity log: detection */
+       CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
+
+       return true;
+}
+
+bool detect_dp_sink_caps(struct dc_link *link)
+{
+       return retrieve_link_cap(link);
+}
+
+void detect_edp_sink_caps(struct dc_link *link)
+{
+       uint8_t supported_link_rates[16];
+       uint32_t entry;
+       uint32_t link_rate_in_khz;
+       enum dc_link_rate link_rate = LINK_RATE_UNKNOWN;
+       uint8_t backlight_adj_cap;
+       uint8_t general_edp_cap;
+
+       retrieve_link_cap(link);
+       link->dpcd_caps.edp_supported_link_rates_count = 0;
+       memset(supported_link_rates, 0, sizeof(supported_link_rates));
+
+       /*
+        * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
+        * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
+        */
+       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
+                       (link->panel_config.ilr.optimize_edp_link_rate ||
+                       link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) {
+               // Read DPCD 00010h - 0001Fh 16 bytes at one shot
+               core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
+                                                       supported_link_rates, sizeof(supported_link_rates));
+
+               for (entry = 0; entry < 16; entry += 2) {
+                       // DPCD register reports per-lane link rate = 16-bit link rate capability
+                       // value X 200 kHz. Need multiplier to find link rate in kHz.
+                       link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
+                                                                               supported_link_rates[entry]) * 200;
+
+                       if (link_rate_in_khz != 0) {
+                               link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz);
+                               link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate;
+                               link->dpcd_caps.edp_supported_link_rates_count++;
+
+                               if (link->reported_link_cap.link_rate < link_rate)
+                                       link->reported_link_cap.link_rate = link_rate;
+                       }
+               }
+       }
+       core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP,
+                                               &backlight_adj_cap, sizeof(backlight_adj_cap));
+
+       link->dpcd_caps.dynamic_backlight_capable_edp =
+                               (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false;
+
+       core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1,
+                                               &general_edp_cap, sizeof(general_edp_cap));
+
+       link->dpcd_caps.set_power_state_capable_edp =
+                               (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false;
+
+       set_default_brightness_aux(link);
+
+       core_link_read_dpcd(link, DP_EDP_DPCD_REV,
+               &link->dpcd_caps.edp_rev,
+               sizeof(link->dpcd_caps.edp_rev));
+       /*
+        * PSR is only valid for eDP v1.3 or higher.
+        */
+       if (link->dpcd_caps.edp_rev >= DP_EDP_13) {
+               core_link_read_dpcd(link, DP_PSR_SUPPORT,
+                       &link->dpcd_caps.psr_info.psr_version,
+                       sizeof(link->dpcd_caps.psr_info.psr_version));
+               if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
+                       core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY,
+                                               &link->dpcd_caps.psr_info.force_psrsu_cap,
+                                               sizeof(link->dpcd_caps.psr_info.force_psrsu_cap));
+               core_link_read_dpcd(link, DP_PSR_CAPS,
+                       &link->dpcd_caps.psr_info.psr_dpcd_caps.raw,
+                       sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw));
+               if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) {
+                       core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY,
+                               &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap,
+                               sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap));
+               }
+       }
+
+       /*
+        * ALPM is only valid for eDP v1.4 or higher.
+        */
+       if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14)
+               core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP,
+                       &link->dpcd_caps.alpm_caps.raw,
+                       sizeof(link->dpcd_caps.alpm_caps.raw));
+}
+
+bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
+{
+       struct link_encoder *link_enc = NULL;
+
+       if (!max_link_enc_cap) {
+               DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__);
+               return false;
+       }
+
+       link_enc = link_enc_cfg_get_link_enc(link);
+       ASSERT(link_enc);
+
+       if (link_enc && link_enc->funcs->get_max_link_cap) {
+               link_enc->funcs->get_max_link_cap(link_enc, max_link_enc_cap);
+               return true;
+       }
+
+       DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__);
+       max_link_enc_cap->lane_count = 1;
+       max_link_enc_cap->link_rate = 6;
+       return false;
+}
+
+const struct dc_link_settings *dc_link_get_link_cap(
+               const struct dc_link *link)
+{
+       if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN &&
+                       link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
+               return &link->preferred_link_setting;
+       return &link->verified_link_cap;
+}
+
+struct dc_link_settings dp_get_max_link_cap(struct dc_link *link)
+{
+       struct dc_link_settings max_link_cap = {0};
+       enum dc_link_rate lttpr_max_link_rate;
+       enum dc_link_rate cable_max_link_rate;
+       struct link_encoder *link_enc = NULL;
+
+
+       link_enc = link_enc_cfg_get_link_enc(link);
+       ASSERT(link_enc);
+
+       /* get max link encoder capability */
+       if (link_enc)
+               link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap);
+
+       /* Lower link settings based on sink's link cap */
+       if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
+               max_link_cap.lane_count =
+                               link->reported_link_cap.lane_count;
+       if (link->reported_link_cap.link_rate < max_link_cap.link_rate)
+               max_link_cap.link_rate =
+                               link->reported_link_cap.link_rate;
+       if (link->reported_link_cap.link_spread <
+                       max_link_cap.link_spread)
+               max_link_cap.link_spread =
+                               link->reported_link_cap.link_spread;
+
+       /* Lower link settings based on cable attributes
+        * Cable ID is a DP2 feature to identify max certified link rate that
+        * a cable can carry. The cable identification method requires both
+        * cable and display hardware support. Since the specs comes late, it is
+        * anticipated that the first round of DP2 cables and displays may not
+        * be fully compatible to reliably return cable ID data. Therefore the
+        * decision of our cable id policy is that if the cable can return non
+        * zero cable id data, we will take cable's link rate capability into
+        * account. However if we get zero data, the cable link rate capability
+        * is considered inconclusive. In this case, we will not take cable's
+        * capability into account to avoid of over limiting hardware capability
+        * from users. The max overall link rate capability is still determined
+        * after actual dp pre-training. Cable id is considered as an auxiliary
+        * method of determining max link bandwidth capability.
+        */
+       cable_max_link_rate = get_cable_max_link_rate(link);
+
+       if (!link->dc->debug.ignore_cable_id &&
+                       cable_max_link_rate != LINK_RATE_UNKNOWN &&
+                       cable_max_link_rate < max_link_cap.link_rate)
+               max_link_cap.link_rate = cable_max_link_rate;
+
+       /* account for lttpr repeaters cap
+        * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
+        */
+       if (dp_is_lttpr_present(link)) {
+               if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count)
+                       max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count;
+               lttpr_max_link_rate = get_lttpr_max_link_rate(link);
+
+               if (lttpr_max_link_rate < max_link_cap.link_rate)
+                       max_link_cap.link_rate = lttpr_max_link_rate;
+
+               DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR,  max_lane count %d max_link rate %d \n",
+                                               __func__,
+                                               max_link_cap.lane_count,
+                                               max_link_cap.link_rate);
+       }
+
+       if (link_dp_get_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING &&
+                       link->dc->debug.disable_uhbr)
+               max_link_cap.link_rate = LINK_RATE_HIGH3;
+
+       return max_link_cap;
+}
+
+static bool dp_verify_link_cap(
+       struct dc_link *link,
+       struct dc_link_settings *known_limit_link_setting,
+       int *fail_count)
+{
+       struct dc_link_settings cur_link_settings = {0};
+       struct dc_link_settings max_link_settings = *known_limit_link_setting;
+       bool success = false;
+       bool skip_video_pattern;
+       enum clock_source_id dp_cs_id = get_clock_source_id(link);
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+       union hpd_irq_data irq_data;
+       struct link_resource link_res;
+
+       memset(&irq_data, 0, sizeof(irq_data));
+       cur_link_settings = max_link_settings;
+
+       /* Grant extended timeout request */
+       if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) {
+               uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80;
+
+               core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
+       }
+
+       do {
+               if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings))
+                       continue;
+
+               skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW;
+               dp_enable_link_phy(
+                               link,
+                               &link_res,
+                               link->connector_signal,
+                               dp_cs_id,
+                               &cur_link_settings);
+
+               status = dp_perform_link_training(
+                               link,
+                               &link_res,
+                               &cur_link_settings,
+                               skip_video_pattern);
+
+               if (status == LINK_TRAINING_SUCCESS) {
+                       success = true;
+                       udelay(1000);
+                       if (dp_read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
+                                       dc_link_check_link_loss_status(
+                                                       link,
+                                                       &irq_data))
+                               (*fail_count)++;
+
+               } else {
+                       (*fail_count)++;
+               }
+               dp_trace_lt_total_count_increment(link, true);
+               dp_trace_lt_result_update(link, status, true);
+               dp_disable_link_phy(link, &link_res, link->connector_signal);
+       } while (!success && decide_fallback_link_setting(link,
+                       &max_link_settings, &cur_link_settings, status));
+
+       link->verified_link_cap = success ?
+                       cur_link_settings : fail_safe_link_settings;
+       return success;
+}
+
+bool dp_verify_link_cap_with_retries(
+       struct dc_link *link,
+       struct dc_link_settings *known_limit_link_setting,
+       int attempts)
+{
+       int i = 0;
+       bool success = false;
+       int fail_count = 0;
+
+       dp_trace_detect_lt_init(link);
+
+       if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
+                       link->dc->debug.usbc_combo_phy_reset_wa)
+               apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting);
+
+       dp_trace_set_lt_start_timestamp(link, false);
+       for (i = 0; i < attempts; i++) {
+               enum dc_connection_type type = dc_connection_none;
+
+               memset(&link->verified_link_cap, 0,
+                               sizeof(struct dc_link_settings));
+               if (!dc_link_detect_sink(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,
+                               &fail_count) && fail_count == 0) {
+                       success = true;
+                       break;
+               }
+               msleep(10);
+       }
+
+       dp_trace_lt_fail_count_update(link, fail_count, true);
+       dp_trace_set_lt_end_timestamp(link, true);
+
+       return success;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h
new file mode 100644 (file)
index 0000000..f79e4a4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DP_CAPABILITY_H__
+#define __DC_LINK_DP_CAPABILITY_H__
+
+#include "link.h"
+
+bool detect_dp_sink_caps(struct dc_link *link);
+
+void detect_edp_sink_caps(struct dc_link *link);
+
+struct dc_link_settings dp_get_max_link_cap(struct dc_link *link);
+
+
+enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
+
+/* Convert PHY repeater count read from DPCD uint8_t. */
+uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count);
+
+bool dp_is_lttpr_present(struct dc_link *link);
+
+bool is_dp_active_dongle(const struct dc_link *link);
+
+bool is_dp_branch_device(const struct dc_link *link);
+
+void dpcd_write_cable_id_to_dprx(struct dc_link *link);
+
+/* Initialize output parameter lt_settings. */
+void dp_decide_training_settings(
+       struct dc_link *link,
+       const struct dc_link_settings *link_setting,
+       struct link_training_settings *lt_settings);
+
+
+bool decide_edp_link_settings_with_dsc(struct dc_link *link,
+               struct dc_link_settings *link_setting,
+               uint32_t req_bw,
+               enum dc_link_rate max_link_rate);
+
+void dpcd_set_source_specific_data(struct dc_link *link);
+
+/*query dpcd for version and mst cap addresses*/
+bool read_is_mst_supported(struct dc_link *link);
+
+bool decide_fallback_link_setting(
+               struct dc_link *link,
+               struct dc_link_settings *max,
+               struct dc_link_settings *cur,
+               enum link_training_result training_result);
+
+bool dp_verify_link_cap_with_retries(
+       struct dc_link *link,
+       struct dc_link_settings *known_limit_link_setting,
+       int attempts);
+
+#endif /* __DC_LINK_DP_CAPABILITY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c
new file mode 100644 (file)
index 0000000..a57a2be
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2021 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 "dc.h"
+#include "inc/core_status.h"
+#include "dc_link.h"
+#include "dpcd_defs.h"
+
+#include "link_dp_dpia.h"
+#include "link_hwss.h"
+#include "dm_helpers.h"
+#include "dmub/inc/dmub_cmd.h"
+#include "link_dpcd.h"
+#include "link_dp_training.h"
+#include "dc_dmub_srv.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */
+/* DPCD DP Tunneling over USB4 */
+#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d
+#define DP_IN_ADAPTER_INFO                0xe000e
+#define DP_USB4_DRIVER_ID                 0xe000f
+#define DP_USB4_ROUTER_TOPOLOGY_ID        0xe001b
+
+enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
+{
+       enum dc_status status = DC_OK;
+       uint8_t dpcd_dp_tun_data[3] = {0};
+       uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0};
+       uint8_t i = 0;
+
+       status = core_link_read_dpcd(
+                       link,
+                       DP_TUNNELING_CAPABILITIES_SUPPORT,
+                       dpcd_dp_tun_data,
+                       sizeof(dpcd_dp_tun_data));
+
+       status = core_link_read_dpcd(
+                       link,
+                       DP_USB4_ROUTER_TOPOLOGY_ID,
+                       dpcd_topology_data,
+                       sizeof(dpcd_topology_data));
+
+       link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw =
+                       dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - DP_TUNNELING_CAPABILITIES_SUPPORT];
+       link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw =
+                       dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT];
+       link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id =
+                       dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT];
+
+       for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++)
+               link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i];
+
+       return status;
+}
+
+bool dc_link_dpia_query_hpd_status(struct dc_link *link)
+{
+       union dmub_rb_cmd cmd = {0};
+       struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv;
+       bool is_hpd_high = false;
+
+       /* prepare QUERY_HPD command */
+       cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE;
+       cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1;
+       cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA;
+
+       /* Return HPD status reported by DMUB if query successfully executed. */
+       if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS)
+               is_hpd_high = cmd.query_hpd.data.result;
+
+       DC_LOG_DEBUG("%s: link(%d) dpia(%d) cmd_status(%d) result(%d)\n",
+               __func__,
+               link->link_index,
+               link->link_id.enum_id - ENUM_ID_1,
+               cmd.query_hpd.data.status,
+               cmd.query_hpd.data.result);
+
+       return is_hpd_high;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h
new file mode 100644 (file)
index 0000000..98935cc
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2021 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_DPIA_H__
+#define __DC_LINK_DPIA_H__
+
+#include "link.h"
+
+/* Read tunneling device capability from DPCD and update link capability
+ * accordingly.
+ */
+enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link);
+
+/* Query hot plug status of USB4 DP tunnel.
+ * Returns true if HPD high.
+ */
+bool dc_link_dpia_query_hpd_status(struct dc_link *link);
+
+
+#endif /* __DC_LINK_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c
new file mode 100644 (file)
index 0000000..801a95b
--- /dev/null
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+/*********************************************************************/
+//                             USB4 DPIA BANDWIDTH ALLOCATION LOGIC
+/*********************************************************************/
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h
new file mode 100644 (file)
index 0000000..58eb7b5
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021 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_INC_LINK_DP_DPIA_BW_H_
+#define DC_INC_LINK_DP_DPIA_BW_H_
+
+/*
+ * Host Router BW type
+ */
+enum bw_type {
+       HOST_ROUTER_BW_ESTIMATED,
+       HOST_ROUTER_BW_ALLOCATED,
+       HOST_ROUTER_BW_INVALID,
+};
+
+/*
+ * Enable BW Allocation Mode Support from the DP-Tx side
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: SUCCESS or FAILURE
+ */
+bool set_dptx_usb4_bw_alloc_support(struct dc_link *link);
+
+/*
+ * Send a request from DP-Tx requesting to allocate BW remotely after
+ * allocating it locally. This will get processed by CM and a CB function
+ * will be called.
+ *
+ * @link: pointer to the dc_link struct instance
+ * @req_bw: The requested bw in Kbyte to allocated
+ *
+ * return: none
+ */
+void set_usb4_req_bw_req(struct dc_link *link, int req_bw);
+
+/*
+ * CB function for when the status of the Req above is complete. We will
+ * find out the result of allocating on CM and update structs accordingly
+ *
+ * @link: pointer to the dc_link struct instance
+ * @bw: Allocated or Estimated BW depending on the result
+ * @result: Response type
+ *
+ * return: none
+ */
+void get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result);
+
+/*
+ * Return the response_ready flag from dc_link struct
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: response_ready flag from dc_link struct
+ */
+bool get_cm_response_ready_flag(struct dc_link *link);
+
+/*
+ * Get the Max Available BW or Max Estimated BW for each Host Router
+ *
+ * @link: pointer to the dc_link struct instance
+ * @type: ESTIMATD BW or MAX AVAILABLE BW
+ *
+ * return: response_ready flag from dc_link struct
+ */
+int get_host_router_total_bw(struct dc_link *link, uint8_t type);
+
+/*
+ * Cleanup function for when the dpia is unplugged to reset struct
+ * and perform any required clean up
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: none
+ */
+bool dpia_bw_alloc_unplug(struct dc_link *link);
+
+#endif /* DC_INC_LINK_DP_DPIA_BW_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
new file mode 100644 (file)
index 0000000..9a832a9
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ *
+ */
+
+#include "link_dp_irq_handler.h"
+#include "link_dpcd.h"
+#include "link_dp_training.h"
+#include "link_dp_capability.h"
+#include "link/accessories/link_dp_trace.h"
+#include "dm_helpers.h"
+
+#define DC_LOGGER_INIT(logger)
+
+bool dc_link_check_link_loss_status(
+       struct dc_link *link,
+       union hpd_irq_data *hpd_irq_dpcd_data)
+{
+       uint8_t irq_reg_rx_power_state = 0;
+       enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
+       union lane_status lane_status;
+       uint32_t lane;
+       bool sink_status_changed;
+       bool return_code;
+
+       sink_status_changed = false;
+       return_code = false;
+
+       if (link->cur_link_settings.lane_count == 0)
+               return return_code;
+
+       /*1. Check that Link Status changed, before re-training.*/
+
+       /*parse lane status*/
+       for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
+               /* check status of lanes 0,1
+                * changed DpcdAddress_Lane01Status (0x202)
+                */
+               lane_status.raw = dp_get_nibble_at_index(
+                       &hpd_irq_dpcd_data->bytes.lane01_status.raw,
+                       lane);
+
+               if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
+                       !lane_status.bits.CR_DONE_0 ||
+                       !lane_status.bits.SYMBOL_LOCKED_0) {
+                       /* if one of the channel equalization, clock
+                        * recovery or symbol lock is dropped
+                        * consider it as (link has been
+                        * dropped) dp sink status has changed
+                        */
+                       sink_status_changed = true;
+                       break;
+               }
+       }
+
+       /* Check interlane align.*/
+       if (sink_status_changed ||
+               !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
+
+               DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
+
+               return_code = true;
+
+               /*2. Check that we can handle interrupt: Not in FS DOS,
+                *  Not in "Display Timeout" state, Link is trained.
+                */
+               dpcd_result = core_link_read_dpcd(link,
+                       DP_SET_POWER,
+                       &irq_reg_rx_power_state,
+                       sizeof(irq_reg_rx_power_state));
+
+               if (dpcd_result != DC_OK) {
+                       DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
+                               __func__);
+               } else {
+                       if (irq_reg_rx_power_state != DP_SET_POWER_D0)
+                               return_code = false;
+               }
+       }
+
+       return return_code;
+}
+
+static bool handle_hpd_irq_psr_sink(struct dc_link *link)
+{
+       union dpcd_psr_configuration psr_configuration;
+
+       if (!link->psr_settings.psr_feature_enabled)
+               return false;
+
+       dm_helpers_dp_read_dpcd(
+               link->ctx,
+               link,
+               368,/*DpcdAddress_PSR_Enable_Cfg*/
+               &psr_configuration.raw,
+               sizeof(psr_configuration.raw));
+
+       if (psr_configuration.bits.ENABLE) {
+               unsigned char dpcdbuf[3] = {0};
+               union psr_error_status psr_error_status;
+               union psr_sink_psr_status psr_sink_psr_status;
+
+               dm_helpers_dp_read_dpcd(
+                       link->ctx,
+                       link,
+                       0x2006, /*DpcdAddress_PSR_Error_Status*/
+                       (unsigned char *) dpcdbuf,
+                       sizeof(dpcdbuf));
+
+               /*DPCD 2006h   ERROR STATUS*/
+               psr_error_status.raw = dpcdbuf[0];
+               /*DPCD 2008h   SINK PANEL SELF REFRESH STATUS*/
+               psr_sink_psr_status.raw = dpcdbuf[2];
+
+               if (psr_error_status.bits.LINK_CRC_ERROR ||
+                               psr_error_status.bits.RFB_STORAGE_ERROR ||
+                               psr_error_status.bits.VSC_SDP_ERROR) {
+                       bool allow_active;
+
+                       /* Acknowledge and clear error bits */
+                       dm_helpers_dp_write_dpcd(
+                               link->ctx,
+                               link,
+                               8198,/*DpcdAddress_PSR_Error_Status*/
+                               &psr_error_status.raw,
+                               sizeof(psr_error_status.raw));
+
+                       /* PSR error, disable and re-enable PSR */
+                       if (link->psr_settings.psr_allow_active) {
+                               allow_active = false;
+                               dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
+                               allow_active = true;
+                               dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
+                       }
+
+                       return true;
+               } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS ==
+                               PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){
+                       /* No error is detect, PSR is active.
+                        * We should return with IRQ_HPD handled without
+                        * checking for loss of sync since PSR would have
+                        * powered down main link.
+                        */
+                       return true;
+               }
+       }
+       return false;
+}
+
+void dc_link_dp_handle_link_loss(struct dc_link *link)
+{
+       int i;
+       struct pipe_ctx *pipe_ctx;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
+               if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
+                       break;
+       }
+
+       if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
+               return;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               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);
+       }
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               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) {
+                       // Always use max settings here for DP 1.4a LL Compliance CTS
+                       if (link->is_automated) {
+                               pipe_ctx->link_config.dp_link_settings.lane_count =
+                                               link->verified_link_cap.lane_count;
+                               pipe_ctx->link_config.dp_link_settings.link_rate =
+                                               link->verified_link_cap.link_rate;
+                               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);
+               }
+       }
+}
+
+enum dc_status dp_read_hpd_rx_irq_data(
+       struct dc_link *link,
+       union hpd_irq_data *irq_data)
+{
+       static enum dc_status retval;
+
+       /* The HW reads 16 bytes from 200h on HPD,
+        * but if we get an AUX_DEFER, the HW cannot retry
+        * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
+        * fail, so we now explicitly read 6 bytes which is
+        * the req from the above mentioned test cases.
+        *
+        * For DP 1.4 we need to read those from 2002h range.
+        */
+       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT,
+                       irq_data->raw,
+                       sizeof(union hpd_irq_data));
+       else {
+               /* Read 14 bytes in a single read and then copy only the required fields.
+                * This is more efficient than doing it in two separate AUX reads. */
+
+               uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
+
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT_ESI,
+                       tmp,
+                       sizeof(tmp));
+
+               if (retval != DC_OK)
+                       return retval;
+
+               irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
+               irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
+               irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
+       }
+
+       return retval;
+}
+
+/*************************Short Pulse IRQ***************************/
+bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link)
+{
+       /*
+        * Don't handle RX IRQ unless one of following is met:
+        * 1) The link is established (cur_link_settings != unknown)
+        * 2) We know we're dealing with a branch device, SST or MST
+        */
+
+       if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
+               is_dp_branch_device(link))
+               return true;
+
+       return false;
+}
+
+bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
+                                                       bool defer_handling, bool *has_left_work)
+{
+       union hpd_irq_data hpd_irq_dpcd_data = {0};
+       union device_service_irq device_service_clear = {0};
+       enum dc_status result;
+       bool status = false;
+
+       if (out_link_loss)
+               *out_link_loss = false;
+
+       if (has_left_work)
+               *has_left_work = false;
+       /* For use cases related to down stream connection status change,
+        * PSR and device auto test, refer to function handle_sst_hpd_irq
+        * in DAL2.1*/
+
+       DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
+               __func__, link->link_index);
+
+
+        /* All the "handle_hpd_irq_xxx()" methods
+                * should be called only after
+                * 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);
+       if (out_hpd_irq_dpcd_data)
+               *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data;
+
+       if (result != DC_OK) {
+               DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",
+                       __func__);
+               return false;
+       }
+
+       if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
+               // Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC
+               link->is_automated = true;
+               device_service_clear.bits.AUTOMATED_TEST = 1;
+               core_link_write_dpcd(
+                       link,
+                       DP_DEVICE_SERVICE_IRQ_VECTOR,
+                       &device_service_clear.raw,
+                       sizeof(device_service_clear.raw));
+               device_service_clear.raw = 0;
+               if (defer_handling && has_left_work)
+                       *has_left_work = true;
+               else
+                       dc_link_dp_handle_automated_test(link);
+               return false;
+       }
+
+       if (!dc_link_dp_allow_hpd_rx_irq(link)) {
+               DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
+                       __func__, link->link_index);
+               return false;
+       }
+
+       if (handle_hpd_irq_psr_sink(link))
+               /* PSR-related error was detected and handled */
+               return true;
+
+       /* If PSR-related error handled, Main link may be off,
+        * so do not handle as a normal sink status change interrupt.
+        */
+
+       if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) {
+               if (defer_handling && has_left_work)
+                       *has_left_work = true;
+               return true;
+       }
+
+       /* check if we have MST msg and return since we poll for it */
+       if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
+               if (defer_handling && has_left_work)
+                       *has_left_work = true;
+               return false;
+       }
+
+       /* For now we only handle 'Downstream port status' case.
+        * If we got sink count changed it means
+        * Downstream port status changed,
+        * then DM should call DC to do the detection.
+        * NOTE: Do not handle link loss on eDP since it is internal link*/
+       if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
+               dc_link_check_link_loss_status(
+                       link,
+                       &hpd_irq_dpcd_data)) {
+               /* Connectivity log: link loss */
+               CONN_DATA_LINK_LOSS(link,
+                                       hpd_irq_dpcd_data.raw,
+                                       sizeof(hpd_irq_dpcd_data),
+                                       "Status: ");
+
+               if (defer_handling && has_left_work)
+                       *has_left_work = true;
+               else
+                       dc_link_dp_handle_link_loss(link);
+
+               status = false;
+               if (out_link_loss)
+                       *out_link_loss = true;
+
+               dp_trace_link_loss_increment(link);
+       }
+
+       if (link->type == dc_connection_sst_branch &&
+               hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
+                       != link->dpcd_sink_count)
+               status = true;
+
+       /* reasons for HPD RX:
+        * 1. Link Loss - ie Re-train the Link
+        * 2. MST sideband message
+        * 3. Automated Test - ie. Internal Commit
+        * 4. CP (copy protection) - (not interesting for DM???)
+        * 5. DRR
+        * 6. Downstream Port status changed
+        * -ie. Detect - this the only one
+        * which is interesting for DM because
+        * it must call dc_link_detect.
+        */
+       return status;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h
new file mode 100644 (file)
index 0000000..cac7acd
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DP_IRQ_HANDLER_H__
+#define __DC_LINK_DP_IRQ_HANDLER_H__
+
+#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__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c
new file mode 100644 (file)
index 0000000..5e53162
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements basic dp phy functionality such as enable/disable phy
+ * output and set lane/drive settings. This file is responsible for maintaining
+ * and update software state representing current phy status such as current
+ * link settings.
+ */
+
+#include "link_dp_phy.h"
+#include "link_dpcd.h"
+#include "link_dp_training.h"
+#include "link_dp_capability.h"
+#include "clk_mgr.h"
+#include "resource.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on)
+{
+       uint8_t state;
+
+       state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
+
+       if (link->sync_lt_in_progress)
+               return;
+
+       core_link_write_dpcd(link, DP_SET_POWER, &state,
+                                                sizeof(state));
+
+}
+
+void dp_enable_link_phy(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       enum signal_type signal,
+       enum clock_source_id clock_source,
+       const struct dc_link_settings *link_settings)
+{
+       link->cur_link_settings = *link_settings;
+       link->dc->hwss.enable_dp_link_output(link, link_res, signal,
+                       clock_source, link_settings);
+       dc_link_dp_receiver_power_ctrl(link, true);
+}
+
+void dp_disable_link_phy(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+{
+       struct dc  *dc = link->ctx->dc;
+
+       if (!link->wa_flags.dp_keep_receiver_powered)
+               dc_link_dp_receiver_power_ctrl(link, false);
+
+       dc->hwss.disable_link_output(link, link_res, signal);
+       /* Clear current link setting.*/
+       memset(&link->cur_link_settings, 0,
+                       sizeof(link->cur_link_settings));
+
+       if (dc->clk_mgr->funcs->notify_link_rate_change)
+               dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
+}
+
+void dp_disable_link_phy_mst(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+{
+       /* MST disable link only when no stream use the link */
+       if (link->mst_stream_alloc_table.stream_count > 0)
+               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)
+{
+       return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ==
+                       offset);
+}
+
+void dp_set_hw_lane_settings(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       const struct link_training_settings *link_settings,
+       uint32_t offset)
+{
+       const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+
+       if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) &&
+                       !is_immediate_downstream(link, offset))
+               return;
+
+       if (link_hwss->ext.set_dp_lane_settings)
+               link_hwss->ext.set_dp_lane_settings(link, link_res,
+                               &link_settings->link_settings,
+                               link_settings->hw_lane_settings);
+
+       memmove(link->cur_lane_setting,
+                       link_settings->hw_lane_settings,
+                       sizeof(link->cur_lane_setting));
+}
+
+void dp_set_drive_settings(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings)
+{
+       /* program ASIC PHY settings*/
+       dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
+
+       dp_hw_to_dpcd_lane_settings(lt_settings,
+                       lt_settings->hw_lane_settings,
+                       lt_settings->dpcd_lane_settings);
+
+       /* Notify DP sink the PHY settings from source */
+       dpcd_set_lane_settings(link, lt_settings, DPRX);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h
new file mode 100644 (file)
index 0000000..850da64
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DP_PHY_H__
+#define __DC_LINK_DP_PHY_H__
+
+#include "link.h"
+void dp_enable_link_phy(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       enum signal_type signal,
+       enum clock_source_id clock_source,
+       const struct dc_link_settings *link_settings);
+
+void dp_disable_link_phy(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal);
+
+void dp_disable_link_phy_mst(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal);
+
+void dp_set_hw_lane_settings(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct link_training_settings *link_settings,
+               uint32_t offset);
+
+void dp_set_drive_settings(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings);
+
+#endif /* __DC_LINK_DP_PHY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
new file mode 100644 (file)
index 0000000..18ec09b
--- /dev/null
@@ -0,0 +1,1700 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements all generic dp link training helper functions and top
+ * level generic training sequence. All variations of dp link training sequence
+ * should be called inside the top level training functions in this file to
+ * ensure the integrity of our overall training procedure across different types
+ * of link encoding and back end hardware.
+ */
+#include "link_dp_training.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dp_training_128b_132b.h"
+#include "link_dp_training_auxless.h"
+#include "link_dp_training_dpia.h"
+#include "link_dp_training_fixed_vs_pe_retimer.h"
+#include "link_dpcd.h"
+#include "link/accessories/link_dp_trace.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+#include "link_edp_panel_control.h"
+#include "atomfirmware.h"
+#include "link_enc_cfg.h"
+#include "resource.h"
+#include "dm_helpers.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+#define POST_LT_ADJ_REQ_LIMIT 6
+#define POST_LT_ADJ_REQ_TIMEOUT 200
+
+void dp_log_training_result(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings,
+       enum link_training_result status)
+{
+       char *link_rate = "Unknown";
+       char *lt_result = "Unknown";
+       char *lt_spread = "Disabled";
+
+       switch (lt_settings->link_settings.link_rate) {
+       case LINK_RATE_LOW:
+               link_rate = "RBR";
+               break;
+       case LINK_RATE_RATE_2:
+               link_rate = "R2";
+               break;
+       case LINK_RATE_RATE_3:
+               link_rate = "R3";
+               break;
+       case LINK_RATE_HIGH:
+               link_rate = "HBR";
+               break;
+       case LINK_RATE_RBR2:
+               link_rate = "RBR2";
+               break;
+       case LINK_RATE_RATE_6:
+               link_rate = "R6";
+               break;
+       case LINK_RATE_HIGH2:
+               link_rate = "HBR2";
+               break;
+       case LINK_RATE_HIGH3:
+               link_rate = "HBR3";
+               break;
+       case LINK_RATE_UHBR10:
+               link_rate = "UHBR10";
+               break;
+       case LINK_RATE_UHBR13_5:
+               link_rate = "UHBR13.5";
+               break;
+       case LINK_RATE_UHBR20:
+               link_rate = "UHBR20";
+               break;
+       default:
+               break;
+       }
+
+       switch (status) {
+       case LINK_TRAINING_SUCCESS:
+               lt_result = "pass";
+               break;
+       case LINK_TRAINING_CR_FAIL_LANE0:
+               lt_result = "CR failed lane0";
+               break;
+       case LINK_TRAINING_CR_FAIL_LANE1:
+               lt_result = "CR failed lane1";
+               break;
+       case LINK_TRAINING_CR_FAIL_LANE23:
+               lt_result = "CR failed lane23";
+               break;
+       case LINK_TRAINING_EQ_FAIL_CR:
+               lt_result = "CR failed in EQ";
+               break;
+       case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
+               lt_result = "CR failed in EQ partially";
+               break;
+       case LINK_TRAINING_EQ_FAIL_EQ:
+               lt_result = "EQ failed";
+               break;
+       case LINK_TRAINING_LQA_FAIL:
+               lt_result = "LQA failed";
+               break;
+       case LINK_TRAINING_LINK_LOSS:
+               lt_result = "Link loss";
+               break;
+       case DP_128b_132b_LT_FAILED:
+               lt_result = "LT_FAILED received";
+               break;
+       case DP_128b_132b_MAX_LOOP_COUNT_REACHED:
+               lt_result = "max loop count reached";
+               break;
+       case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT:
+               lt_result = "channel EQ timeout";
+               break;
+       case DP_128b_132b_CDS_DONE_TIMEOUT:
+               lt_result = "CDS timeout";
+               break;
+       default:
+               break;
+       }
+
+       switch (lt_settings->link_settings.link_spread) {
+       case LINK_SPREAD_DISABLED:
+               lt_spread = "Disabled";
+               break;
+       case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
+               lt_spread = "0.5% 30KHz";
+               break;
+       case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
+               lt_spread = "0.5% 33KHz";
+               break;
+       default:
+               break;
+       }
+
+       /* Connectivity log: link training */
+
+       /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
+
+       CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
+                               link_rate,
+                               lt_settings->link_settings.lane_count,
+                               lt_result,
+                               lt_settings->hw_lane_settings[0].VOLTAGE_SWING,
+                               lt_settings->hw_lane_settings[0].PRE_EMPHASIS,
+                               lt_spread);
+}
+
+uint8_t dp_initialize_scrambling_data_symbols(
+       struct dc_link *link,
+       enum dc_dp_training_pattern pattern)
+{
+       uint8_t disable_scrabled_data_symbols = 0;
+
+       switch (pattern) {
+       case DP_TRAINING_PATTERN_SEQUENCE_1:
+       case DP_TRAINING_PATTERN_SEQUENCE_2:
+       case DP_TRAINING_PATTERN_SEQUENCE_3:
+               disable_scrabled_data_symbols = 1;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_4:
+       case DP_128b_132b_TPS1:
+       case DP_128b_132b_TPS2:
+               disable_scrabled_data_symbols = 0;
+               break;
+       default:
+               ASSERT(0);
+               DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
+                       __func__, pattern);
+               break;
+       }
+       return disable_scrabled_data_symbols;
+}
+
+enum dpcd_training_patterns
+       dp_training_pattern_to_dpcd_training_pattern(
+       struct dc_link *link,
+       enum dc_dp_training_pattern pattern)
+{
+       enum dpcd_training_patterns dpcd_tr_pattern =
+       DPCD_TRAINING_PATTERN_VIDEOIDLE;
+
+       switch (pattern) {
+       case DP_TRAINING_PATTERN_SEQUENCE_1:
+               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_2:
+               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_3:
+               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_4:
+               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
+               break;
+       case DP_128b_132b_TPS1:
+               dpcd_tr_pattern = DPCD_128b_132b_TPS1;
+               break;
+       case DP_128b_132b_TPS2:
+               dpcd_tr_pattern = DPCD_128b_132b_TPS2;
+               break;
+       case DP_128b_132b_TPS2_CDS:
+               dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS;
+               break;
+       case DP_TRAINING_PATTERN_VIDEOIDLE:
+               dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
+               break;
+       default:
+               ASSERT(0);
+               DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
+                       __func__, pattern);
+               break;
+       }
+
+       return dpcd_tr_pattern;
+}
+
+uint8_t dp_get_nibble_at_index(const uint8_t *buf,
+       uint32_t index)
+{
+       uint8_t nibble;
+       nibble = buf[index / 2];
+
+       if (index % 2)
+               nibble >>= 4;
+       else
+               nibble &= 0x0F;
+
+       return nibble;
+}
+
+void dp_wait_for_training_aux_rd_interval(
+       struct dc_link *link,
+       uint32_t wait_in_micro_secs)
+{
+       if (wait_in_micro_secs > 1000)
+               msleep(wait_in_micro_secs/1000);
+       else
+               udelay(wait_in_micro_secs);
+
+       DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
+               __func__,
+               wait_in_micro_secs);
+}
+
+/* maximum pre emphasis level allowed for each voltage swing level*/
+static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
+               PRE_EMPHASIS_LEVEL3,
+               PRE_EMPHASIS_LEVEL2,
+               PRE_EMPHASIS_LEVEL1,
+               PRE_EMPHASIS_DISABLED };
+
+static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing(
+       enum dc_voltage_swing voltage)
+{
+       enum dc_pre_emphasis pre_emphasis;
+       pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
+
+       if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
+               pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
+
+       return pre_emphasis;
+
+}
+
+static void maximize_lane_settings(const struct link_training_settings *lt_settings,
+               struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+       uint32_t lane;
+       struct dc_lane_settings max_requested;
+
+       max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING;
+       max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS;
+       max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET;
+
+       /* Determine what the maximum of the requested settings are*/
+       for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) {
+               if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING)
+                       max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING;
+
+               if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS)
+                       max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS;
+               if (lane_settings[lane].FFE_PRESET.settings.level >
+                               max_requested.FFE_PRESET.settings.level)
+                       max_requested.FFE_PRESET.settings.level =
+                                       lane_settings[lane].FFE_PRESET.settings.level;
+       }
+
+       /* make sure the requested settings are
+        * not higher than maximum settings*/
+       if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
+               max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
+
+       if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
+               max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
+       if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
+               max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
+
+       /* make sure the pre-emphasis matches the voltage swing*/
+       if (max_requested.PRE_EMPHASIS >
+               get_max_pre_emphasis_for_voltage_swing(
+                       max_requested.VOLTAGE_SWING))
+               max_requested.PRE_EMPHASIS =
+               get_max_pre_emphasis_for_voltage_swing(
+                       max_requested.VOLTAGE_SWING);
+
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
+               lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
+               lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
+       }
+}
+
+void dp_hw_to_dpcd_lane_settings(
+               const struct link_training_settings *lt_settings,
+               const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+               union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
+{
+       uint8_t lane = 0;
+
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_8b_10b_ENCODING) {
+                       dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
+                                       (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
+                       dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
+                                       (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
+                       dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
+                                       (hw_lane_settings[lane].VOLTAGE_SWING ==
+                                                       VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
+                       dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
+                                       (hw_lane_settings[lane].PRE_EMPHASIS ==
+                                                       PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
+               } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_128b_132b_ENCODING) {
+                       dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
+                                       hw_lane_settings[lane].FFE_PRESET.settings.level;
+               }
+       }
+}
+
+uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
+{
+       uint8_t link_rate = 0;
+       enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings);
+
+       if (encoding == DP_128b_132b_ENCODING)
+               switch (link_settings->link_rate) {
+               case LINK_RATE_UHBR10:
+                       link_rate = 0x1;
+                       break;
+               case LINK_RATE_UHBR20:
+                       link_rate = 0x2;
+                       break;
+               case LINK_RATE_UHBR13_5:
+                       link_rate = 0x4;
+                       break;
+               default:
+                       link_rate = 0;
+                       break;
+               }
+       else if (encoding == DP_8b_10b_ENCODING)
+               link_rate = (uint8_t) link_settings->link_rate;
+       else
+               link_rate = 0;
+
+       return link_rate;
+}
+
+/* Only used for channel equalization */
+uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
+{
+       unsigned int aux_rd_interval_us = 400;
+
+       switch (dpcd_aux_read_interval) {
+       case 0x01:
+               aux_rd_interval_us = 4000;
+               break;
+       case 0x02:
+               aux_rd_interval_us = 8000;
+               break;
+       case 0x03:
+               aux_rd_interval_us = 12000;
+               break;
+       case 0x04:
+               aux_rd_interval_us = 16000;
+               break;
+       case 0x05:
+               aux_rd_interval_us = 32000;
+               break;
+       case 0x06:
+               aux_rd_interval_us = 64000;
+               break;
+       default:
+               break;
+       }
+
+       return aux_rd_interval_us;
+}
+
+enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
+                                       union lane_status *dpcd_lane_status)
+{
+       enum link_training_result result = LINK_TRAINING_SUCCESS;
+
+       if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
+               result = LINK_TRAINING_CR_FAIL_LANE0;
+       else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
+               result = LINK_TRAINING_CR_FAIL_LANE1;
+       else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
+               result = LINK_TRAINING_CR_FAIL_LANE23;
+       else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
+               result = LINK_TRAINING_CR_FAIL_LANE23;
+       return result;
+}
+
+bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
+{
+       return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
+}
+
+bool dp_is_max_vs_reached(
+       const struct link_training_settings *lt_settings)
+{
+       uint32_t lane;
+       for (lane = 0; lane <
+               (uint32_t)(lt_settings->link_settings.lane_count);
+               lane++) {
+               if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
+                       == VOLTAGE_SWING_MAX_LEVEL)
+                       return true;
+       }
+       return false;
+
+}
+
+bool dp_is_cr_done(enum dc_lane_count ln_count,
+       union lane_status *dpcd_lane_status)
+{
+       bool done = true;
+       uint32_t lane;
+       /*LANEx_CR_DONE bits All 1's?*/
+       for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
+               if (!dpcd_lane_status[lane].bits.CR_DONE_0)
+                       done = false;
+       }
+       return done;
+
+}
+
+bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
+               union lane_status *dpcd_lane_status)
+{
+       bool done = true;
+       uint32_t lane;
+       for (lane = 0; lane < (uint32_t)(ln_count); lane++)
+               if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
+                       done = false;
+       return done;
+}
+
+bool dp_is_symbol_locked(enum dc_lane_count ln_count,
+               union lane_status *dpcd_lane_status)
+{
+       bool locked = true;
+       uint32_t lane;
+       for (lane = 0; lane < (uint32_t)(ln_count); lane++)
+               if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
+                       locked = false;
+       return locked;
+}
+
+bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
+{
+       return align_status.bits.INTERLANE_ALIGN_DONE == 1;
+}
+
+enum link_training_result dp_check_link_loss_status(
+       struct dc_link *link,
+       const struct link_training_settings *link_training_setting)
+{
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+       union lane_status lane_status;
+       uint8_t dpcd_buf[6] = {0};
+       uint32_t lane;
+
+       core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT,
+                       (uint8_t *)(dpcd_buf),
+                       sizeof(dpcd_buf));
+
+       /*parse lane status*/
+       for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
+               /*
+                * check lanes status
+                */
+               lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane);
+
+               if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
+                       !lane_status.bits.CR_DONE_0 ||
+                       !lane_status.bits.SYMBOL_LOCKED_0) {
+                       /* if one of the channel equalization, clock
+                        * recovery or symbol lock is dropped
+                        * consider it as (link has been
+                        * dropped) dp sink status has changed
+                        */
+                       status = LINK_TRAINING_LINK_LOSS;
+                       break;
+               }
+       }
+
+       return status;
+}
+
+enum dc_status dp_get_lane_status_and_lane_adjust(
+       struct dc_link *link,
+       const struct link_training_settings *link_training_setting,
+       union lane_status ln_status[LANE_COUNT_DP_MAX],
+       union lane_align_status_updated *ln_align,
+       union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+       uint32_t offset)
+{
+       unsigned int lane01_status_address = DP_LANE0_1_STATUS;
+       uint8_t lane_adjust_offset = 4;
+       unsigned int lane01_adjust_address;
+       uint8_t dpcd_buf[6] = {0};
+       uint32_t lane;
+       enum dc_status status;
+
+       if (is_repeater(link_training_setting, offset)) {
+               lane01_status_address =
+                               DP_LANE0_1_STATUS_PHY_REPEATER1 +
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+               lane_adjust_offset = 3;
+       }
+
+       status = core_link_read_dpcd(
+               link,
+               lane01_status_address,
+               (uint8_t *)(dpcd_buf),
+               sizeof(dpcd_buf));
+
+       if (status != DC_OK) {
+               DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
+                       " keep current lane status and lane adjust unchanged",
+                       __func__,
+                       lane01_status_address);
+               return status;
+       }
+
+       for (lane = 0; lane <
+               (uint32_t)(link_training_setting->link_settings.lane_count);
+               lane++) {
+
+               ln_status[lane].raw =
+                       dp_get_nibble_at_index(&dpcd_buf[0], lane);
+               ln_adjust[lane].raw =
+                       dp_get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
+       }
+
+       ln_align->raw = dpcd_buf[2];
+
+       if (is_repeater(link_training_setting, offset)) {
+               DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+                               " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
+                       __func__,
+                       offset,
+                       lane01_status_address, dpcd_buf[0],
+                       lane01_status_address + 1, dpcd_buf[1]);
+
+               lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+               DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+                               " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
+                                       __func__,
+                                       offset,
+                                       lane01_adjust_address,
+                                       dpcd_buf[lane_adjust_offset],
+                                       lane01_adjust_address + 1,
+                                       dpcd_buf[lane_adjust_offset + 1]);
+       } else {
+               DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
+                       __func__,
+                       lane01_status_address, dpcd_buf[0],
+                       lane01_status_address + 1, dpcd_buf[1]);
+
+               lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
+
+               DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
+                       __func__,
+                       lane01_adjust_address,
+                       dpcd_buf[lane_adjust_offset],
+                       lane01_adjust_address + 1,
+                       dpcd_buf[lane_adjust_offset + 1]);
+       }
+
+       return status;
+}
+
+static void override_lane_settings(const struct link_training_settings *lt_settings,
+               struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+       uint32_t lane;
+
+       if (lt_settings->voltage_swing == NULL &&
+                       lt_settings->pre_emphasis == NULL &&
+                       lt_settings->ffe_preset == NULL &&
+                       lt_settings->post_cursor2 == NULL)
+
+               return;
+
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               if (lt_settings->voltage_swing)
+                       lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
+               if (lt_settings->pre_emphasis)
+                       lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
+               if (lt_settings->post_cursor2)
+                       lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
+               if (lt_settings->ffe_preset)
+                       lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
+       }
+}
+
+void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
+{
+       if (!dp_is_lttpr_present(link))
+               return;
+
+       if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
+               *override = LTTPR_MODE_TRANSPARENT;
+       } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
+               *override = LTTPR_MODE_NON_TRANSPARENT;
+       } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
+               *override = LTTPR_MODE_NON_LTTPR;
+       }
+       DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
+}
+
+void override_training_settings(
+               struct dc_link *link,
+               const struct dc_link_training_overrides *overrides,
+               struct link_training_settings *lt_settings)
+{
+       uint32_t lane;
+
+       /* Override link spread */
+       if (!link->dp_ss_off && overrides->downspread != NULL)
+               lt_settings->link_settings.link_spread = *overrides->downspread ?
+                               LINK_SPREAD_05_DOWNSPREAD_30KHZ
+                               : LINK_SPREAD_DISABLED;
+
+       /* Override lane settings */
+       if (overrides->voltage_swing != NULL)
+               lt_settings->voltage_swing = overrides->voltage_swing;
+       if (overrides->pre_emphasis != NULL)
+               lt_settings->pre_emphasis = overrides->pre_emphasis;
+       if (overrides->post_cursor2 != NULL)
+               lt_settings->post_cursor2 = overrides->post_cursor2;
+       if (overrides->ffe_preset != NULL)
+               lt_settings->ffe_preset = overrides->ffe_preset;
+       /* Override HW lane settings with BIOS forced values if present */
+       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+                       lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
+               lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
+               lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
+               lt_settings->always_match_dpcd_with_hw_lane_settings = false;
+       }
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
+                       lt_settings->voltage_swing != NULL ?
+                       *lt_settings->voltage_swing :
+                       VOLTAGE_SWING_LEVEL0;
+               lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
+                       lt_settings->pre_emphasis != NULL ?
+                       *lt_settings->pre_emphasis
+                       : PRE_EMPHASIS_DISABLED;
+               lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
+                       lt_settings->post_cursor2 != NULL ?
+                       *lt_settings->post_cursor2
+                       : POST_CURSOR2_DISABLED;
+       }
+
+       if (lt_settings->always_match_dpcd_with_hw_lane_settings)
+               dp_hw_to_dpcd_lane_settings(lt_settings,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+
+       /* Override training timings */
+       if (overrides->cr_pattern_time != NULL)
+               lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
+       if (overrides->eq_pattern_time != NULL)
+               lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
+       if (overrides->pattern_for_cr != NULL)
+               lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
+       if (overrides->pattern_for_eq != NULL)
+               lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
+       if (overrides->enhanced_framing != NULL)
+               lt_settings->enhanced_framing = *overrides->enhanced_framing;
+       if (link->preferred_training_settings.fec_enable != NULL)
+               lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       /* Check DP tunnel LTTPR mode debug option. */
+       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
+               lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
+
+#endif
+       dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
+
+}
+
+enum dc_dp_training_pattern decide_cr_training_pattern(
+               const struct dc_link_settings *link_settings)
+{
+       switch (link_dp_get_encoding_format(link_settings)) {
+       case DP_8b_10b_ENCODING:
+       default:
+               return DP_TRAINING_PATTERN_SEQUENCE_1;
+       case DP_128b_132b_ENCODING:
+               return DP_128b_132b_TPS1;
+       }
+}
+
+enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
+               const struct dc_link_settings *link_settings)
+{
+       struct link_encoder *link_enc;
+       struct encoder_feature_support *enc_caps;
+       struct dpcd_caps *rx_caps = &link->dpcd_caps;
+       enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
+
+       link_enc = link_enc_cfg_get_link_enc(link);
+       ASSERT(link_enc);
+       enc_caps = &link_enc->features;
+
+       switch (link_dp_get_encoding_format(link_settings)) {
+       case DP_8b_10b_ENCODING:
+               if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
+                               rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
+                       pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+               else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
+                               rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
+                       pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
+               else
+                       pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
+               break;
+       case DP_128b_132b_ENCODING:
+               pattern = DP_128b_132b_TPS2;
+               break;
+       default:
+               pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
+               break;
+       }
+       return pattern;
+}
+
+enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link,
+               struct dc_link_settings *link_setting)
+{
+       enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting);
+
+       if (encoding == DP_8b_10b_ENCODING)
+               return dp_decide_8b_10b_lttpr_mode(link);
+       else if (encoding == DP_128b_132b_ENCODING)
+               return dp_decide_128b_132b_lttpr_mode(link);
+
+       ASSERT(0);
+       return LTTPR_MODE_NON_LTTPR;
+}
+
+void dp_decide_lane_settings(
+               const struct link_training_settings *lt_settings,
+               const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+               struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+               union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
+{
+       uint32_t lane;
+
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_8b_10b_ENCODING) {
+                       hw_lane_settings[lane].VOLTAGE_SWING =
+                                       (enum dc_voltage_swing)(ln_adjust[lane].bits.
+                                                       VOLTAGE_SWING_LANE);
+                       hw_lane_settings[lane].PRE_EMPHASIS =
+                                       (enum dc_pre_emphasis)(ln_adjust[lane].bits.
+                                                       PRE_EMPHASIS_LANE);
+               } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_128b_132b_ENCODING) {
+                       hw_lane_settings[lane].FFE_PRESET.raw =
+                                       ln_adjust[lane].tx_ffe.PRESET_VALUE;
+               }
+       }
+       dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
+
+       if (lt_settings->disallow_per_lane_settings) {
+               /* we find the maximum of the requested settings across all lanes*/
+               /* and set this maximum for all lanes*/
+               maximize_lane_settings(lt_settings, hw_lane_settings);
+               override_lane_settings(lt_settings, hw_lane_settings);
+
+               if (lt_settings->always_match_dpcd_with_hw_lane_settings)
+                       dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
+       }
+
+}
+
+void dp_decide_training_settings(
+               struct dc_link *link,
+               const struct dc_link_settings *link_settings,
+               struct link_training_settings *lt_settings)
+{
+       if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
+               decide_8b_10b_training_settings(link, link_settings, lt_settings);
+       else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
+               decide_128b_132b_training_settings(link, link_settings, lt_settings);
+}
+
+
+enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
+{
+       uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
+
+       DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
+       return core_link_write_dpcd(link,
+                       DP_PHY_REPEATER_MODE,
+                       (uint8_t *)&repeater_mode,
+                       sizeof(repeater_mode));
+}
+
+static enum dc_status configure_lttpr_mode_non_transparent(
+               struct dc_link *link,
+               const struct link_training_settings *lt_settings)
+{
+       /* aux timeout is already set to extended */
+       /* RESET/SET lttpr mode to enable non transparent mode */
+       uint8_t repeater_cnt;
+       uint32_t aux_interval_address;
+       uint8_t repeater_id;
+       enum dc_status result = DC_ERROR_UNEXPECTED;
+       uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
+
+       enum dp_link_encoding encoding = link_dp_get_encoding_format(&lt_settings->link_settings);
+
+       if (encoding == DP_8b_10b_ENCODING) {
+               DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
+               result = core_link_write_dpcd(link,
+                               DP_PHY_REPEATER_MODE,
+                               (uint8_t *)&repeater_mode,
+                               sizeof(repeater_mode));
+
+       }
+
+       if (result == DC_OK) {
+               link->dpcd_caps.lttpr_caps.mode = repeater_mode;
+       }
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+               DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
+
+               repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
+               result = core_link_write_dpcd(link,
+                               DP_PHY_REPEATER_MODE,
+                               (uint8_t *)&repeater_mode,
+                               sizeof(repeater_mode));
+
+               if (result == DC_OK) {
+                       link->dpcd_caps.lttpr_caps.mode = repeater_mode;
+               }
+
+               if (encoding == DP_8b_10b_ENCODING) {
+                       repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+                       /* Driver does not need to train the first hop. Skip DPCD read and clear
+                        * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
+                        */
+                       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+                               link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
+
+                       for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
+                               aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
+                                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
+                               core_link_read_dpcd(
+                                               link,
+                                               aux_interval_address,
+                                               (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
+                                               sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
+                               link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
+                       }
+               }
+       }
+
+       return result;
+}
+
+enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
+{
+       enum dc_status status = DC_OK;
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
+               status = configure_lttpr_mode_transparent(link);
+
+       else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
+               status = configure_lttpr_mode_non_transparent(link, lt_settings);
+
+       return status;
+}
+
+void repeater_training_done(struct dc_link *link, uint32_t offset)
+{
+       union dpcd_training_pattern dpcd_pattern = {0};
+
+       const uint32_t dpcd_base_lt_offset =
+                       DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+       /* Set training not in progress*/
+       dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
+
+       core_link_write_dpcd(
+               link,
+               dpcd_base_lt_offset,
+               &dpcd_pattern.raw,
+               1);
+
+       DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
+               __func__,
+               offset,
+               dpcd_base_lt_offset,
+               dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+}
+
+static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
+{
+       uint8_t sink_status = 0;
+       uint8_t i;
+
+       /* clear training pattern set */
+       dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
+
+       if (encoding == DP_128b_132b_ENCODING) {
+               /* poll for intra-hop disable */
+               for (i = 0; i < 10; i++) {
+                       if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
+                                       (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
+                               break;
+                       udelay(1000);
+               }
+       }
+}
+
+enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
+               struct link_training_settings *lt_settings)
+{
+       enum dp_link_encoding encoding =
+                       link_dp_get_encoding_format(
+                                       &lt_settings->link_settings);
+       enum dc_status status;
+
+       status = core_link_write_dpcd(
+                       link,
+                       DP_MAIN_LINK_CHANNEL_CODING_SET,
+                       (uint8_t *) &encoding,
+                       1);
+       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
+                                       __func__,
+                                       DP_MAIN_LINK_CHANNEL_CODING_SET,
+                                       encoding);
+
+       return status;
+}
+
+void dpcd_set_training_pattern(
+       struct dc_link *link,
+       enum dc_dp_training_pattern training_pattern)
+{
+       union dpcd_training_pattern dpcd_pattern = {0};
+
+       dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
+                       dp_training_pattern_to_dpcd_training_pattern(
+                                       link, training_pattern);
+
+       core_link_write_dpcd(
+               link,
+               DP_TRAINING_PATTERN_SET,
+               &dpcd_pattern.raw,
+               1);
+
+       DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
+               __func__,
+               DP_TRAINING_PATTERN_SET,
+               dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+}
+
+enum dc_status dpcd_set_link_settings(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings)
+{
+       uint8_t rate;
+       enum dc_status status;
+
+       union down_spread_ctrl downspread = {0};
+       union lane_count_set lane_count_set = {0};
+
+       downspread.raw = (uint8_t)
+       (lt_settings->link_settings.link_spread);
+
+       lane_count_set.bits.LANE_COUNT_SET =
+       lt_settings->link_settings.lane_count;
+
+       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+       lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+
+       if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
+                       lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
+               lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
+                               link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
+       }
+
+       status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
+               &downspread.raw, sizeof(downspread));
+
+       status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
+               &lane_count_set.raw, 1);
+
+       if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
+                       lt_settings->link_settings.use_link_rate_set == true) {
+               rate = 0;
+               /* WA for some MUX chips that will power down with eDP and lose supported
+                * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
+                * MUX chip gets link rate set back before link training.
+                */
+               if (link->connector_signal == SIGNAL_TYPE_EDP) {
+                       uint8_t supported_link_rates[16];
+
+                       core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
+                                       supported_link_rates, sizeof(supported_link_rates));
+               }
+               status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
+               status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
+                               &lt_settings->link_settings.link_rate_set, 1);
+       } else {
+               rate = get_dpcd_link_rate(&lt_settings->link_settings);
+
+               status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
+       }
+
+       if (rate) {
+               DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+                       __func__,
+                       DP_LINK_BW_SET,
+                       lt_settings->link_settings.link_rate,
+                       DP_LANE_COUNT_SET,
+                       lt_settings->link_settings.lane_count,
+                       lt_settings->enhanced_framing,
+                       DP_DOWNSPREAD_CTRL,
+                       lt_settings->link_settings.link_spread);
+       } else {
+               DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+                       __func__,
+                       DP_LINK_RATE_SET,
+                       lt_settings->link_settings.link_rate_set,
+                       DP_LANE_COUNT_SET,
+                       lt_settings->link_settings.lane_count,
+                       lt_settings->enhanced_framing,
+                       DP_DOWNSPREAD_CTRL,
+                       lt_settings->link_settings.link_spread);
+       }
+
+       return status;
+}
+
+enum dc_status dpcd_set_lane_settings(
+       struct dc_link *link,
+       const struct link_training_settings *link_training_setting,
+       uint32_t offset)
+{
+       unsigned int lane0_set_address;
+       enum dc_status status;
+       lane0_set_address = DP_TRAINING_LANE0_SET;
+
+       if (is_repeater(link_training_setting, offset))
+               lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
+               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+       status = core_link_write_dpcd(link,
+               lane0_set_address,
+               (uint8_t *)(link_training_setting->dpcd_lane_settings),
+               link_training_setting->link_settings.lane_count);
+
+       if (is_repeater(link_training_setting, offset)) {
+               DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
+                               " 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
+                       __func__,
+                       offset,
+                       lane0_set_address,
+                       link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+                       link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+                       link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+                       link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+
+       } else {
+               DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
+                       __func__,
+                       lane0_set_address,
+                       link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+                       link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+                       link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+                       link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+       }
+
+       return status;
+}
+
+void dpcd_set_lt_pattern_and_lane_settings(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings,
+       enum dc_dp_training_pattern pattern,
+       uint32_t offset)
+{
+       uint32_t dpcd_base_lt_offset;
+       uint8_t dpcd_lt_buffer[5] = {0};
+       union dpcd_training_pattern dpcd_pattern = {0};
+       uint32_t size_in_bytes;
+       bool edp_workaround = false; /* TODO link_prop.INTERNAL */
+       dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
+
+       if (is_repeater(lt_settings, offset))
+               dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+       /*****************************************************************
+       * DpcdAddress_TrainingPatternSet
+       *****************************************************************/
+       dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
+               dp_training_pattern_to_dpcd_training_pattern(link, pattern);
+
+       dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
+               dp_initialize_scrambling_data_symbols(link, pattern);
+
+       dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
+               = dpcd_pattern.raw;
+
+       if (is_repeater(lt_settings, offset)) {
+               DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
+                       __func__,
+                       offset,
+                       dpcd_base_lt_offset,
+                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+       } else {
+               DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
+                       __func__,
+                       dpcd_base_lt_offset,
+                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+       }
+
+       /* concatenate everything into one buffer*/
+       size_in_bytes = lt_settings->link_settings.lane_count *
+                       sizeof(lt_settings->dpcd_lane_settings[0]);
+
+        // 0x00103 - 0x00102
+       memmove(
+               &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
+               lt_settings->dpcd_lane_settings,
+               size_in_bytes);
+
+       if (is_repeater(lt_settings, offset)) {
+               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_128b_132b_ENCODING)
+                       DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+                                       " 0x%X TX_FFE_PRESET_VALUE = %x\n",
+                                       __func__,
+                                       offset,
+                                       dpcd_base_lt_offset,
+                                       lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
+               else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_8b_10b_ENCODING)
+               DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+                               " 0x%X VS set = %x PE set = %x max VS Reached = %x  max PE Reached = %x\n",
+                       __func__,
+                       offset,
+                       dpcd_base_lt_offset,
+                       lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+                       lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+                       lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+                       lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+       } else {
+               if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_128b_132b_ENCODING)
+                       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
+                                       __func__,
+                                       dpcd_base_lt_offset,
+                                       lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
+               else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_8b_10b_ENCODING)
+                       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x  PE set = %x max VS Reached = %x  max PE Reached = %x\n",
+                                       __func__,
+                                       dpcd_base_lt_offset,
+                                       lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+                                       lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+                                       lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+                                       lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+       }
+       if (edp_workaround) {
+               /* for eDP write in 2 parts because the 5-byte burst is
+               * causing issues on some eDP panels (EPR#366724)
+               */
+               core_link_write_dpcd(
+                       link,
+                       DP_TRAINING_PATTERN_SET,
+                       &dpcd_pattern.raw,
+                       sizeof(dpcd_pattern.raw));
+
+               core_link_write_dpcd(
+                       link,
+                       DP_TRAINING_LANE0_SET,
+                       (uint8_t *)(lt_settings->dpcd_lane_settings),
+                       size_in_bytes);
+
+       } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                       DP_128b_132b_ENCODING) {
+               core_link_write_dpcd(
+                               link,
+                               dpcd_base_lt_offset,
+                               dpcd_lt_buffer,
+                               sizeof(dpcd_lt_buffer));
+       } else
+               /* write it all in (1 + number-of-lanes)-byte burst*/
+               core_link_write_dpcd(
+                               link,
+                               dpcd_base_lt_offset,
+                               dpcd_lt_buffer,
+                               size_in_bytes + sizeof(dpcd_pattern.raw));
+}
+
+void start_clock_recovery_pattern_early(struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings,
+               uint32_t offset)
+{
+       DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
+                       __func__);
+       dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
+       dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
+       udelay(400);
+}
+
+void dp_set_hw_test_pattern(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       enum dp_test_pattern test_pattern,
+       uint8_t *custom_pattern,
+       uint32_t custom_pattern_size)
+{
+       const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+       struct encoder_set_dp_phy_pattern_param pattern_param = {0};
+
+       pattern_param.dp_phy_pattern = test_pattern;
+       pattern_param.custom_pattern = custom_pattern;
+       pattern_param.custom_pattern_size = custom_pattern_size;
+       pattern_param.dp_panel_mode = dp_get_panel_mode(link);
+
+       if (link_hwss->ext.set_dp_link_test_pattern)
+               link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
+}
+
+bool dp_set_hw_training_pattern(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       enum dc_dp_training_pattern pattern,
+       uint32_t offset)
+{
+       enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
+
+       switch (pattern) {
+       case DP_TRAINING_PATTERN_SEQUENCE_1:
+               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_2:
+               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_3:
+               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_4:
+               test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
+               break;
+       case DP_128b_132b_TPS1:
+               test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
+               break;
+       case DP_128b_132b_TPS2:
+               test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
+               break;
+       default:
+               break;
+       }
+
+       dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
+
+       return true;
+}
+
+static bool perform_post_lt_adj_req_sequence(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       enum dc_lane_count lane_count =
+       lt_settings->link_settings.lane_count;
+
+       uint32_t adj_req_count;
+       uint32_t adj_req_timer;
+       bool req_drv_setting_changed;
+       uint32_t lane;
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+       req_drv_setting_changed = false;
+       for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
+       adj_req_count++) {
+
+               req_drv_setting_changed = false;
+
+               for (adj_req_timer = 0;
+                       adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
+                       adj_req_timer++) {
+
+                       dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               DPRX);
+
+                       if (dpcd_lane_status_updated.bits.
+                                       POST_LT_ADJ_REQ_IN_PROGRESS == 0)
+                               return true;
+
+                       if (!dp_is_cr_done(lane_count, dpcd_lane_status))
+                               return false;
+
+                       if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
+                                       !dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
+                                       !dp_is_interlane_aligned(dpcd_lane_status_updated))
+                               return false;
+
+                       for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
+
+                               if (lt_settings->
+                               dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
+                               dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
+                               lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
+                               dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
+
+                                       req_drv_setting_changed = true;
+                                       break;
+                               }
+                       }
+
+                       if (req_drv_setting_changed) {
+                               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+
+                               dp_set_drive_settings(link,
+                                               link_res,
+                                               lt_settings);
+                               break;
+                       }
+
+                       msleep(1);
+               }
+
+               if (!req_drv_setting_changed) {
+                       DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
+                               __func__);
+
+                       ASSERT(0);
+                       return true;
+               }
+       }
+       DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
+               __func__);
+
+       ASSERT(0);
+       return true;
+
+}
+
+static enum link_training_result dp_transition_to_video_idle(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings,
+       enum link_training_result status)
+{
+       union lane_count_set lane_count_set = {0};
+
+       /* 4. mainlink output idle pattern*/
+       dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+       /*
+        * 5. post training adjust if required
+        * If the upstream DPTX and downstream DPRX both support TPS4,
+        * TPS4 must be used instead of POST_LT_ADJ_REQ.
+        */
+       if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
+                       lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
+               /* delay 5ms after Main Link output idle pattern and then check
+                * DPCD 0202h.
+                */
+               if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
+                       msleep(5);
+                       status = dp_check_link_loss_status(link, lt_settings);
+               }
+               return status;
+       }
+
+       if (status == LINK_TRAINING_SUCCESS &&
+               perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
+               status = LINK_TRAINING_LQA_FAIL;
+
+       lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
+       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+       lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+       core_link_write_dpcd(
+               link,
+               DP_LANE_COUNT_SET,
+               &lane_count_set.raw,
+               sizeof(lane_count_set));
+
+       return status;
+}
+
+enum link_training_result dp_perform_link_training(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       const struct dc_link_settings *link_settings,
+       bool skip_video_pattern)
+{
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+       struct link_training_settings lt_settings = {0};
+       enum dp_link_encoding encoding =
+                       link_dp_get_encoding_format(link_settings);
+
+       /* decide training settings */
+       dp_decide_training_settings(
+                       link,
+                       link_settings,
+                       &lt_settings);
+
+       override_training_settings(
+                       link,
+                       &link->preferred_training_settings,
+                       &lt_settings);
+
+       /* reset previous training states */
+       dpcd_exit_training_mode(link, encoding);
+
+       /* configure link prior to entering training mode */
+       dpcd_configure_lttpr_mode(link, &lt_settings);
+       dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
+       dpcd_configure_channel_coding(link, &lt_settings);
+
+       /* enter training mode:
+        * Per DP specs starting from here, DPTX device shall not issue
+        * Non-LT AUX transactions inside training mode.
+        */
+       if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING)
+               status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
+       else if (encoding == DP_8b_10b_ENCODING)
+               status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
+       else if (encoding == DP_128b_132b_ENCODING)
+               status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
+       else
+               ASSERT(0);
+
+       /* exit training mode */
+       dpcd_exit_training_mode(link, encoding);
+
+       /* switch to video idle */
+       if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
+               status = dp_transition_to_video_idle(link,
+                               link_res,
+                               &lt_settings,
+                               status);
+
+       /* dump debug data */
+       dp_log_training_result(link, &lt_settings, status);
+       if (status != LINK_TRAINING_SUCCESS)
+               link->ctx->dc->debug_data.ltFailCount++;
+       return status;
+}
+
+bool perform_link_training_with_retries(
+       const struct dc_link_settings *link_setting,
+       bool skip_video_pattern,
+       int attempts,
+       struct pipe_ctx *pipe_ctx,
+       enum signal_type signal,
+       bool do_fallback)
+{
+       int j;
+       uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
+       struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
+       enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
+       enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
+       struct dc_link_settings cur_link_settings = *link_setting;
+       struct dc_link_settings max_link_settings = *link_setting;
+       const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+       int fail_count = 0;
+       bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
+       bool is_link_bw_min = /* RBR x 1 */
+               (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+               (cur_link_settings.lane_count <= LANE_COUNT_ONE);
+
+       dp_trace_commit_lt_init(link);
+
+
+       if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
+               /* We need to do this before the link training to ensure the idle
+                * pattern in SST mode will be sent right after the link training
+                */
+               link_hwss->setup_stream_encoder(pipe_ctx);
+
+       dp_trace_set_lt_start_timestamp(link, false);
+       j = 0;
+       while (j < attempts && fail_count < (attempts * 10)) {
+
+               DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n",
+                       __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
+                       cur_link_settings.lane_count);
+
+               dp_enable_link_phy(
+                       link,
+                       &pipe_ctx->link_res,
+                       signal,
+                       pipe_ctx->clock_source->id,
+                       &cur_link_settings);
+
+               if (stream->sink_patches.dppowerup_delay > 0) {
+                       int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
+
+                       msleep(delay_dp_power_up_in_ms);
+               }
+
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+               if (panel_mode == DP_PANEL_MODE_EDP) {
+                       struct cp_psp *cp_psp = &stream->ctx->cp_psp;
+
+                       if (cp_psp && cp_psp->funcs.enable_assr) {
+                               /* ASSR is bound to fail with unsigned PSP
+                                * verstage used during devlopment phase.
+                                * Report and continue with eDP panel mode to
+                                * perform eDP link training with right settings
+                                */
+                               bool result;
+                               result = cp_psp->funcs.enable_assr(cp_psp->handle, link);
+                       }
+               }
+#endif
+
+               dp_set_panel_mode(link, panel_mode);
+
+               if (link->aux_access_disabled) {
+                       dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
+                       return true;
+               } else {
+                       /** @todo Consolidate USB4 DP and DPx.x training. */
+                       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+                               status = dc_link_dpia_perform_link_training(
+                                               link,
+                                               &pipe_ctx->link_res,
+                                               &cur_link_settings,
+                                               skip_video_pattern);
+
+                               /* Transmit idle pattern once training successful. */
+                               if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
+                                       dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+                                       // Update verified link settings to current one
+                                       // Because DPIA LT might fallback to lower link setting.
+                                       if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+                                               link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
+                                               link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
+                                               dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
+                                       }
+                               }
+                       } else {
+                               status = dp_perform_link_training(
+                                               link,
+                                               &pipe_ctx->link_res,
+                                               &cur_link_settings,
+                                               skip_video_pattern);
+                       }
+
+                       dp_trace_lt_total_count_increment(link, false);
+                       dp_trace_lt_result_update(link, status, false);
+                       dp_trace_set_lt_end_timestamp(link, false);
+                       if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
+                               return true;
+               }
+
+               fail_count++;
+               dp_trace_lt_fail_count_update(link, fail_count, false);
+               if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
+                       /* latest link training still fail or link training is aborted
+                        * skip delay and keep PHY on
+                        */
+                       if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
+                               break;
+               }
+
+               DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n",
+                       __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
+                       cur_link_settings.lane_count, status);
+
+               dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
+
+               /* Abort link training if failure due to sink being unplugged. */
+               if (status == LINK_TRAINING_ABORT) {
+                       enum dc_connection_type type = dc_connection_none;
+
+                       dc_link_detect_sink(link, &type);
+                       if (type == dc_connection_none) {
+                               DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
+                               break;
+                       }
+               }
+
+               /* Try to train again at original settings if:
+                * - not falling back between training attempts;
+                * - aborted previous attempt due to reasons other than sink unplug;
+                * - successfully trained but at a link rate lower than that required by stream;
+                * - reached minimum link bandwidth.
+                */
+               if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
+                               (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
+                               is_link_bw_min) {
+                       j++;
+                       cur_link_settings = *link_setting;
+                       delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
+                       is_link_bw_low = false;
+                       is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+                               (cur_link_settings.lane_count <= LANE_COUNT_ONE);
+
+               } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
+                       uint32_t req_bw;
+                       uint32_t link_bw;
+
+                       decide_fallback_link_setting(link, &max_link_settings,
+                                       &cur_link_settings, status);
+                       /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
+                        * minimum link bandwidth.
+                        */
+                       req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
+                       link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings);
+                       is_link_bw_low = (req_bw > link_bw);
+                       is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+                               (cur_link_settings.lane_count <= LANE_COUNT_ONE));
+
+                       if (is_link_bw_low)
+                               DC_LOG_WARNING(
+                                       "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
+                                       __func__, link->link_index, req_bw, link_bw);
+               }
+
+               msleep(delay_between_attempts);
+       }
+
+       return false;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h
new file mode 100644 (file)
index 0000000..a049486
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_H__
+#define __DC_LINK_DP_TRAINING_H__
+#include "link.h"
+
+bool perform_link_training_with_retries(
+       const struct dc_link_settings *link_setting,
+       bool skip_video_pattern,
+       int attempts,
+       struct pipe_ctx *pipe_ctx,
+       enum signal_type signal,
+       bool do_fallback);
+
+enum link_training_result dp_perform_link_training(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct dc_link_settings *link_settings,
+               bool skip_video_pattern);
+
+bool dp_set_hw_training_pattern(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               enum dc_dp_training_pattern pattern,
+               uint32_t offset);
+
+void dp_set_hw_test_pattern(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               enum dp_test_pattern test_pattern,
+               uint8_t *custom_pattern,
+               uint32_t custom_pattern_size);
+
+void dpcd_set_training_pattern(
+       struct dc_link *link,
+       enum dc_dp_training_pattern training_pattern);
+
+/* Write DPCD drive settings. */
+enum dc_status dpcd_set_lane_settings(
+       struct dc_link *link,
+       const struct link_training_settings *link_training_setting,
+       uint32_t offset);
+
+/* Write DPCD link configuration data. */
+enum dc_status dpcd_set_link_settings(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings);
+
+void dpcd_set_lt_pattern_and_lane_settings(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings,
+       enum dc_dp_training_pattern pattern,
+       uint32_t offset);
+
+/* Read training status and adjustment requests from DPCD. */
+enum dc_status dp_get_lane_status_and_lane_adjust(
+       struct dc_link *link,
+       const struct link_training_settings *link_training_setting,
+       union lane_status ln_status[LANE_COUNT_DP_MAX],
+       union lane_align_status_updated *ln_align,
+       union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+       uint32_t offset);
+
+enum dc_status dpcd_configure_lttpr_mode(
+               struct dc_link *link,
+               struct link_training_settings *lt_settings);
+
+enum dc_status configure_lttpr_mode_transparent(struct dc_link *link);
+
+enum dc_status dpcd_configure_channel_coding(
+               struct dc_link *link,
+               struct link_training_settings *lt_settings);
+
+void repeater_training_done(struct dc_link *link, uint32_t offset);
+
+void start_clock_recovery_pattern_early(struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings,
+               uint32_t offset);
+
+void dp_decide_training_settings(
+               struct dc_link *link,
+               const struct dc_link_settings *link_settings,
+               struct link_training_settings *lt_settings);
+
+void dp_decide_lane_settings(
+       const struct link_training_settings *lt_settings,
+       const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+       struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+       union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
+
+enum dc_dp_training_pattern decide_cr_training_pattern(
+               const struct dc_link_settings *link_settings);
+
+enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
+               const struct dc_link_settings *link_settings);
+
+void dp_get_lttpr_mode_override(struct dc_link *link,
+               enum lttpr_mode *override);
+
+void override_training_settings(
+               struct dc_link *link,
+               const struct dc_link_training_overrides *overrides,
+               struct link_training_settings *lt_settings);
+
+/* Check DPCD training status registers to detect link loss. */
+enum link_training_result dp_check_link_loss_status(
+               struct dc_link *link,
+               const struct link_training_settings *link_training_setting);
+
+bool dp_is_cr_done(enum dc_lane_count ln_count,
+       union lane_status *dpcd_lane_status);
+
+bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
+       union lane_status *dpcd_lane_status);
+bool dp_is_symbol_locked(enum dc_lane_count ln_count,
+       union lane_status *dpcd_lane_status);
+bool dp_is_interlane_aligned(union lane_align_status_updated align_status);
+
+bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset);
+
+bool dp_is_max_vs_reached(
+       const struct link_training_settings *lt_settings);
+
+uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings);
+
+enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
+       union lane_status *dpcd_lane_status);
+
+void dp_hw_to_dpcd_lane_settings(
+       const struct link_training_settings *lt_settings,
+       const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+       union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
+
+void dp_wait_for_training_aux_rd_interval(
+       struct dc_link *link,
+       uint32_t wait_in_micro_secs);
+
+enum dpcd_training_patterns
+       dp_training_pattern_to_dpcd_training_pattern(
+       struct dc_link *link,
+       enum dc_dp_training_pattern pattern);
+
+uint8_t dp_initialize_scrambling_data_symbols(
+       struct dc_link *link,
+       enum dc_dp_training_pattern pattern);
+
+void dp_log_training_result(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings,
+       enum link_training_result status);
+
+uint32_t dp_translate_training_aux_read_interval(
+               uint32_t dpcd_aux_read_interval);
+
+uint8_t dp_get_nibble_at_index(const uint8_t *buf,
+       uint32_t index);
+#endif /* __DC_LINK_DP_TRAINING_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c
new file mode 100644 (file)
index 0000000..23d380f
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements dp 128b/132b link training software policies and
+ * sequences.
+ */
+#include "link_dp_training_128b_132b.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+static enum dc_status dpcd_128b_132b_set_lane_settings(
+               struct dc_link *link,
+               const struct link_training_settings *link_training_setting)
+{
+       enum dc_status status = core_link_write_dpcd(link,
+                       DP_TRAINING_LANE0_SET,
+                       (uint8_t *)(link_training_setting->dpcd_lane_settings),
+                       sizeof(link_training_setting->dpcd_lane_settings));
+
+       DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
+                       __func__,
+                       DP_TRAINING_LANE0_SET,
+                       link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
+       return status;
+}
+
+static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
+               uint32_t *interval_in_us)
+{
+       union dp_128b_132b_training_aux_rd_interval dpcd_interval;
+       uint32_t interval_unit = 0;
+
+       dpcd_interval.raw = 0;
+       core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL,
+                       &dpcd_interval.raw, sizeof(dpcd_interval.raw));
+       interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
+       /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
+        * INTERVAL_UNIT. The maximum is 256 ms
+        */
+       *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
+}
+
+static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       uint8_t loop_count;
+       uint32_t aux_rd_interval = 0;
+       uint32_t wait_time = 0;
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+       enum dc_status status = DC_OK;
+       enum link_training_result result = LINK_TRAINING_SUCCESS;
+
+       /* Transmit 128b/132b_TPS1 over Main-Link */
+       dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX);
+
+       /* Set TRAINING_PATTERN_SET to 01h */
+       dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
+
+       /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
+       dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
+       dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+                       &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+       dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+       dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
+       dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX);
+
+       /* Set loop counter to start from 1 */
+       loop_count = 1;
+
+       /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
+       dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
+                       lt_settings->pattern_for_eq, DPRX);
+
+       /* poll for channel EQ done */
+       while (result == LINK_TRAINING_SUCCESS) {
+               dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
+               wait_time += aux_rd_interval;
+               status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+                               &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+               dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+               } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count,
+                               dpcd_lane_status)) {
+                       /* pass */
+                       break;
+               } else if (loop_count >= lt_settings->eq_loop_count_limit) {
+                       result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
+               } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+                       result = DP_128b_132b_LT_FAILED;
+               } else {
+                       dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
+                       dpcd_128b_132b_set_lane_settings(link, lt_settings);
+               }
+               loop_count++;
+       }
+
+       /* poll for EQ interlane align done */
+       while (result == LINK_TRAINING_SUCCESS) {
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+               } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
+                       /* pass */
+                       break;
+               } else if (wait_time >= lt_settings->eq_wait_time_limit) {
+                       result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
+               } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+                       result = DP_128b_132b_LT_FAILED;
+               } else {
+                       dp_wait_for_training_aux_rd_interval(link,
+                                       lt_settings->eq_pattern_time);
+                       wait_time += lt_settings->eq_pattern_time;
+                       status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+                                       &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+               }
+       }
+
+       return result;
+}
+
+static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       /* Assumption: assume hardware has transmitted eq pattern */
+       enum dc_status status = DC_OK;
+       enum link_training_result result = LINK_TRAINING_SUCCESS;
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+       uint32_t wait_time = 0;
+
+       /* initiate CDS done sequence */
+       dpcd_set_training_pattern(link, lt_settings->pattern_for_cds);
+
+       /* poll for CDS interlane align done and symbol lock */
+       while (result == LINK_TRAINING_SUCCESS) {
+               dp_wait_for_training_aux_rd_interval(link,
+                               lt_settings->cds_pattern_time);
+               wait_time += lt_settings->cds_pattern_time;
+               status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+                                               &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+               } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) &&
+                               dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) {
+                       /* pass */
+                       break;
+               } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+                       result = DP_128b_132b_LT_FAILED;
+               } else if (wait_time >= lt_settings->cds_wait_time_limit) {
+                       result = DP_128b_132b_CDS_DONE_TIMEOUT;
+               }
+       }
+
+       return result;
+}
+
+enum link_training_result dp_perform_128b_132b_link_training(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       enum link_training_result result = LINK_TRAINING_SUCCESS;
+
+       /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
+       if (link->dc->debug.legacy_dp2_lt) {
+               struct link_training_settings legacy_settings;
+
+               decide_8b_10b_training_settings(link,
+                               &lt_settings->link_settings,
+                               &legacy_settings);
+               return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
+       }
+
+       dpcd_set_link_settings(link, lt_settings);
+
+       if (result == LINK_TRAINING_SUCCESS)
+               result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
+
+       if (result == LINK_TRAINING_SUCCESS)
+               result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
+
+       return result;
+}
+
+void decide_128b_132b_training_settings(struct dc_link *link,
+               const struct dc_link_settings *link_settings,
+               struct link_training_settings *lt_settings)
+{
+       memset(lt_settings, 0, sizeof(*lt_settings));
+
+       lt_settings->link_settings = *link_settings;
+       /* TODO: should decide link spread when populating link_settings */
+       lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
+                       LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+
+       lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
+       lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
+       lt_settings->eq_pattern_time = 2500;
+       lt_settings->eq_wait_time_limit = 400000;
+       lt_settings->eq_loop_count_limit = 20;
+       lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
+       lt_settings->cds_pattern_time = 2500;
+       lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count(
+                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
+       lt_settings->disallow_per_lane_settings = true;
+       lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
+       dp_hw_to_dpcd_lane_settings(lt_settings,
+                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+}
+
+enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
+{
+       enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
+
+       if (dp_is_lttpr_present(link))
+               mode = LTTPR_MODE_NON_TRANSPARENT;
+
+       DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
+       return mode;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h
new file mode 100644 (file)
index 0000000..2147f24
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_128B_132B_H__
+#define __DC_LINK_DP_TRAINING_128B_132B_H__
+#include "link_dp_training.h"
+
+enum link_training_result dp_perform_128b_132b_link_training(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings);
+
+void decide_128b_132b_training_settings(struct dc_link *link,
+               const struct dc_link_settings *link_settings,
+               struct link_training_settings *lt_settings);
+
+enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link);
+
+#endif /* __DC_LINK_DP_TRAINING_128B_132B_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c
new file mode 100644 (file)
index 0000000..14b98e0
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements dp 8b/10b link training software policies and
+ * sequences.
+ */
+#include "link_dp_training_8b_10b.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
+               const struct dc_link_settings *link_settings)
+{
+       union training_aux_rd_interval training_rd_interval;
+       uint32_t wait_in_micro_secs = 100;
+
+       memset(&training_rd_interval, 0, sizeof(training_rd_interval));
+       if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
+                       link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
+               core_link_read_dpcd(
+                               link,
+                               DP_TRAINING_AUX_RD_INTERVAL,
+                               (uint8_t *)&training_rd_interval,
+                               sizeof(training_rd_interval));
+               if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
+                       wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+       }
+       return wait_in_micro_secs;
+}
+
+static uint32_t get_eq_training_aux_rd_interval(
+       struct dc_link *link,
+       const struct dc_link_settings *link_settings)
+{
+       union training_aux_rd_interval training_rd_interval;
+
+       memset(&training_rd_interval, 0, sizeof(training_rd_interval));
+       if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+               core_link_read_dpcd(
+                               link,
+                               DP_128B132B_TRAINING_AUX_RD_INTERVAL,
+                               (uint8_t *)&training_rd_interval,
+                               sizeof(training_rd_interval));
+       } else if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
+                       link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
+               core_link_read_dpcd(
+                               link,
+                               DP_TRAINING_AUX_RD_INTERVAL,
+                               (uint8_t *)&training_rd_interval,
+                               sizeof(training_rd_interval));
+       }
+
+       switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
+       case 0: return 400;
+       case 1: return 4000;
+       case 2: return 8000;
+       case 3: return 12000;
+       case 4: return 16000;
+       case 5: return 32000;
+       case 6: return 64000;
+       default: return 400;
+       }
+}
+
+void decide_8b_10b_training_settings(
+        struct dc_link *link,
+       const struct dc_link_settings *link_setting,
+       struct link_training_settings *lt_settings)
+{
+       memset(lt_settings, '\0', sizeof(struct link_training_settings));
+
+       /* Initialize link settings */
+       lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
+       lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
+       lt_settings->link_settings.link_rate = link_setting->link_rate;
+       lt_settings->link_settings.lane_count = link_setting->lane_count;
+       /* TODO hard coded to SS for now
+        * lt_settings.link_settings.link_spread =
+        * dal_display_path_is_ss_supported(
+        * path_mode->display_path) ?
+        * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
+        * LINK_SPREAD_DISABLED;
+        */
+       lt_settings->link_settings.link_spread = link->dp_ss_off ?
+                       LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+       lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
+       lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
+       lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
+       lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
+       lt_settings->enhanced_framing = 1;
+       lt_settings->should_set_fec_ready = true;
+       lt_settings->disallow_per_lane_settings = true;
+       lt_settings->always_match_dpcd_with_hw_lane_settings = true;
+       lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
+       dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+}
+
+enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
+{
+       bool is_lttpr_present = dp_is_lttpr_present(link);
+       bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
+       bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
+
+       if (!is_lttpr_present)
+               return LTTPR_MODE_NON_LTTPR;
+
+       if (vbios_lttpr_aware) {
+               if (vbios_lttpr_force_non_transparent) {
+                       DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
+                       return LTTPR_MODE_NON_TRANSPARENT;
+               } else {
+                       DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
+                       return LTTPR_MODE_TRANSPARENT;
+               }
+       }
+
+       if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
+                       link->dc->caps.extended_aux_timeout_support) {
+               DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
+               return LTTPR_MODE_NON_TRANSPARENT;
+       }
+
+       DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
+       return LTTPR_MODE_NON_LTTPR;
+}
+
+enum link_training_result perform_8b_10b_clock_recovery_sequence(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings,
+       uint32_t offset)
+{
+       uint32_t retries_cr;
+       uint32_t retry_count;
+       uint32_t wait_time_microsec;
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+       union lane_align_status_updated dpcd_lane_status_updated;
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+       retries_cr = 0;
+       retry_count = 0;
+
+       memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+       memset(&dpcd_lane_status_updated, '\0',
+       sizeof(dpcd_lane_status_updated));
+
+       if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
+               dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
+
+       /* najeeb - The synaptics MST hub can put the LT in
+       * infinite loop by switching the VS
+       */
+       /* between level 0 and level 1 continuously, here
+       * we try for CR lock for LinkTrainingMaxCRRetry count*/
+       while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+               (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+
+               /* 1. call HWSS to set lane settings*/
+               dp_set_hw_lane_settings(
+                               link,
+                               link_res,
+                               lt_settings,
+                               offset);
+
+               /* 2. update DPCD of the receiver*/
+               if (!retry_count)
+                       /* EPR #361076 - write as a 5-byte burst,
+                        * but only for the 1-st iteration.*/
+                       dpcd_set_lt_pattern_and_lane_settings(
+                                       link,
+                                       lt_settings,
+                                       lt_settings->pattern_for_cr,
+                                       offset);
+               else
+                       dpcd_set_lane_settings(
+                                       link,
+                                       lt_settings,
+                                       offset);
+
+               /* 3. wait receiver to lock-on*/
+               wait_time_microsec = lt_settings->cr_pattern_time;
+
+               dp_wait_for_training_aux_rd_interval(
+                               link,
+                               wait_time_microsec);
+
+               /* 4. Read lane status and requested drive
+               * settings as set by the sink
+               */
+               dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               offset);
+
+               /* 5. check CR done*/
+               if (dp_is_cr_done(lane_count, dpcd_lane_status))
+                       return LINK_TRAINING_SUCCESS;
+
+               /* 6. max VS reached*/
+               if ((link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                               DP_8b_10b_ENCODING) &&
+                               dp_is_max_vs_reached(lt_settings))
+                       break;
+
+               /* 7. same lane settings*/
+               /* Note: settings are the same for all lanes,
+                * so comparing first lane is sufficient*/
+               if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING) &&
+                               lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
+                                               dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
+                       retries_cr++;
+               else if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
+                               lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
+                                               dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
+                       retries_cr++;
+               else
+                       retries_cr = 0;
+
+               /* 8. update VS/PE/PC2 in lt_settings*/
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+               retry_count++;
+       }
+
+       if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
+               ASSERT(0);
+               DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
+                       __func__,
+                       LINK_TRAINING_MAX_CR_RETRY);
+
+       }
+
+       return dp_get_cr_failure(lane_count, dpcd_lane_status);
+}
+
+enum link_training_result perform_8b_10b_channel_equalization_sequence(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings,
+       uint32_t offset)
+{
+       enum dc_dp_training_pattern tr_pattern;
+       uint32_t retries_ch_eq;
+       uint32_t wait_time_microsec;
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+       /* Note: also check that TPS4 is a supported feature*/
+       tr_pattern = lt_settings->pattern_for_eq;
+
+       if (is_repeater(lt_settings, offset) && link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
+               tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+
+       dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
+
+       for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
+               retries_ch_eq++) {
+
+               dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
+
+               /* 2. update DPCD*/
+               if (!retries_ch_eq)
+                       /* EPR #361076 - write as a 5-byte burst,
+                        * but only for the 1-st iteration
+                        */
+
+                       dpcd_set_lt_pattern_and_lane_settings(
+                               link,
+                               lt_settings,
+                               tr_pattern, offset);
+               else
+                       dpcd_set_lane_settings(link, lt_settings, offset);
+
+               /* 3. wait for receiver to lock-on*/
+               wait_time_microsec = lt_settings->eq_pattern_time;
+
+               if (is_repeater(lt_settings, offset))
+                       wait_time_microsec =
+                                       dp_translate_training_aux_read_interval(
+                                               link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
+
+               dp_wait_for_training_aux_rd_interval(
+                               link,
+                               wait_time_microsec);
+
+               /* 4. Read lane status and requested
+                * drive settings as set by the sink*/
+
+               dp_get_lane_status_and_lane_adjust(
+                       link,
+                       lt_settings,
+                       dpcd_lane_status,
+                       &dpcd_lane_status_updated,
+                       dpcd_lane_adjust,
+                       offset);
+
+               /* 5. check CR done*/
+               if (!dp_is_cr_done(lane_count, dpcd_lane_status))
+                       return dpcd_lane_status[0].bits.CR_DONE_0 ?
+                                       LINK_TRAINING_EQ_FAIL_CR_PARTIAL :
+                                       LINK_TRAINING_EQ_FAIL_CR;
+
+               /* 6. check CHEQ done*/
+               if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
+                               dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
+                               dp_is_interlane_aligned(dpcd_lane_status_updated))
+                       return LINK_TRAINING_SUCCESS;
+
+               /* 7. update VS/PE/PC2 in lt_settings*/
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+       }
+
+       return LINK_TRAINING_EQ_FAIL_EQ;
+
+}
+
+enum link_training_result dp_perform_8b_10b_link_training(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+
+       uint8_t repeater_cnt;
+       uint8_t repeater_id;
+       uint8_t lane = 0;
+
+       if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
+               start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
+
+       /* 1. set link rate, lane count and spread. */
+       dpcd_set_link_settings(link, lt_settings);
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+               /* 2. perform link training (set link training done
+                *  to false is done as well)
+                */
+               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+               for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
+                               repeater_id--) {
+                       status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
+
+                       if (status != LINK_TRAINING_SUCCESS) {
+                               repeater_training_done(link, repeater_id);
+                               break;
+                       }
+
+                       status = perform_8b_10b_channel_equalization_sequence(link,
+                                       link_res,
+                                       lt_settings,
+                                       repeater_id);
+
+                       repeater_training_done(link, repeater_id);
+
+                       if (status != LINK_TRAINING_SUCCESS)
+                               break;
+
+                       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+                               lt_settings->dpcd_lane_settings[lane].raw = 0;
+                               lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
+                               lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
+                       }
+               }
+       }
+
+       if (status == LINK_TRAINING_SUCCESS) {
+               status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
+               if (status == LINK_TRAINING_SUCCESS) {
+                       status = perform_8b_10b_channel_equalization_sequence(link,
+                                       link_res,
+                                       lt_settings,
+                                       DPRX);
+               }
+       }
+
+       return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h
new file mode 100644 (file)
index 0000000..d26de15
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_8B_10B_H__
+#define __DC_LINK_DP_TRAINING_8B_10B_H__
+#include "link_dp_training.h"
+
+/* to avoid infinite loop where-in the receiver
+ * switches between different VS
+ */
+#define LINK_TRAINING_MAX_CR_RETRY 100
+#define LINK_TRAINING_MAX_RETRY_COUNT 5
+
+enum link_training_result dp_perform_8b_10b_link_training(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings);
+
+enum link_training_result perform_8b_10b_clock_recovery_sequence(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings,
+       uint32_t offset);
+
+enum link_training_result perform_8b_10b_channel_equalization_sequence(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings,
+       uint32_t offset);
+
+enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link);
+
+void decide_8b_10b_training_settings(
+        struct dc_link *link,
+       const struct dc_link_settings *link_setting,
+       struct link_training_settings *lt_settings);
+
+#endif /* __DC_LINK_DP_TRAINING_8B_10B_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c
new file mode 100644 (file)
index 0000000..e50ec50
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ */
+#include "link_dp_training_auxless.h"
+#include "link_dp_phy.h"
+#define DC_LOGGER \
+       link->ctx->logger
+bool dc_link_dp_perform_link_training_skip_aux(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       const struct dc_link_settings *link_setting)
+{
+       struct link_training_settings lt_settings = {0};
+
+       dp_decide_training_settings(
+                       link,
+                       link_setting,
+                       &lt_settings);
+       override_training_settings(
+                       link,
+                       &link->preferred_training_settings,
+                       &lt_settings);
+
+       /* 1. Perform_clock_recovery_sequence. */
+
+       /* transmit training pattern for clock recovery */
+       dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX);
+
+       /* call HWSS to set lane settings*/
+       dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
+
+       /* wait receiver to lock-on*/
+       dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
+
+       /* 2. Perform_channel_equalization_sequence. */
+
+       /* transmit training pattern for channel equalization. */
+       dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX);
+
+       /* call HWSS to set lane settings*/
+       dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
+
+       /* wait receiver to lock-on. */
+       dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
+
+       /* 3. Perform_link_training_int. */
+
+       /* Mainlink output idle pattern. */
+       dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+       dp_log_training_result(link, &lt_settings, LINK_TRAINING_SUCCESS);
+
+       return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h
new file mode 100644 (file)
index 0000000..413999c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_AUXLESS_H__
+#define __DC_LINK_DP_TRAINING_AUXLESS_H__
+#include "link_dp_training.h"
+
+bool dc_link_dp_perform_link_training_skip_aux(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       const struct dc_link_settings *link_setting);
+#endif /* __DC_LINK_DP_TRAINING_AUXLESS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c
new file mode 100644 (file)
index 0000000..0565762
--- /dev/null
@@ -0,0 +1,1044 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This module implements functionality for training DPIA links.
+ */
+#include "link_dp_training_dpia.h"
+#include "dc.h"
+#include "inc/core_status.h"
+#include "dc_link.h"
+#include "dpcd_defs.h"
+
+#include "link_dp_dpia.h"
+#include "link_hwss.h"
+#include "dm_helpers.h"
+#include "dmub/inc/dmub_cmd.h"
+#include "link_dpcd.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dp_capability.h"
+#include "dc_dmub_srv.h"
+#define DC_LOGGER \
+       link->ctx->logger
+
+/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */
+#define DPIA_CLK_SYNC_DELAY 16000
+
+/* Extend interval between training status checks for manual testing. */
+#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000
+
+/* SET_CONFIG message types sent by driver. */
+enum dpia_set_config_type {
+       DPIA_SET_CFG_SET_LINK = 0x01,
+       DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05,
+       DPIA_SET_CFG_SET_TRAINING = 0x18,
+       DPIA_SET_CFG_SET_VSPE = 0x19
+};
+
+/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */
+enum dpia_set_config_ts {
+       DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */
+       DPIA_TS_TPS1 = 0x01,
+       DPIA_TS_TPS2 = 0x02,
+       DPIA_TS_TPS3 = 0x03,
+       DPIA_TS_TPS4 = 0x07,
+       DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */
+};
+
+/* SET_CONFIG message data associated with messages sent by driver. */
+union dpia_set_config_data {
+       struct {
+               uint8_t mode : 1;
+               uint8_t reserved : 7;
+       } set_link;
+       struct {
+               uint8_t stage;
+       } set_training;
+       struct {
+               uint8_t swing : 2;
+               uint8_t max_swing_reached : 1;
+               uint8_t pre_emph : 2;
+               uint8_t max_pre_emph_reached : 1;
+               uint8_t reserved : 2;
+       } set_vspe;
+       uint8_t raw;
+};
+
+
+/* Configure link as prescribed in link_setting; set LTTPR mode; and
+ * Initialize link training settings.
+ * Abort link training if sink unplug detected.
+ *
+ * @param link DPIA link being trained.
+ * @param[in] link_setting Lane count, link rate and downspread control.
+ * @param[out] lt_settings Link settings and drive settings (voltage swing and pre-emphasis).
+ */
+static enum link_training_result dpia_configure_link(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               const struct dc_link_settings *link_setting,
+               struct link_training_settings *lt_settings)
+{
+       enum dc_status status;
+       bool fec_enable;
+
+       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               lt_settings->lttpr_mode);
+
+       dp_decide_training_settings(
+               link,
+               link_setting,
+               lt_settings);
+
+       dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
+
+       status = dpcd_configure_channel_coding(link, lt_settings);
+       if (status != DC_OK && link->is_hpd_pending)
+               return LINK_TRAINING_ABORT;
+
+       /* Configure lttpr mode */
+       status = dpcd_configure_lttpr_mode(link, lt_settings);
+       if (status != DC_OK && link->is_hpd_pending)
+               return LINK_TRAINING_ABORT;
+
+       /* Set link rate, lane count and spread. */
+       status = dpcd_set_link_settings(link, lt_settings);
+       if (status != DC_OK && link->is_hpd_pending)
+               return LINK_TRAINING_ABORT;
+
+       if (link->preferred_training_settings.fec_enable != NULL)
+               fec_enable = *link->preferred_training_settings.fec_enable;
+       else
+               fec_enable = true;
+       status = dp_set_fec_ready(link, link_res, fec_enable);
+       if (status != DC_OK && link->is_hpd_pending)
+               return LINK_TRAINING_ABORT;
+
+       return LINK_TRAINING_SUCCESS;
+}
+
+static enum dc_status core_link_send_set_config(
+       struct dc_link *link,
+       uint8_t msg_type,
+       uint8_t msg_data)
+{
+       struct set_config_cmd_payload payload;
+       enum set_config_status set_config_result = SET_CONFIG_PENDING;
+
+       /* prepare set_config payload */
+       payload.msg_type = msg_type;
+       payload.msg_data = msg_data;
+
+       if (!link->ddc->ddc_pin && !link->aux_access_disabled &&
+                       (dm_helpers_dmub_set_config_sync(link->ctx,
+                       link, &payload, &set_config_result) == -1)) {
+               return DC_ERROR_UNEXPECTED;
+       }
+
+       /* set_config should return ACK if successful */
+       return (set_config_result == SET_CONFIG_ACK_RECEIVED) ? DC_OK : DC_ERROR_UNEXPECTED;
+}
+
+/* Build SET_CONFIG message data payload for specified message type. */
+static uint8_t dpia_build_set_config_data(
+               enum dpia_set_config_type type,
+               struct dc_link *link,
+               struct link_training_settings *lt_settings)
+{
+       union dpia_set_config_data data;
+
+       data.raw = 0;
+
+       switch (type) {
+       case DPIA_SET_CFG_SET_LINK:
+               data.set_link.mode = lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT ? 1 : 0;
+               break;
+       case DPIA_SET_CFG_SET_PHY_TEST_MODE:
+               break;
+       case DPIA_SET_CFG_SET_VSPE:
+               /* Assume all lanes have same drive settings. */
+               data.set_vspe.swing = lt_settings->hw_lane_settings[0].VOLTAGE_SWING;
+               data.set_vspe.pre_emph = lt_settings->hw_lane_settings[0].PRE_EMPHASIS;
+               data.set_vspe.max_swing_reached =
+                               lt_settings->hw_lane_settings[0].VOLTAGE_SWING == VOLTAGE_SWING_MAX_LEVEL ? 1 : 0;
+               data.set_vspe.max_pre_emph_reached =
+                               lt_settings->hw_lane_settings[0].PRE_EMPHASIS == PRE_EMPHASIS_MAX_LEVEL ? 1 : 0;
+               break;
+       default:
+               ASSERT(false); /* Message type not supported by helper function. */
+               break;
+       }
+
+       return data.raw;
+}
+
+/* Convert DC training pattern to DPIA training stage. */
+static enum dc_status convert_trng_ptn_to_trng_stg(enum dc_dp_training_pattern tps, enum dpia_set_config_ts *ts)
+{
+       enum dc_status status = DC_OK;
+
+       switch (tps) {
+       case DP_TRAINING_PATTERN_SEQUENCE_1:
+               *ts = DPIA_TS_TPS1;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_2:
+               *ts = DPIA_TS_TPS2;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_3:
+               *ts = DPIA_TS_TPS3;
+               break;
+       case DP_TRAINING_PATTERN_SEQUENCE_4:
+               *ts = DPIA_TS_TPS4;
+               break;
+       case DP_TRAINING_PATTERN_VIDEOIDLE:
+               *ts = DPIA_TS_DPRX_DONE;
+               break;
+       default: /* TPS not supported by helper function. */
+               ASSERT(false);
+               *ts = DPIA_TS_DPRX_DONE;
+               status = DC_UNSUPPORTED_VALUE;
+               break;
+       }
+
+       return status;
+}
+
+/* Write training pattern to DPCD. */
+static enum dc_status dpcd_set_lt_pattern(
+       struct dc_link *link,
+       enum dc_dp_training_pattern pattern,
+       uint32_t hop)
+{
+       union dpcd_training_pattern dpcd_pattern = {0};
+       uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
+       enum dc_status status;
+
+       if (hop != DPRX)
+               dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
+
+       /* DpcdAddress_TrainingPatternSet */
+       dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
+               dp_training_pattern_to_dpcd_training_pattern(link, pattern);
+
+       dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
+               dp_initialize_scrambling_data_symbols(link, pattern);
+
+       if (hop != DPRX) {
+               DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
+                       __func__,
+                       hop,
+                       dpcd_tps_offset,
+                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+       } else {
+               DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
+                       __func__,
+                       dpcd_tps_offset,
+                       dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+       }
+
+       status = core_link_write_dpcd(
+                       link,
+                       dpcd_tps_offset,
+                       &dpcd_pattern.raw,
+                       sizeof(dpcd_pattern.raw));
+
+       return status;
+}
+
+/* Execute clock recovery phase of link training for specified hop in display
+ * path.in non-transparent mode:
+ * - Driver issues both DPCD and SET_CONFIG transactions.
+ * - TPS1 is transmitted for any hops downstream of DPOA.
+ * - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
+ * - CR for the first hop (DPTX-to-DPIA) is assumed to be successful.
+ *
+ * @param link DPIA link being trained.
+ * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static enum link_training_result dpia_training_cr_non_transparent(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
+       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
+       enum dc_status status;
+       uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
+       uint32_t retry_count = 0;
+       uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL; /* From DP spec, CR read interval is always 100us. */
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+       uint8_t set_cfg_data;
+       enum dpia_set_config_ts ts;
+
+       repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+       /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
+        * Fix inherited from perform_clock_recovery_sequence() -
+        * the DP equivalent of this function:
+        * Required for Synaptics MST hub which can put the LT in
+        * infinite loop by switching the VS between level 0 and level 1
+        * continuously.
+        */
+       while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+                       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+               /* DPTX-to-DPIA */
+               if (hop == repeater_cnt) {
+                       /* Send SET_CONFIG(SET_LINK:LC,LR,LTTPR) to notify DPOA that
+                        * non-transparent link training has started.
+                        * This also enables the transmission of clk_sync packets.
+                        */
+                       set_cfg_data = dpia_build_set_config_data(
+                                       DPIA_SET_CFG_SET_LINK,
+                                       link,
+                                       lt_settings);
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_LINK,
+                                       set_cfg_data);
+                       /* CR for this hop is considered successful as long as
+                        * SET_CONFIG message is acknowledged by DPOA.
+                        */
+                       if (status == DC_OK)
+                               result = LINK_TRAINING_SUCCESS;
+                       else
+                               result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               /* DPOA-to-x */
+               /* Instruct DPOA to transmit TPS1 then update DPCD. */
+               if (retry_count == 0) {
+                       status = convert_trng_ptn_to_trng_stg(lt_settings->pattern_for_cr, &ts);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_TRAINING,
+                                       ts);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+                       status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, hop);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+               }
+
+               /* Update DPOA drive settings then DPCD. DPOA does only adjusts
+                * drive settings for hops immediately downstream.
+                */
+               if (hop == repeater_cnt - 1) {
+                       set_cfg_data = dpia_build_set_config_data(
+                                       DPIA_SET_CFG_SET_VSPE,
+                                       link,
+                                       lt_settings);
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_VSPE,
+                                       set_cfg_data);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+               }
+               status = dpcd_set_lane_settings(link, lt_settings, hop);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
+
+               /* Read status and adjustment requests from DPCD. */
+               status = dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               hop);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               /* Check if clock recovery successful. */
+               if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
+                       result = LINK_TRAINING_SUCCESS;
+                       break;
+               }
+
+               result = dp_get_cr_failure(lane_count, dpcd_lane_status);
+
+               if (dp_is_max_vs_reached(lt_settings))
+                       break;
+
+               /* Count number of attempts with same drive settings.
+                * Note: settings are the same for all lanes,
+                * so comparing first lane is sufficient.
+                */
+               if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
+                               dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
+                               && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
+                                               dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
+                       retries_cr++;
+               else
+                       retries_cr = 0;
+
+               /* Update VS/PE. */
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings,
+                               lt_settings->dpcd_lane_settings);
+               retry_count++;
+       }
+
+       /* Abort link training if clock recovery failed due to HPD unplug. */
+       if (link->is_hpd_pending)
+               result = LINK_TRAINING_ABORT;
+
+       DC_LOG_HW_LINK_TRAINING(
+               "%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n - status(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               hop,
+               result,
+               retry_count,
+               status);
+
+       return result;
+}
+
+/* Execute clock recovery phase of link training in transparent LTTPR mode:
+ * - Driver only issues DPCD transactions and leaves USB4 tunneling (SET_CONFIG) messages to DPIA.
+ * - Driver writes TPS1 to DPCD to kick off training.
+ * - Clock recovery (CR) for link is handled by DPOA, which reports result to DPIA on completion.
+ * - DPIA communicates result to driver by updating CR status when driver reads DPCD.
+ *
+ * @param link DPIA link being trained.
+ * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
+ */
+static enum link_training_result dpia_training_cr_transparent(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
+       enum dc_status status;
+       uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
+       uint32_t retry_count = 0;
+       uint32_t wait_time_microsec = lt_settings->cr_pattern_time;
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+       /* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
+        * Fix inherited from perform_clock_recovery_sequence() -
+        * the DP equivalent of this function:
+        * Required for Synaptics MST hub which can put the LT in
+        * infinite loop by switching the VS between level 0 and level 1
+        * continuously.
+        */
+       while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+                       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+               /* Write TPS1 (not VS or PE) to DPCD to start CR phase.
+                * DPIA sends SET_CONFIG(SET_LINK) to notify DPOA to
+                * start link training.
+                */
+               if (retry_count == 0) {
+                       status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, DPRX);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+               }
+
+               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
+
+               /* Read status and adjustment requests from DPCD. */
+               status = dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               DPRX);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               /* Check if clock recovery successful. */
+               if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
+                       result = LINK_TRAINING_SUCCESS;
+                       break;
+               }
+
+               result = dp_get_cr_failure(lane_count, dpcd_lane_status);
+
+               if (dp_is_max_vs_reached(lt_settings))
+                       break;
+
+               /* Count number of attempts with same drive settings.
+                * Note: settings are the same for all lanes,
+                * so comparing first lane is sufficient.
+                */
+               if ((lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
+                               dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
+                               && (lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET ==
+                                               dpcd_lane_adjust[0].bits.PRE_EMPHASIS_LANE))
+                       retries_cr++;
+               else
+                       retries_cr = 0;
+
+               /* Update VS/PE. */
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+               retry_count++;
+       }
+
+       /* Abort link training if clock recovery failed due to HPD unplug. */
+       if (link->is_hpd_pending)
+               result = LINK_TRAINING_ABORT;
+
+       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               DPRX,
+               result,
+               retry_count);
+
+       return result;
+}
+
+/* Execute clock recovery phase of link training for specified hop in display
+ * path.
+ *
+ * @param link DPIA link being trained.
+ * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static enum link_training_result dpia_training_cr_phase(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0;
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
+               result = dpia_training_cr_non_transparent(link, link_res, lt_settings, hop);
+       else
+               result = dpia_training_cr_transparent(link, link_res, lt_settings);
+
+       return result;
+}
+
+/* Return status read interval during equalization phase. */
+static uint32_t dpia_get_eq_aux_rd_interval(
+               const struct dc_link *link,
+               const struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       uint32_t wait_time_microsec;
+
+       if (hop == DPRX)
+               wait_time_microsec = lt_settings->eq_pattern_time;
+       else
+               wait_time_microsec =
+                               dp_translate_training_aux_read_interval(
+                                       link->dpcd_caps.lttpr_caps.aux_rd_interval[hop - 1]);
+
+       /* Check debug option for extending aux read interval. */
+       if (link->dc->debug.dpia_debug.bits.extend_aux_rd_interval)
+               wait_time_microsec = DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US;
+
+       return wait_time_microsec;
+}
+
+/* Execute equalization phase of link training for specified hop in display
+ * path in non-transparent mode:
+ * - driver issues both DPCD and SET_CONFIG transactions.
+ * - TPSx is transmitted for any hops downstream of DPOA.
+ * - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
+ * - EQ for the first hop (DPTX-to-DPIA) is assumed to be successful.
+ * - DPRX EQ only reported successful when both DPRX and DPIA requirements (clk sync packets sent) fulfilled.
+ *
+ * @param link DPIA link being trained.
+ * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static enum link_training_result dpia_training_eq_non_transparent(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
+       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
+       uint32_t retries_eq = 0;
+       enum dc_status status;
+       enum dc_dp_training_pattern tr_pattern;
+       uint32_t wait_time_microsec;
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+       uint8_t set_cfg_data;
+       enum dpia_set_config_ts ts;
+
+       /* Training pattern is TPS4 for repeater;
+        * TPS2/3/4 for DPRX depending on what it supports.
+        */
+       if (hop == DPRX)
+               tr_pattern = lt_settings->pattern_for_eq;
+       else
+               tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+
+       repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+       for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
+
+               /* DPTX-to-DPIA equalization always successful. */
+               if (hop == repeater_cnt) {
+                       result = LINK_TRAINING_SUCCESS;
+                       break;
+               }
+
+               /* Instruct DPOA to transmit TPSn then update DPCD. */
+               if (retries_eq == 0) {
+                       status = convert_trng_ptn_to_trng_stg(tr_pattern, &ts);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_TRAINING,
+                                       ts);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+                       status = dpcd_set_lt_pattern(link, tr_pattern, hop);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+               }
+
+               /* Update DPOA drive settings then DPCD. DPOA only adjusts
+                * drive settings for hop immediately downstream.
+                */
+               if (hop == repeater_cnt - 1) {
+                       set_cfg_data = dpia_build_set_config_data(
+                                       DPIA_SET_CFG_SET_VSPE,
+                                       link,
+                                       lt_settings);
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_VSPE,
+                                       set_cfg_data);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+               }
+               status = dpcd_set_lane_settings(link, lt_settings, hop);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               /* Extend wait time on second equalisation attempt on final hop to
+                * ensure clock sync packets have been sent.
+                */
+               if (hop == DPRX && retries_eq == 1)
+                       wait_time_microsec = max(wait_time_microsec, (uint32_t) DPIA_CLK_SYNC_DELAY);
+               else
+                       wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, hop);
+
+               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
+
+               /* Read status and adjustment requests from DPCD. */
+               status = dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               hop);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               /* CR can still fail during EQ phase. Fail training if CR fails. */
+               if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
+                       result = LINK_TRAINING_EQ_FAIL_CR;
+                       break;
+               }
+
+               if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
+                               dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
+                               dp_is_interlane_aligned(dpcd_lane_status_updated)) {
+                       result =  LINK_TRAINING_SUCCESS;
+                       break;
+               }
+
+               /* Update VS/PE. */
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+       }
+
+       /* Abort link training if equalization failed due to HPD unplug. */
+       if (link->is_hpd_pending)
+               result = LINK_TRAINING_ABORT;
+
+       DC_LOG_HW_LINK_TRAINING(
+               "%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n - status(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               hop,
+               result,
+               retries_eq,
+               status);
+
+       return result;
+}
+
+/* Execute equalization phase of link training for specified hop in display
+ * path in transparent LTTPR mode:
+ * - driver only issues DPCD transactions leaves USB4 tunneling (SET_CONFIG) messages to DPIA.
+ * - driver writes TPSx to DPCD to notify DPIA that is in equalization phase.
+ * - equalization (EQ) for link is handled by DPOA, which reports result to DPIA on completion.
+ * - DPIA communicates result to driver by updating EQ status when driver reads DPCD.
+ *
+ * @param link DPIA link being trained.
+ * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static enum link_training_result dpia_training_eq_transparent(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ;
+       uint32_t retries_eq = 0;
+       enum dc_status status;
+       enum dc_dp_training_pattern tr_pattern = lt_settings->pattern_for_eq;
+       uint32_t wait_time_microsec;
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       union lane_align_status_updated dpcd_lane_status_updated = {0};
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+       union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+       wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX);
+
+       for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
+
+               if (retries_eq == 0) {
+                       status = dpcd_set_lt_pattern(link, tr_pattern, DPRX);
+                       if (status != DC_OK) {
+                               result = LINK_TRAINING_ABORT;
+                               break;
+                       }
+               }
+
+               dp_wait_for_training_aux_rd_interval(link, wait_time_microsec);
+
+               /* Read status and adjustment requests from DPCD. */
+               status = dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               DPRX);
+               if (status != DC_OK) {
+                       result = LINK_TRAINING_ABORT;
+                       break;
+               }
+
+               /* CR can still fail during EQ phase. Fail training if CR fails. */
+               if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
+                       result = LINK_TRAINING_EQ_FAIL_CR;
+                       break;
+               }
+
+               if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
+                               dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status)) {
+                       /* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4
+                        * has to share encoders unlike DP and USBC
+                        */
+                       if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->is_automated && retries_eq)) {
+                               result =  LINK_TRAINING_SUCCESS;
+                               break;
+                       }
+               }
+
+               /* Update VS/PE. */
+               dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                               lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+       }
+
+       /* Abort link training if equalization failed due to HPD unplug. */
+       if (link->is_hpd_pending)
+               result = LINK_TRAINING_ABORT;
+
+       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               DPRX,
+               result,
+               retries_eq);
+
+       return result;
+}
+
+/* Execute equalization phase of link training for specified hop in display
+ * path.
+ *
+ * @param link DPIA link being trained.
+ * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static enum link_training_result dpia_training_eq_phase(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       enum link_training_result result;
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
+               result = dpia_training_eq_non_transparent(link, link_res, lt_settings, hop);
+       else
+               result = dpia_training_eq_transparent(link, link_res, lt_settings);
+
+       return result;
+}
+
+/* End training of specified hop in display path. */
+static enum dc_status dpcd_clear_lt_pattern(
+       struct dc_link *link,
+       uint32_t hop)
+{
+       union dpcd_training_pattern dpcd_pattern = {0};
+       uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
+       enum dc_status status;
+
+       if (hop != DPRX)
+               dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
+
+       status = core_link_write_dpcd(
+                       link,
+                       dpcd_tps_offset,
+                       &dpcd_pattern.raw,
+                       sizeof(dpcd_pattern.raw));
+
+       return status;
+}
+
+/* End training of specified hop in display path.
+ *
+ * In transparent LTTPR mode:
+ * - driver clears training pattern for the specified hop in DPCD.
+ * In non-transparent LTTPR mode:
+ * - in addition to clearing training pattern, driver issues USB4 tunneling
+ * (SET_CONFIG) messages to notify DPOA when training is done for first hop
+ * (DPTX-to-DPIA) and last hop (DPRX).
+ *
+ * @param link DPIA link being trained.
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static enum link_training_result dpia_training_end(
+               struct dc_link *link,
+               struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       enum link_training_result result = LINK_TRAINING_SUCCESS;
+       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
+       enum dc_status status;
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+               if (hop == repeater_cnt) { /* DPTX-to-DPIA */
+                       /* Send SET_CONFIG(SET_TRAINING:0xff) to notify DPOA that
+                        * DPTX-to-DPIA hop trained. No DPCD write needed for first hop.
+                        */
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_TRAINING,
+                                       DPIA_TS_UFP_DONE);
+                       if (status != DC_OK)
+                               result = LINK_TRAINING_ABORT;
+               } else { /* DPOA-to-x */
+                       /* Write 0x0 to TRAINING_PATTERN_SET */
+                       status = dpcd_clear_lt_pattern(link, hop);
+                       if (status != DC_OK)
+                               result = LINK_TRAINING_ABORT;
+               }
+
+               /* Notify DPOA that non-transparent link training of DPRX done. */
+               if (hop == DPRX && result != LINK_TRAINING_ABORT) {
+                       status = core_link_send_set_config(
+                                       link,
+                                       DPIA_SET_CFG_SET_TRAINING,
+                                       DPIA_TS_DPRX_DONE);
+                       if (status != DC_OK)
+                               result = LINK_TRAINING_ABORT;
+               }
+
+       } else { /* non-LTTPR or transparent LTTPR. */
+
+               /* Write 0x0 to TRAINING_PATTERN_SET */
+               status = dpcd_clear_lt_pattern(link, hop);
+               if (status != DC_OK)
+                       result = LINK_TRAINING_ABORT;
+
+       }
+
+       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) end\n - hop(%d)\n - result(%d)\n - LTTPR mode(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               hop,
+               result,
+               lt_settings->lttpr_mode);
+
+       return result;
+}
+
+/* When aborting training of specified hop in display path, clean up by:
+ * - Attempting to clear DPCD TRAINING_PATTERN_SET, LINK_BW_SET and LANE_COUNT_SET.
+ * - Sending SET_CONFIG(SET_LINK) with lane count and link rate set to 0.
+ *
+ * @param link DPIA link being trained.
+ * @param hop Hop in display path. DPRX = 0.
+ */
+static void dpia_training_abort(
+               struct dc_link *link,
+               struct link_training_settings *lt_settings,
+               uint32_t hop)
+{
+       uint8_t data = 0;
+       uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
+
+       DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n",
+               __func__,
+               link->link_id.enum_id - ENUM_ID_1,
+               lt_settings->lttpr_mode,
+               link->is_hpd_pending);
+
+       /* Abandon clean-up if sink unplugged. */
+       if (link->is_hpd_pending)
+               return;
+
+       if (hop != DPRX)
+               dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+                       ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
+
+       core_link_write_dpcd(link, dpcd_tps_offset, &data, 1);
+       core_link_write_dpcd(link, DP_LINK_BW_SET, &data, 1);
+       core_link_write_dpcd(link, DP_LANE_COUNT_SET, &data, 1);
+       core_link_send_set_config(link, DPIA_SET_CFG_SET_LINK, data);
+}
+
+enum link_training_result dc_link_dpia_perform_link_training(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       const struct dc_link_settings *link_setting,
+       bool skip_video_pattern)
+{
+       enum link_training_result result;
+       struct link_training_settings lt_settings = {0};
+       uint8_t repeater_cnt = 0; /* Number of hops/repeaters in display path. */
+       int8_t repeater_id; /* Current hop. */
+
+       struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in
+
+       lt_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link_settings);
+
+       /* Configure link as prescribed in link_setting and set LTTPR mode. */
+       result = dpia_configure_link(link, link_res, link_setting, &lt_settings);
+       if (result != LINK_TRAINING_SUCCESS)
+               return result;
+
+       if (lt_settings.lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
+               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+       /* Train each hop in turn starting with the one closest to DPTX.
+        * In transparent or non-LTTPR mode, train only the final hop (DPRX).
+        */
+       for (repeater_id = repeater_cnt; repeater_id >= 0; repeater_id--) {
+               /* Clock recovery. */
+               result = dpia_training_cr_phase(link, link_res, &lt_settings, repeater_id);
+               if (result != LINK_TRAINING_SUCCESS)
+                       break;
+
+               /* Equalization. */
+               result = dpia_training_eq_phase(link, link_res, &lt_settings, repeater_id);
+               if (result != LINK_TRAINING_SUCCESS)
+                       break;
+
+               /* Stop training hop. */
+               result = dpia_training_end(link, &lt_settings, repeater_id);
+               if (result != LINK_TRAINING_SUCCESS)
+                       break;
+       }
+
+       /* Double-check link status if training successful; gracefully abort
+        * training of current hop if training failed due to message tunneling
+        * failure; end training of hop if training ended conventionally and
+        * falling back to lower bandwidth settings possible.
+        */
+       if (result == LINK_TRAINING_SUCCESS) {
+               msleep(5);
+               if (!link->is_automated)
+                       result = dp_check_link_loss_status(link, &lt_settings);
+       } else if (result == LINK_TRAINING_ABORT)
+               dpia_training_abort(link, &lt_settings, repeater_id);
+       else
+               dpia_training_end(link, &lt_settings, repeater_id);
+
+       return result;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h
new file mode 100644 (file)
index 0000000..0150f29
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_DPIA_H__
+#define __DC_LINK_DP_TRAINING_DPIA_H__
+#include "link_dp_training.h"
+
+/* Train DP tunneling link for USB4 DPIA display endpoint.
+ * DPIA equivalent of dc_link_dp_perfrorm_link_training.
+ * Aborts link training upon detection of sink unplug.
+ */
+enum link_training_result dc_link_dpia_perform_link_training(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       const struct dc_link_settings *link_setting,
+       bool skip_video_pattern);
+
+#endif /* __DC_LINK_DP_TRAINING_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
new file mode 100644 (file)
index 0000000..a4071d2
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements 8b/10b link training specially modified to support an
+ * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
+ * Unlike native dp connection this chip requires a modified link training
+ * protocol based on 8b/10b link training. Since this is a non standard sequence
+ * and we must support this hardware, we decided to isolate it in its own
+ * training sequence inside its own file.
+ */
+#include "link_dp_training_fixed_vs_pe_retimer.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+
+#define DC_LOGGER \
+       link->ctx->logger
+
+void dp_fixed_vs_pe_read_lane_adjust(
+       struct dc_link *link,
+       union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
+{
+       const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
+       const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
+       const uint8_t offset = dp_parse_lttpr_repeater_count(
+                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+       uint32_t vendor_lttpr_write_address = 0xF004F;
+       uint32_t vendor_lttpr_read_address = 0xF0053;
+       uint8_t dprx_vs = 0;
+       uint8_t dprx_pe = 0;
+       uint8_t lane;
+
+       if (offset != 0xFF) {
+               vendor_lttpr_write_address +=
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+               vendor_lttpr_read_address +=
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+       }
+
+       /* W/A to read lane settings requested by DPRX */
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_vs[0],
+                       sizeof(vendor_lttpr_write_data_vs));
+       core_link_read_dpcd(
+                       link,
+                       vendor_lttpr_read_address,
+                       &dprx_vs,
+                       1);
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_pe[0],
+                       sizeof(vendor_lttpr_write_data_pe));
+       core_link_read_dpcd(
+                       link,
+                       vendor_lttpr_read_address,
+                       &dprx_pe,
+                       1);
+
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET  = (dprx_vs >> (2 * lane)) & 0x3;
+               dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
+       }
+}
+
+
+void dp_fixed_vs_pe_set_retimer_lane_settings(
+       struct dc_link *link,
+       const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
+       uint8_t lane_count)
+{
+       const uint8_t offset = dp_parse_lttpr_repeater_count(
+                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+       const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
+       uint32_t vendor_lttpr_write_address = 0xF004F;
+       uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+       uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+       uint8_t lane = 0;
+
+       if (offset != 0xFF) {
+               vendor_lttpr_write_address +=
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+       }
+
+       for (lane = 0; lane < lane_count; lane++) {
+               vendor_lttpr_write_data_vs[3] |=
+                               dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
+               vendor_lttpr_write_data_pe[3] |=
+                               dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
+       }
+
+       /* Force LTTPR to output desired VS and PE */
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_reset[0],
+                       sizeof(vendor_lttpr_write_data_reset));
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_vs[0],
+                       sizeof(vendor_lttpr_write_data_vs));
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_pe[0],
+                       sizeof(vendor_lttpr_write_data_pe));
+}
+
+static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
+               struct dc_link *link,
+               const struct link_resource *link_res,
+               struct link_training_settings *lt_settings)
+{
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+       uint8_t lane = 0;
+       uint8_t toggle_rate = 0x6;
+       uint8_t target_rate = 0x6;
+       bool apply_toggle_rate_wa = false;
+       uint8_t repeater_cnt;
+       uint8_t repeater_id;
+
+       /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
+       if (lt_settings->cr_pattern_time < 16000)
+               lt_settings->cr_pattern_time = 16000;
+
+       /* Fixed VS/PE specific: Toggle link rate */
+       apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate);
+       target_rate = get_dpcd_link_rate(&lt_settings->link_settings);
+       toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
+
+       if (apply_toggle_rate_wa)
+               lt_settings->link_settings.link_rate = toggle_rate;
+
+       if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
+               start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
+
+       /* 1. set link rate, lane count and spread. */
+       dpcd_set_link_settings(link, lt_settings);
+
+       /* Fixed VS/PE specific: Toggle link rate back*/
+       if (apply_toggle_rate_wa) {
+               core_link_write_dpcd(
+                               link,
+                               DP_LINK_BW_SET,
+                               &target_rate,
+                               1);
+       }
+
+       link->vendor_specific_lttpr_link_rate_wa = target_rate;
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+               /* 2. perform link training (set link training done
+                *  to false is done as well)
+                */
+               repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+               for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
+                               repeater_id--) {
+                       status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
+
+                       if (status != LINK_TRAINING_SUCCESS) {
+                               repeater_training_done(link, repeater_id);
+                               break;
+                       }
+
+                       status = perform_8b_10b_channel_equalization_sequence(link,
+                                       link_res,
+                                       lt_settings,
+                                       repeater_id);
+
+                       repeater_training_done(link, repeater_id);
+
+                       if (status != LINK_TRAINING_SUCCESS)
+                               break;
+
+                       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+                               lt_settings->dpcd_lane_settings[lane].raw = 0;
+                               lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
+                               lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
+                       }
+               }
+       }
+
+       if (status == LINK_TRAINING_SUCCESS) {
+               status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
+               if (status == LINK_TRAINING_SUCCESS) {
+                       status = perform_8b_10b_channel_equalization_sequence(link,
+                                                                      link_res,
+                                                                      lt_settings,
+                                                                      DPRX);
+               }
+       }
+
+       return status;
+}
+
+
+enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings)
+{
+       const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
+       const uint8_t offset = dp_parse_lttpr_repeater_count(
+                       link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+       const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
+       const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
+       uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
+       uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+       uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+       uint32_t vendor_lttpr_write_address = 0xF004F;
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+       uint8_t lane = 0;
+       union down_spread_ctrl downspread = {0};
+       union lane_count_set lane_count_set = {0};
+       uint8_t toggle_rate;
+       uint8_t rate;
+
+       /* Only 8b/10b is supported */
+       ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
+                       DP_8b_10b_ENCODING);
+
+       if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+               status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
+               return status;
+       }
+
+       if (offset != 0xFF) {
+               vendor_lttpr_write_address +=
+                               ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+               /* Certain display and cable configuration require extra delay */
+               if (offset > 2)
+                       pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
+       }
+
+       /* Vendor specific: Reset lane settings */
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_reset[0],
+                       sizeof(vendor_lttpr_write_data_reset));
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_vs[0],
+                       sizeof(vendor_lttpr_write_data_vs));
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_pe[0],
+                       sizeof(vendor_lttpr_write_data_pe));
+
+       /* Vendor specific: Enable intercept */
+       core_link_write_dpcd(
+                       link,
+                       vendor_lttpr_write_address,
+                       &vendor_lttpr_write_data_intercept_en[0],
+                       sizeof(vendor_lttpr_write_data_intercept_en));
+
+       /* 1. set link rate, lane count and spread. */
+
+       downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
+
+       lane_count_set.bits.LANE_COUNT_SET =
+       lt_settings->link_settings.lane_count;
+
+       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+       lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+
+       if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
+               lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
+                               link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
+       }
+
+       core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
+               &downspread.raw, sizeof(downspread));
+
+       core_link_write_dpcd(link, DP_LANE_COUNT_SET,
+               &lane_count_set.raw, 1);
+
+       rate = get_dpcd_link_rate(&lt_settings->link_settings);
+
+       /* Vendor specific: Toggle link rate */
+       toggle_rate = (rate == 0x6) ? 0xA : 0x6;
+
+       if (link->vendor_specific_lttpr_link_rate_wa == rate) {
+               core_link_write_dpcd(
+                               link,
+                               DP_LINK_BW_SET,
+                               &toggle_rate,
+                               1);
+       }
+
+       link->vendor_specific_lttpr_link_rate_wa = rate;
+
+       core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
+
+       DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+               __func__,
+               DP_LINK_BW_SET,
+               lt_settings->link_settings.link_rate,
+               DP_LANE_COUNT_SET,
+               lt_settings->link_settings.lane_count,
+               lt_settings->enhanced_framing,
+               DP_DOWNSPREAD_CTRL,
+               lt_settings->link_settings.link_spread);
+
+       /* 2. Perform link training */
+
+       /* Perform Clock Recovery Sequence */
+       if (status == LINK_TRAINING_SUCCESS) {
+               const uint8_t max_vendor_dpcd_retries = 10;
+               uint32_t retries_cr;
+               uint32_t retry_count;
+               uint32_t wait_time_microsec;
+               enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+               union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+               union lane_align_status_updated dpcd_lane_status_updated;
+               union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+               enum dc_status dpcd_status = DC_OK;
+               uint8_t i = 0;
+
+               retries_cr = 0;
+               retry_count = 0;
+
+               memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+               memset(&dpcd_lane_status_updated, '\0',
+               sizeof(dpcd_lane_status_updated));
+
+               while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+                       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+
+                       /* 1. call HWSS to set lane settings */
+                       dp_set_hw_lane_settings(
+                                       link,
+                                       link_res,
+                                       lt_settings,
+                                       0);
+
+                       /* 2. update DPCD of the receiver */
+                       if (!retry_count) {
+                               /* EPR #361076 - write as a 5-byte burst,
+                                * but only for the 1-st iteration.
+                                */
+                               dpcd_set_lt_pattern_and_lane_settings(
+                                               link,
+                                               lt_settings,
+                                               lt_settings->pattern_for_cr,
+                                               0);
+                               /* Vendor specific: Disable intercept */
+                               for (i = 0; i < max_vendor_dpcd_retries; i++) {
+                                       msleep(pre_disable_intercept_delay_ms);
+                                       dpcd_status = core_link_write_dpcd(
+                                                       link,
+                                                       vendor_lttpr_write_address,
+                                                       &vendor_lttpr_write_data_intercept_dis[0],
+                                                       sizeof(vendor_lttpr_write_data_intercept_dis));
+
+                                       if (dpcd_status == DC_OK)
+                                               break;
+
+                                       core_link_write_dpcd(
+                                                       link,
+                                                       vendor_lttpr_write_address,
+                                                       &vendor_lttpr_write_data_intercept_en[0],
+                                                       sizeof(vendor_lttpr_write_data_intercept_en));
+                               }
+                       } else {
+                               vendor_lttpr_write_data_vs[3] = 0;
+                               vendor_lttpr_write_data_pe[3] = 0;
+
+                               for (lane = 0; lane < lane_count; lane++) {
+                                       vendor_lttpr_write_data_vs[3] |=
+                                                       lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
+                                       vendor_lttpr_write_data_pe[3] |=
+                                                       lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
+                               }
+
+                               /* Vendor specific: Update VS and PE to DPRX requested value */
+                               core_link_write_dpcd(
+                                               link,
+                                               vendor_lttpr_write_address,
+                                               &vendor_lttpr_write_data_vs[0],
+                                               sizeof(vendor_lttpr_write_data_vs));
+                               core_link_write_dpcd(
+                                               link,
+                                               vendor_lttpr_write_address,
+                                               &vendor_lttpr_write_data_pe[0],
+                                               sizeof(vendor_lttpr_write_data_pe));
+
+                               dpcd_set_lane_settings(
+                                               link,
+                                               lt_settings,
+                                               0);
+                       }
+
+                       /* 3. wait receiver to lock-on*/
+                       wait_time_microsec = lt_settings->cr_pattern_time;
+
+                       dp_wait_for_training_aux_rd_interval(
+                                       link,
+                                       wait_time_microsec);
+
+                       /* 4. Read lane status and requested drive
+                        * settings as set by the sink
+                        */
+                       dp_get_lane_status_and_lane_adjust(
+                                       link,
+                                       lt_settings,
+                                       dpcd_lane_status,
+                                       &dpcd_lane_status_updated,
+                                       dpcd_lane_adjust,
+                                       0);
+
+                       /* 5. check CR done*/
+                       if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
+                               status = LINK_TRAINING_SUCCESS;
+                               break;
+                       }
+
+                       /* 6. max VS reached*/
+                       if (dp_is_max_vs_reached(lt_settings))
+                               break;
+
+                       /* 7. same lane settings */
+                       /* Note: settings are the same for all lanes,
+                        * so comparing first lane is sufficient
+                        */
+                       if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
+                                       dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
+                               retries_cr++;
+                       else
+                               retries_cr = 0;
+
+                       /* 8. update VS/PE/PC2 in lt_settings*/
+                       dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+                       retry_count++;
+               }
+
+               if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
+                       ASSERT(0);
+                       DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
+                               __func__,
+                               LINK_TRAINING_MAX_CR_RETRY);
+
+               }
+
+               status = dp_get_cr_failure(lane_count, dpcd_lane_status);
+       }
+
+       /* Perform Channel EQ Sequence */
+       if (status == LINK_TRAINING_SUCCESS) {
+               enum dc_dp_training_pattern tr_pattern;
+               uint32_t retries_ch_eq;
+               uint32_t wait_time_microsec;
+               enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+               union lane_align_status_updated dpcd_lane_status_updated = {0};
+               union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+               union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+               /* Note: also check that TPS4 is a supported feature*/
+               tr_pattern = lt_settings->pattern_for_eq;
+
+               dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
+
+               status = LINK_TRAINING_EQ_FAIL_EQ;
+
+               for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
+                       retries_ch_eq++) {
+
+                       dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
+
+                       vendor_lttpr_write_data_vs[3] = 0;
+                       vendor_lttpr_write_data_pe[3] = 0;
+
+                       for (lane = 0; lane < lane_count; lane++) {
+                               vendor_lttpr_write_data_vs[3] |=
+                                               lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
+                               vendor_lttpr_write_data_pe[3] |=
+                                               lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
+                       }
+
+                       /* Vendor specific: Update VS and PE to DPRX requested value */
+                       core_link_write_dpcd(
+                                       link,
+                                       vendor_lttpr_write_address,
+                                       &vendor_lttpr_write_data_vs[0],
+                                       sizeof(vendor_lttpr_write_data_vs));
+                       core_link_write_dpcd(
+                                       link,
+                                       vendor_lttpr_write_address,
+                                       &vendor_lttpr_write_data_pe[0],
+                                       sizeof(vendor_lttpr_write_data_pe));
+
+                       /* 2. update DPCD*/
+                       if (!retries_ch_eq)
+                               /* EPR #361076 - write as a 5-byte burst,
+                                * but only for the 1-st iteration
+                                */
+
+                               dpcd_set_lt_pattern_and_lane_settings(
+                                       link,
+                                       lt_settings,
+                                       tr_pattern, 0);
+                       else
+                               dpcd_set_lane_settings(link, lt_settings, 0);
+
+                       /* 3. wait for receiver to lock-on*/
+                       wait_time_microsec = lt_settings->eq_pattern_time;
+
+                       dp_wait_for_training_aux_rd_interval(
+                                       link,
+                                       wait_time_microsec);
+
+                       /* 4. Read lane status and requested
+                        * drive settings as set by the sink
+                        */
+                       dp_get_lane_status_and_lane_adjust(
+                               link,
+                               lt_settings,
+                               dpcd_lane_status,
+                               &dpcd_lane_status_updated,
+                               dpcd_lane_adjust,
+                               0);
+
+                       /* 5. check CR done*/
+                       if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
+                               status = LINK_TRAINING_EQ_FAIL_CR;
+                               break;
+                       }
+
+                       /* 6. check CHEQ done*/
+                       if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
+                                       dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
+                                       dp_is_interlane_aligned(dpcd_lane_status_updated)) {
+                               status = LINK_TRAINING_SUCCESS;
+                               break;
+                       }
+
+                       /* 7. update VS/PE/PC2 in lt_settings*/
+                       dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+                                       lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+               }
+       }
+
+       return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h
new file mode 100644 (file)
index 0000000..e61970e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
+#define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
+#include "link_dp_training.h"
+
+enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+       struct dc_link *link,
+       const struct link_resource *link_res,
+       struct link_training_settings *lt_settings);
+
+void dp_fixed_vs_pe_set_retimer_lane_settings(
+       struct dc_link *link,
+       const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
+       uint8_t lane_count);
+
+void dp_fixed_vs_pe_read_lane_adjust(
+       struct dc_link *link,
+       union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]);
+
+#endif /* __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c
new file mode 100644 (file)
index 0000000..5c9a302
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2021 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 basic dpcd read/write functionality. It also does basic
+ * dpcd range check to ensure that every dpcd request is compliant with specs
+ * range requirements.
+ */
+
+#include "link_dpcd.h"
+#include <drm/display/drm_dp_helper.h>
+#include "dm_helpers.h"
+
+#define END_ADDRESS(start, size) (start + size - 1)
+#define ADDRESS_RANGE_SIZE(start, end) (end - start + 1)
+struct dpcd_address_range {
+       uint32_t start;
+       uint32_t end;
+};
+
+static enum dc_status internal_link_read_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       uint8_t *data,
+       uint32_t size)
+{
+       if (!link->aux_access_disabled &&
+                       !dm_helpers_dp_read_dpcd(link->ctx,
+                       link, address, data, size)) {
+               return DC_ERROR_UNEXPECTED;
+       }
+
+       return DC_OK;
+}
+
+static enum dc_status internal_link_write_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       const uint8_t *data,
+       uint32_t size)
+{
+       if (!link->aux_access_disabled &&
+                       !dm_helpers_dp_write_dpcd(link->ctx,
+                       link, address, data, size)) {
+               return DC_ERROR_UNEXPECTED;
+       }
+
+       return DC_OK;
+}
+
+/*
+ * Partition the entire DPCD address space
+ * XXX: This partitioning must cover the entire DPCD address space,
+ * and must contain no gaps or overlapping address ranges.
+ */
+static const struct dpcd_address_range mandatory_dpcd_partitions[] = {
+       { 0, DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1) - 1},
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR1), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR2), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR3), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR4), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR5), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR6), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR7), DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8) - 1 },
+       { DP_TRAINING_PATTERN_SET_PHY_REPEATER(DP_PHY_LTTPR8), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
+       /*
+        * The FEC registers are contiguous
+        */
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR1) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR2) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR3) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR4) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR5) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR6) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7), DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR7) - 1 },
+       { DP_FEC_STATUS_PHY_REPEATER(DP_PHY_LTTPR8), DP_LTTPR_MAX_ADD },
+       /* all remaining DPCD addresses */
+       { DP_LTTPR_MAX_ADD + 1, DP_DPCD_MAX_ADD } };
+
+static inline bool do_addresses_intersect_with_range(
+               const struct dpcd_address_range *range,
+               const uint32_t start_address,
+               const uint32_t end_address)
+{
+       return start_address <= range->end && end_address >= range->start;
+}
+
+static uint32_t dpcd_get_next_partition_size(const uint32_t address, const uint32_t size)
+{
+       const uint32_t end_address = END_ADDRESS(address, size);
+       uint32_t partition_iterator = 0;
+
+       /*
+        * find current partition
+        * this loop spins forever if partition map above is not surjective
+        */
+       while (!do_addresses_intersect_with_range(&mandatory_dpcd_partitions[partition_iterator],
+                               address, end_address))
+               partition_iterator++;
+       if (end_address < mandatory_dpcd_partitions[partition_iterator].end)
+               return size;
+       return ADDRESS_RANGE_SIZE(address, mandatory_dpcd_partitions[partition_iterator].end);
+}
+
+/*
+ * Ranges of DPCD addresses that must be read in a single transaction
+ * XXX: Do not allow any two address ranges in this array to overlap
+ */
+static const struct dpcd_address_range mandatory_dpcd_blocks[] = {
+       { DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT }};
+
+/*
+ * extend addresses to read all mandatory blocks together
+ */
+static void dpcd_extend_address_range(
+               const uint32_t in_address,
+               uint8_t * const in_data,
+               const uint32_t in_size,
+               uint32_t *out_address,
+               uint8_t **out_data,
+               uint32_t *out_size)
+{
+       const uint32_t end_address = END_ADDRESS(in_address, in_size);
+       const struct dpcd_address_range *addr_range;
+       struct dpcd_address_range new_addr_range;
+       uint32_t i;
+
+       new_addr_range.start = in_address;
+       new_addr_range.end = end_address;
+       for (i = 0; i < ARRAY_SIZE(mandatory_dpcd_blocks); i++) {
+               addr_range = &mandatory_dpcd_blocks[i];
+               if (addr_range->start <= in_address && addr_range->end >= in_address)
+                       new_addr_range.start = addr_range->start;
+
+               if (addr_range->start <= end_address && addr_range->end >= end_address)
+                       new_addr_range.end = addr_range->end;
+       }
+       *out_address = in_address;
+       *out_size = in_size;
+       *out_data = in_data;
+       if (new_addr_range.start != in_address || new_addr_range.end != end_address) {
+               *out_address = new_addr_range.start;
+               *out_size = ADDRESS_RANGE_SIZE(new_addr_range.start, new_addr_range.end);
+               *out_data = kzalloc(*out_size * sizeof(**out_data), GFP_KERNEL);
+       }
+}
+
+/*
+ * Reduce the AUX reply down to the values the caller requested
+ */
+static void dpcd_reduce_address_range(
+               const uint32_t extended_address,
+               uint8_t * const extended_data,
+               const uint32_t extended_size,
+               const uint32_t reduced_address,
+               uint8_t * const reduced_data,
+               const uint32_t reduced_size)
+{
+       const uint32_t offset = reduced_address - extended_address;
+
+       /*
+        * If the address is same, address was not extended.
+        * So we do not need to free any memory.
+        * The data is in original buffer(reduced_data).
+        */
+       if (extended_data == reduced_data)
+               return;
+
+       memcpy(&extended_data[offset], reduced_data, reduced_size);
+       kfree(extended_data);
+}
+
+enum dc_status core_link_read_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       uint8_t *data,
+       uint32_t size)
+{
+       uint32_t extended_address;
+       uint32_t partitioned_address;
+       uint8_t *extended_data;
+       uint32_t extended_size;
+       /* size of the remaining partitioned address space */
+       uint32_t size_left_to_read;
+       enum dc_status status;
+       /* size of the next partition to be read from */
+       uint32_t partition_size;
+       uint32_t data_index = 0;
+
+       dpcd_extend_address_range(address, data, size, &extended_address, &extended_data, &extended_size);
+       partitioned_address = extended_address;
+       size_left_to_read = extended_size;
+       while (size_left_to_read) {
+               partition_size = dpcd_get_next_partition_size(partitioned_address, size_left_to_read);
+               status = internal_link_read_dpcd(link, partitioned_address, &extended_data[data_index], partition_size);
+               if (status != DC_OK)
+                       break;
+               partitioned_address += partition_size;
+               data_index += partition_size;
+               size_left_to_read -= partition_size;
+       }
+       dpcd_reduce_address_range(extended_address, extended_data, extended_size, address, data, size);
+       return status;
+}
+
+enum dc_status core_link_write_dpcd(
+       struct dc_link *link,
+       uint32_t address,
+       const uint8_t *data,
+       uint32_t size)
+{
+       uint32_t partition_size;
+       uint32_t data_index = 0;
+       enum dc_status status;
+
+       while (size) {
+               partition_size = dpcd_get_next_partition_size(address, size);
+               status = internal_link_write_dpcd(link, address, &data[data_index], partition_size);
+               if (status != DC_OK)
+                       break;
+               address += partition_size;
+               data_index += partition_size;
+               size -= partition_size;
+       }
+       return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.h
new file mode 100644 (file)
index 0000000..08d787a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 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_DPCD_H__
+#define __LINK_DPCD_H__
+#include "link.h"
+#include "dpcd_defs.h"
+
+enum dc_status core_link_read_dpcd(
+               struct dc_link *link,
+               uint32_t address,
+               uint8_t *data,
+               uint32_t size);
+
+enum dc_status core_link_write_dpcd(
+               struct dc_link *link,
+               uint32_t address,
+               const uint8_t *data,
+               uint32_t size);
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
new file mode 100644 (file)
index 0000000..97e02b5
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements retrieval and configuration of eDP panel features such
+ * as PSR and ABM and it also manages specs defined eDP panel power sequences.
+ */
+
+#include "link_edp_panel_control.h"
+#include "link_dpcd.h"
+#include "link_dp_capability.h"
+#include "dm_helpers.h"
+#include "dal_asic_id.h"
+#include "dce/dmub_psr.h"
+#include "abm.h"
+#define DC_LOGGER_INIT(logger)
+
+void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
+{
+       union dpcd_edp_config edp_config_set;
+       bool panel_mode_edp = false;
+
+       memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
+
+       if (panel_mode != DP_PANEL_MODE_DEFAULT) {
+
+               switch (panel_mode) {
+               case DP_PANEL_MODE_EDP:
+               case DP_PANEL_MODE_SPECIAL:
+                       panel_mode_edp = true;
+                       break;
+
+               default:
+                               break;
+               }
+
+               /*set edp panel mode in receiver*/
+               core_link_read_dpcd(
+                       link,
+                       DP_EDP_CONFIGURATION_SET,
+                       &edp_config_set.raw,
+                       sizeof(edp_config_set.raw));
+
+               if (edp_config_set.bits.PANEL_MODE_EDP
+                       != panel_mode_edp) {
+                       enum dc_status result;
+
+                       edp_config_set.bits.PANEL_MODE_EDP =
+                       panel_mode_edp;
+                       result = core_link_write_dpcd(
+                               link,
+                               DP_EDP_CONFIGURATION_SET,
+                               &edp_config_set.raw,
+                               sizeof(edp_config_set.raw));
+
+                       ASSERT(result == DC_OK);
+               }
+       }
+       DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
+                "eDP panel mode enabled: %d \n",
+                link->link_index,
+                link->dpcd_caps.panel_mode_edp,
+                panel_mode_edp);
+}
+
+enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
+{
+       /* We need to explicitly check that connector
+        * is not DP. Some Travis_VGA get reported
+        * by video bios as DP.
+        */
+       if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
+
+               switch (link->dpcd_caps.branch_dev_id) {
+               case DP_BRANCH_DEVICE_ID_0022B9:
+                       /* alternate scrambler reset is required for Travis
+                        * for the case when external chip does not
+                        * provide sink device id, alternate scrambler
+                        * scheme will  be overriden later by querying
+                        * Encoder features
+                        */
+                       if (strncmp(
+                               link->dpcd_caps.branch_dev_name,
+                               DP_VGA_LVDS_CONVERTER_ID_2,
+                               sizeof(
+                               link->dpcd_caps.
+                               branch_dev_name)) == 0) {
+                                       return DP_PANEL_MODE_SPECIAL;
+                       }
+                       break;
+               case DP_BRANCH_DEVICE_ID_00001A:
+                       /* alternate scrambler reset is required for Travis
+                        * for the case when external chip does not provide
+                        * sink device id, alternate scrambler scheme will
+                        * be overriden later by querying Encoder feature
+                        */
+                       if (strncmp(link->dpcd_caps.branch_dev_name,
+                               DP_VGA_LVDS_CONVERTER_ID_3,
+                               sizeof(
+                               link->dpcd_caps.
+                               branch_dev_name)) == 0) {
+                                       return DP_PANEL_MODE_SPECIAL;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (link->dpcd_caps.panel_mode_edp &&
+               (link->connector_signal == SIGNAL_TYPE_EDP ||
+                (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+                 link->is_internal_display))) {
+               return DP_PANEL_MODE_EDP;
+       }
+
+       return DP_PANEL_MODE_DEFAULT;
+}
+
+bool dc_link_set_backlight_level_nits(struct dc_link *link,
+               bool isHDR,
+               uint32_t backlight_millinits,
+               uint32_t transition_time_in_ms)
+{
+       struct dpcd_source_backlight_set dpcd_backlight_set;
+       uint8_t backlight_control = isHDR ? 1 : 0;
+
+       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+                       link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+               return false;
+
+       // OLEDs have no PWM, they can only use AUX
+       if (link->dpcd_sink_ext_caps.bits.oled == 1)
+               backlight_control = 1;
+
+       *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
+       *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
+
+
+       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
+                       (uint8_t *)(&dpcd_backlight_set),
+                       sizeof(dpcd_backlight_set)) != DC_OK)
+               return false;
+
+       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL,
+                       &backlight_control, 1) != DC_OK)
+               return false;
+
+       return true;
+}
+
+bool dc_link_get_backlight_level_nits(struct dc_link *link,
+               uint32_t *backlight_millinits_avg,
+               uint32_t *backlight_millinits_peak)
+{
+       union dpcd_source_backlight_get dpcd_backlight_get;
+
+       memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get));
+
+       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+                       link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+               return false;
+
+       if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
+                       dpcd_backlight_get.raw,
+                       sizeof(union dpcd_source_backlight_get)))
+               return false;
+
+       *backlight_millinits_avg =
+               dpcd_backlight_get.bytes.backlight_millinits_avg;
+       *backlight_millinits_peak =
+               dpcd_backlight_get.bytes.backlight_millinits_peak;
+
+       /* On non-supported panels dpcd_read usually succeeds with 0 returned */
+       if (*backlight_millinits_avg == 0 ||
+                       *backlight_millinits_avg > *backlight_millinits_peak)
+               return false;
+
+       return true;
+}
+
+bool link_backlight_enable_aux(struct dc_link *link, bool enable)
+{
+       uint8_t backlight_enable = enable ? 1 : 0;
+
+       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+               link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+               return false;
+
+       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
+               &backlight_enable, 1) != DC_OK)
+               return false;
+
+       return true;
+}
+
+// we read default from 0x320 because we expect BIOS wrote it there
+// regular get_backlight_nit reads from panel set at 0x326
+static bool read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits)
+{
+       if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+               link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+               return false;
+
+       if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
+               (uint8_t *) backlight_millinits,
+               sizeof(uint32_t)))
+               return false;
+
+       return true;
+}
+
+bool set_default_brightness_aux(struct dc_link *link)
+{
+       uint32_t default_backlight;
+
+       if (link && link->dpcd_sink_ext_caps.bits.oled == 1) {
+               if (!read_default_bl_aux(link, &default_backlight))
+                       default_backlight = 150000;
+               // if < 5 nits or > 5000, it might be wrong readback
+               if (default_backlight < 5000 || default_backlight > 5000000)
+                       default_backlight = 150000; //
+
+               return dc_link_set_backlight_level_nits(link, true,
+                               default_backlight, 0);
+       }
+       return false;
+}
+
+bool link_is_edp_ilr_optimization_required(struct dc_link *link,
+               struct dc_crtc_timing *crtc_timing)
+{
+       struct dc_link_settings link_setting;
+       uint8_t link_bw_set;
+       uint8_t link_rate_set;
+       uint32_t req_bw;
+       union lane_count_set lane_count_set = {0};
+
+       ASSERT(link || crtc_timing); // invalid input
+
+       if (link->dpcd_caps.edp_supported_link_rates_count == 0 ||
+                       !link->panel_config.ilr.optimize_edp_link_rate)
+               return false;
+
+
+       // Read DPCD 00100h to find if standard link rates are set
+       core_link_read_dpcd(link, DP_LINK_BW_SET,
+                               &link_bw_set, sizeof(link_bw_set));
+
+       if (link_bw_set) {
+               DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS used link_bw_set\n");
+               return true;
+       }
+
+       // Read DPCD 00115h to find the edp link rate set used
+       core_link_read_dpcd(link, DP_LINK_RATE_SET,
+                           &link_rate_set, sizeof(link_rate_set));
+
+       // Read DPCD 00101h to find out the number of lanes currently set
+       core_link_read_dpcd(link, DP_LANE_COUNT_SET,
+                               &lane_count_set.raw, sizeof(lane_count_set));
+
+       req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing);
+
+       if (!crtc_timing->flags.DSC)
+               dc_link_decide_edp_link_settings(link, &link_setting, req_bw);
+       else
+               decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN);
+
+       if (link->dpcd_caps.edp_supported_link_rates[link_rate_set] != link_setting.link_rate ||
+                       lane_count_set.bits.LANE_COUNT_SET != link_setting.lane_count) {
+               DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n");
+               return true;
+       }
+
+       DC_LOG_EVENT_LINK_TRAINING("eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n");
+       return false;
+}
+
+void dc_link_edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd)
+{
+       if (link->connector_signal != SIGNAL_TYPE_EDP)
+               return;
+
+       link->dc->hwss.edp_power_control(link, true);
+       if (wait_for_hpd)
+               link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+       if (link->dc->hwss.edp_backlight_control)
+               link->dc->hwss.edp_backlight_control(link, true);
+}
+
+bool dc_link_wait_for_t12(struct dc_link *link)
+{
+       if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
+               link->dc->hwss.edp_wait_for_T12(link);
+
+               return true;
+       }
+
+       return false;
+}
+
+void link_edp_add_delay_for_T9(struct dc_link *link)
+{
+       if (link && link->panel_config.pps.extra_delay_backlight_off > 0)
+               udelay(link->panel_config.pps.extra_delay_backlight_off * 1000);
+}
+
+bool link_edp_receiver_ready_T9(struct dc_link *link)
+{
+       unsigned int tries = 0;
+       unsigned char sinkstatus = 0;
+       unsigned char edpRev = 0;
+       enum dc_status result = DC_OK;
+
+       result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
+
+       /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
+       if (result == DC_OK && edpRev >= DP_EDP_12) {
+               do {
+                       sinkstatus = 1;
+                       result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
+                       if (sinkstatus == 0)
+                               break;
+                       if (result != DC_OK)
+                               break;
+                       udelay(100); //MAx T9
+               } while (++tries < 50);
+       }
+
+       return result;
+}
+
+bool link_edp_receiver_ready_T7(struct dc_link *link)
+{
+       unsigned char sinkstatus = 0;
+       unsigned char edpRev = 0;
+       enum dc_status result = DC_OK;
+
+       /* use absolute time stamp to constrain max T7*/
+       unsigned long long enter_timestamp = 0;
+       unsigned long long finish_timestamp = 0;
+       unsigned long long time_taken_in_ns = 0;
+
+       result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
+
+       if (result == DC_OK && edpRev >= DP_EDP_12) {
+               /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
+               enter_timestamp = dm_get_timestamp(link->ctx);
+               do {
+                       sinkstatus = 0;
+                       result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
+                       if (sinkstatus == 1)
+                               break;
+                       if (result != DC_OK)
+                               break;
+                       udelay(25);
+                       finish_timestamp = dm_get_timestamp(link->ctx);
+                       time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
+               } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms
+       }
+
+       if (link && link->panel_config.pps.extra_t7_ms > 0)
+               udelay(link->panel_config.pps.extra_t7_ms * 1000);
+
+       return result;
+}
+
+bool link_power_alpm_dpcd_enable(struct dc_link *link, bool enable)
+{
+       bool ret = false;
+       union dpcd_alpm_configuration alpm_config;
+
+       if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+               memset(&alpm_config, 0, sizeof(alpm_config));
+
+               alpm_config.bits.ENABLE = (enable ? true : false);
+               ret = dm_helpers_dp_write_dpcd(link->ctx, link,
+                               DP_RECEIVER_ALPM_CONFIG, &alpm_config.raw,
+                               sizeof(alpm_config.raw));
+       }
+       return ret;
+}
+
+static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link)
+{
+       int i;
+       struct dc *dc = link->ctx->dc;
+       struct pipe_ctx *pipe_ctx = NULL;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (dc->current_state->res_ctx.pipe_ctx[i].stream) {
+                       if (dc->current_state->res_ctx.pipe_ctx[i].stream->link == link) {
+                               pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+                               break;
+                       }
+               }
+       }
+
+       return pipe_ctx;
+}
+
+bool dc_link_set_backlight_level(const struct dc_link *link,
+               uint32_t backlight_pwm_u16_16,
+               uint32_t frame_ramp)
+{
+       struct dc  *dc = link->ctx->dc;
+
+       DC_LOGGER_INIT(link->ctx->logger);
+       DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
+                       backlight_pwm_u16_16, backlight_pwm_u16_16);
+
+       if (dc_is_embedded_signal(link->connector_signal)) {
+               struct pipe_ctx *pipe_ctx = get_pipe_from_link(link);
+
+               if (pipe_ctx) {
+                       /* Disable brightness ramping when the display is blanked
+                        * as it can hang the DMCU
+                        */
+                       if (pipe_ctx->plane_state == NULL)
+                               frame_ramp = 0;
+               } else {
+                       return false;
+               }
+
+               dc->hwss.set_backlight_level(
+                               pipe_ctx,
+                               backlight_pwm_u16_16,
+                               frame_ramp);
+       }
+       return true;
+}
+
+bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active,
+               bool wait, bool force_static, const unsigned int *power_opts)
+{
+       struct dc  *dc = link->ctx->dc;
+       struct dmcu *dmcu = dc->res_pool->dmcu;
+       struct dmub_psr *psr = dc->res_pool->psr;
+       unsigned int panel_inst;
+
+       if (psr == NULL && force_static)
+               return false;
+
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return false;
+
+       if ((allow_active != NULL) && (*allow_active == true) && (link->type == dc_connection_none)) {
+               // Don't enter PSR if panel is not connected
+               return false;
+       }
+
+       /* Set power optimization flag */
+       if (power_opts && link->psr_settings.psr_power_opt != *power_opts) {
+               link->psr_settings.psr_power_opt = *power_opts;
+
+               if (psr != NULL && link->psr_settings.psr_feature_enabled && psr->funcs->psr_set_power_opt)
+                       psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt, panel_inst);
+       }
+
+       if (psr != NULL && link->psr_settings.psr_feature_enabled &&
+                       force_static && psr->funcs->psr_force_static)
+               psr->funcs->psr_force_static(psr, panel_inst);
+
+       /* Enable or Disable PSR */
+       if (allow_active && link->psr_settings.psr_allow_active != *allow_active) {
+               link->psr_settings.psr_allow_active = *allow_active;
+
+               if (!link->psr_settings.psr_allow_active)
+                       dc_z10_restore(dc);
+
+               if (psr != NULL && link->psr_settings.psr_feature_enabled) {
+                       psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst);
+               } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) &&
+                       link->psr_settings.psr_feature_enabled)
+                       dmcu->funcs->set_psr_enable(dmcu, link->psr_settings.psr_allow_active, wait);
+               else
+                       return false;
+       }
+       return true;
+}
+
+bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state)
+{
+       struct dc  *dc = link->ctx->dc;
+       struct dmcu *dmcu = dc->res_pool->dmcu;
+       struct dmub_psr *psr = dc->res_pool->psr;
+       unsigned int panel_inst;
+
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return false;
+
+       if (psr != NULL && link->psr_settings.psr_feature_enabled)
+               psr->funcs->psr_get_state(psr, state, panel_inst);
+       else if (dmcu != NULL && link->psr_settings.psr_feature_enabled)
+               dmcu->funcs->get_psr_state(dmcu, state);
+
+       return true;
+}
+
+static inline enum physical_phy_id
+transmitter_to_phy_id(struct dc_link *link)
+{
+       struct dc_context *dc_ctx = link->ctx;
+       enum transmitter transmitter_value = link->link_enc->transmitter;
+
+       switch (transmitter_value) {
+       case TRANSMITTER_UNIPHY_A:
+               return PHYLD_0;
+       case TRANSMITTER_UNIPHY_B:
+               return PHYLD_1;
+       case TRANSMITTER_UNIPHY_C:
+               return PHYLD_2;
+       case TRANSMITTER_UNIPHY_D:
+               return PHYLD_3;
+       case TRANSMITTER_UNIPHY_E:
+               return PHYLD_4;
+       case TRANSMITTER_UNIPHY_F:
+               return PHYLD_5;
+       case TRANSMITTER_NUTMEG_CRT:
+               return PHYLD_6;
+       case TRANSMITTER_TRAVIS_CRT:
+               return PHYLD_7;
+       case TRANSMITTER_TRAVIS_LCD:
+               return PHYLD_8;
+       case TRANSMITTER_UNIPHY_G:
+               return PHYLD_9;
+       case TRANSMITTER_COUNT:
+               return PHYLD_COUNT;
+       case TRANSMITTER_UNKNOWN:
+               return PHYLD_UNKNOWN;
+       default:
+               DC_ERROR("Unknown transmitter value %d\n", transmitter_value);
+               return PHYLD_UNKNOWN;
+       }
+}
+
+bool dc_link_setup_psr(struct dc_link *link,
+               const struct dc_stream_state *stream, struct psr_config *psr_config,
+               struct psr_context *psr_context)
+{
+       struct dc *dc;
+       struct dmcu *dmcu;
+       struct dmub_psr *psr;
+       int i;
+       unsigned int panel_inst;
+       /* updateSinkPsrDpcdConfig*/
+       union dpcd_psr_configuration psr_configuration;
+       union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};
+
+       psr_context->controllerId = CONTROLLER_ID_UNDEFINED;
+
+       if (!link)
+               return false;
+
+       dc = link->ctx->dc;
+       dmcu = dc->res_pool->dmcu;
+       psr = dc->res_pool->psr;
+
+       if (!dmcu && !psr)
+               return false;
+
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return false;
+
+
+       memset(&psr_configuration, 0, sizeof(psr_configuration));
+
+       psr_configuration.bits.ENABLE                    = 1;
+       psr_configuration.bits.CRC_VERIFICATION          = 1;
+       psr_configuration.bits.FRAME_CAPTURE_INDICATION  =
+                       psr_config->psr_frame_capture_indication_req;
+
+       /* Check for PSR v2*/
+       if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+               /* For PSR v2 selective update.
+                * Indicates whether sink should start capturing
+                * immediately following active scan line,
+                * or starting with the 2nd active scan line.
+                */
+               psr_configuration.bits.LINE_CAPTURE_INDICATION = 0;
+               /*For PSR v2, determines whether Sink should generate
+                * IRQ_HPD when CRC mismatch is detected.
+                */
+               psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR    = 1;
+               /* For PSR v2, set the bit when the Source device will
+                * be enabling PSR2 operation.
+                */
+               psr_configuration.bits.ENABLE_PSR2    = 1;
+               /* For PSR v2, the Sink device must be able to receive
+                * SU region updates early in the frame time.
+                */
+               psr_configuration.bits.EARLY_TRANSPORT_ENABLE    = 1;
+       }
+
+       dm_helpers_dp_write_dpcd(
+               link->ctx,
+               link,
+               368,
+               &psr_configuration.raw,
+               sizeof(psr_configuration.raw));
+
+       if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+               link_power_alpm_dpcd_enable(link, true);
+               psr_context->su_granularity_required =
+                       psr_config->su_granularity_required;
+               psr_context->su_y_granularity =
+                       psr_config->su_y_granularity;
+               psr_context->line_time_in_us = psr_config->line_time_in_us;
+
+               /* linux must be able to expose AMD Source DPCD definition
+                * in order to support FreeSync PSR
+                */
+               if (link->psr_settings.psr_vtotal_control_support) {
+                       psr_context->rate_control_caps = psr_config->rate_control_caps;
+                       vtotal_control.bits.ENABLE = true;
+                       core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
+                                                       &vtotal_control.raw, sizeof(vtotal_control.raw));
+               }
+       }
+
+       psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
+       psr_context->transmitterId = link->link_enc->transmitter;
+       psr_context->engineId = link->link_enc->preferred_engine;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (dc->current_state->res_ctx.pipe_ctx[i].stream
+                               == stream) {
+                       /* dmcu -1 for all controller id values,
+                        * therefore +1 here
+                        */
+                       psr_context->controllerId =
+                               dc->current_state->res_ctx.
+                               pipe_ctx[i].stream_res.tg->inst + 1;
+                       break;
+               }
+       }
+
+       /* Hardcoded for now.  Can be Pcie or Uniphy (or Unknown)*/
+       psr_context->phyType = PHY_TYPE_UNIPHY;
+       /*PhyId is associated with the transmitter id*/
+       psr_context->smuPhyId = transmitter_to_phy_id(link);
+
+       psr_context->crtcTimingVerticalTotal = stream->timing.v_total;
+       psr_context->vsync_rate_hz = div64_u64(div64_u64((stream->
+                                       timing.pix_clk_100hz * 100),
+                                       stream->timing.v_total),
+                                       stream->timing.h_total);
+
+       psr_context->psrSupportedDisplayConfig = true;
+       psr_context->psrExitLinkTrainingRequired =
+               psr_config->psr_exit_link_training_required;
+       psr_context->sdpTransmitLineNumDeadline =
+               psr_config->psr_sdp_transmit_line_num_deadline;
+       psr_context->psrFrameCaptureIndicationReq =
+               psr_config->psr_frame_capture_indication_req;
+
+       psr_context->skipPsrWaitForPllLock = 0; /* only = 1 in KV */
+
+       psr_context->numberOfControllers =
+                       link->dc->res_pool->timing_generator_count;
+
+       psr_context->rfb_update_auto_en = true;
+
+       /* 2 frames before enter PSR. */
+       psr_context->timehyst_frames = 2;
+       /* half a frame
+        * (units in 100 lines, i.e. a value of 1 represents 100 lines)
+        */
+       psr_context->hyst_lines = stream->timing.v_total / 2 / 100;
+       psr_context->aux_repeats = 10;
+
+       psr_context->psr_level.u32all = 0;
+
+       /*skip power down the single pipe since it blocks the cstate*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       if (link->ctx->asic_id.chip_family >= FAMILY_RV) {
+               switch (link->ctx->asic_id.chip_family) {
+               case FAMILY_YELLOW_CARP:
+               case AMDGPU_FAMILY_GC_10_3_6:
+               case AMDGPU_FAMILY_GC_11_0_1:
+                       if (dc->debug.disable_z10 || dc->debug.psr_skip_crtc_disable)
+                               psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+                       break;
+               default:
+                       psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+                       break;
+               }
+       }
+#else
+       if (link->ctx->asic_id.chip_family >= FAMILY_RV)
+               psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+#endif
+
+       /* SMU will perform additional powerdown sequence.
+        * For unsupported ASICs, set psr_level flag to skip PSR
+        *  static screen notification to SMU.
+        *  (Always set for DAL2, did not check ASIC)
+        */
+       psr_context->allow_smu_optimizations = psr_config->allow_smu_optimizations;
+       psr_context->allow_multi_disp_optimizations = psr_config->allow_multi_disp_optimizations;
+
+       /* Complete PSR entry before aborting to prevent intermittent
+        * freezes on certain eDPs
+        */
+       psr_context->psr_level.bits.DISABLE_PSR_ENTRY_ABORT = 1;
+
+       /* Disable ALPM first for compatible non-ALPM panel now */
+       psr_context->psr_level.bits.DISABLE_ALPM = 0;
+       psr_context->psr_level.bits.ALPM_DEFAULT_PD_MODE = 1;
+
+       /* Controls additional delay after remote frame capture before
+        * continuing power down, default = 0
+        */
+       psr_context->frame_delay = 0;
+
+       psr_context->dsc_slice_height = psr_config->dsc_slice_height;
+
+       if (psr) {
+               link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr,
+                       link, psr_context, panel_inst);
+               link->psr_settings.psr_power_opt = 0;
+               link->psr_settings.psr_allow_active = 0;
+       } else {
+               link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context);
+       }
+
+       /* psr_enabled == 0 indicates setup_psr did not succeed, but this
+        * should not happen since firmware should be running at this point
+        */
+       if (link->psr_settings.psr_feature_enabled == 0)
+               ASSERT(0);
+
+       return true;
+
+}
+
+void link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
+{
+       struct dc  *dc = link->ctx->dc;
+       struct dmub_psr *psr = dc->res_pool->psr;
+       unsigned int panel_inst;
+
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return;
+
+       // PSR residency measurements only supported on DMCUB
+       if (psr != NULL && link->psr_settings.psr_feature_enabled)
+               psr->funcs->psr_get_residency(psr, residency, panel_inst);
+       else
+               *residency = 0;
+}
+bool link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
+{
+       struct dc *dc = link->ctx->dc;
+       struct dmub_psr *psr = dc->res_pool->psr;
+
+       if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
+               return false;
+
+       psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);
+
+       return true;
+}
+
+static struct abm *get_abm_from_stream_res(const struct dc_link *link)
+{
+       int i;
+       struct dc *dc = link->ctx->dc;
+       struct abm *abm = NULL;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
+               struct dc_stream_state *stream = pipe_ctx.stream;
+
+               if (stream && stream->link == link) {
+                       abm = pipe_ctx.stream_res.abm;
+                       break;
+               }
+       }
+       return abm;
+}
+
+int dc_link_get_backlight_level(const struct dc_link *link)
+{
+       struct abm *abm = get_abm_from_stream_res(link);
+       struct panel_cntl *panel_cntl = link->panel_cntl;
+       struct dc  *dc = link->ctx->dc;
+       struct dmcu *dmcu = dc->res_pool->dmcu;
+       bool fw_set_brightness = true;
+
+       if (dmcu)
+               fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
+
+       if (!fw_set_brightness && panel_cntl->funcs->get_current_backlight)
+               return panel_cntl->funcs->get_current_backlight(panel_cntl);
+       else if (abm != NULL && abm->funcs->get_current_backlight != NULL)
+               return (int) abm->funcs->get_current_backlight(abm);
+       else
+               return DC_ERROR_UNEXPECTED;
+}
+
+int dc_link_get_target_backlight_pwm(const struct dc_link *link)
+{
+       struct abm *abm = get_abm_from_stream_res(link);
+
+       if (abm == NULL || abm->funcs->get_target_backlight == NULL)
+               return DC_ERROR_UNEXPECTED;
+
+       return (int) abm->funcs->get_target_backlight(abm);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
new file mode 100644 (file)
index 0000000..7f91a56
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_EDP_PANEL_CONTROL_H__
+#define __DC_LINK_EDP_PANEL_CONTROL_H__
+#include "link.h"
+
+enum dp_panel_mode dp_get_panel_mode(struct dc_link *link);
+void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
+bool set_default_brightness_aux(struct dc_link *link);
+#endif /* __DC_LINK_EDP_POWER_CONTROL_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c
new file mode 100644 (file)
index 0000000..5f39dfe
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This file implements functions that manage basic HPD components such as gpio.
+ * It also provides wrapper functions to execute HPD related programming. This
+ * file only manages basic HPD functionality. It doesn't manage detection or
+ * feature or signal specific HPD behaviors.
+ */
+#include "link_hpd.h"
+#include "gpio_service_interface.h"
+
+bool dc_link_get_hpd_state(struct dc_link *dc_link)
+{
+       uint32_t state;
+
+       dal_gpio_lock_pin(dc_link->hpd_gpio);
+       dal_gpio_get_value(dc_link->hpd_gpio, &state);
+       dal_gpio_unlock_pin(dc_link->hpd_gpio);
+
+       return state;
+}
+
+void dc_link_enable_hpd(const struct dc_link *link)
+{
+       struct link_encoder *encoder = link->link_enc;
+
+       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
+               encoder->funcs->enable_hpd(encoder);
+}
+
+void dc_link_disable_hpd(const struct dc_link *link)
+{
+       struct link_encoder *encoder = link->link_enc;
+
+       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
+               encoder->funcs->disable_hpd(encoder);
+}
+
+void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
+{
+       struct gpio *hpd;
+
+       if (enable) {
+               link->is_hpd_filter_disabled = false;
+               program_hpd_filter(link);
+       } else {
+               link->is_hpd_filter_disabled = true;
+               /* Obtain HPD handle */
+               hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+
+               if (!hpd)
+                       return;
+
+               /* Setup HPD filtering */
+               if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
+                       struct gpio_hpd_config config;
+
+                       config.delay_on_connect = 0;
+                       config.delay_on_disconnect = 0;
+
+                       dal_irq_setup_hpd_filter(hpd, &config);
+
+                       dal_gpio_close(hpd);
+               } else {
+                       ASSERT_CRITICAL(false);
+               }
+               /* Release HPD handle */
+               dal_gpio_destroy_irq(&hpd);
+       }
+}
+
+struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
+                         struct graphics_object_id link_id,
+                         struct gpio_service *gpio_service)
+{
+       enum bp_result bp_result;
+       struct graphics_object_hpd_info hpd_info;
+       struct gpio_pin_info pin_info;
+
+       if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
+               return NULL;
+
+       bp_result = dcb->funcs->get_gpio_pin_info(dcb,
+               hpd_info.hpd_int_gpio_uid, &pin_info);
+
+       if (bp_result != BP_RESULT_OK) {
+               ASSERT(bp_result == BP_RESULT_NORECORD);
+               return NULL;
+       }
+
+       return dal_gpio_service_create_irq(gpio_service,
+                                          pin_info.offset,
+                                          pin_info.mask);
+}
+
+bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high)
+{
+       struct gpio *hpd_pin = link_get_hpd_gpio(
+                       link->ctx->dc_bios, link->link_id,
+                       link->ctx->gpio_service);
+       if (!hpd_pin)
+               return false;
+
+       dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
+       dal_gpio_get_value(hpd_pin, is_hpd_high);
+       dal_gpio_close(hpd_pin);
+       dal_gpio_destroy_irq(&hpd_pin);
+       return true;
+}
+
+enum hpd_source_id get_hpd_line(struct dc_link *link)
+{
+       struct gpio *hpd;
+       enum hpd_source_id hpd_id;
+
+               hpd_id = HPD_SOURCEID_UNKNOWN;
+
+       hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+                          link->ctx->gpio_service);
+
+       if (hpd) {
+               switch (dal_irq_get_source(hpd)) {
+               case DC_IRQ_SOURCE_HPD1:
+                       hpd_id = HPD_SOURCEID1;
+               break;
+               case DC_IRQ_SOURCE_HPD2:
+                       hpd_id = HPD_SOURCEID2;
+               break;
+               case DC_IRQ_SOURCE_HPD3:
+                       hpd_id = HPD_SOURCEID3;
+               break;
+               case DC_IRQ_SOURCE_HPD4:
+                       hpd_id = HPD_SOURCEID4;
+               break;
+               case DC_IRQ_SOURCE_HPD5:
+                       hpd_id = HPD_SOURCEID5;
+               break;
+               case DC_IRQ_SOURCE_HPD6:
+                       hpd_id = HPD_SOURCEID6;
+               break;
+               default:
+                       BREAK_TO_DEBUGGER();
+               break;
+               }
+
+               dal_gpio_destroy_irq(&hpd);
+       }
+
+       return hpd_id;
+}
+
+bool program_hpd_filter(const struct dc_link *link)
+{
+       bool result = false;
+       struct gpio *hpd;
+       int delay_on_connect_in_ms = 0;
+       int delay_on_disconnect_in_ms = 0;
+
+       if (link->is_hpd_filter_disabled)
+               return false;
+       /* Verify feature is supported */
+       switch (link->connector_signal) {
+       case SIGNAL_TYPE_DVI_SINGLE_LINK:
+       case SIGNAL_TYPE_DVI_DUAL_LINK:
+       case SIGNAL_TYPE_HDMI_TYPE_A:
+               /* Program hpd filter */
+               delay_on_connect_in_ms = 500;
+               delay_on_disconnect_in_ms = 100;
+               break;
+       case SIGNAL_TYPE_DISPLAY_PORT:
+       case SIGNAL_TYPE_DISPLAY_PORT_MST:
+               /* Program hpd filter to allow DP signal to settle */
+               /* 500: not able to detect MST <-> SST switch as HPD is low for
+                * only 100ms on DELL U2413
+                * 0: some passive dongle still show aux mode instead of i2c
+                * 20-50: not enough to hide bouncing HPD with passive dongle.
+                * also see intermittent i2c read issues.
+                */
+               delay_on_connect_in_ms = 80;
+               delay_on_disconnect_in_ms = 0;
+               break;
+       case SIGNAL_TYPE_LVDS:
+       case SIGNAL_TYPE_EDP:
+       default:
+               /* Don't program hpd filter */
+               return false;
+       }
+
+       /* Obtain HPD handle */
+       hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+                          link->ctx->gpio_service);
+
+       if (!hpd)
+               return result;
+
+       /* Setup HPD filtering */
+       if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
+               struct gpio_hpd_config config;
+
+               config.delay_on_connect = delay_on_connect_in_ms;
+               config.delay_on_disconnect = delay_on_disconnect_in_ms;
+
+               dal_irq_setup_hpd_filter(hpd, &config);
+
+               dal_gpio_close(hpd);
+
+               result = true;
+       } else {
+               ASSERT_CRITICAL(false);
+       }
+
+       /* Release HPD handle */
+       dal_gpio_destroy_irq(&hpd);
+
+       return result;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h
new file mode 100644 (file)
index 0000000..3d122de
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_HPD_H__
+#define __DC_LINK_HPD_H__
+#include "link.h"
+
+enum hpd_source_id get_hpd_line(struct dc_link *link);
+/*
+ *  Function: program_hpd_filter
+ *
+ *  @brief
+ *     Programs HPD filter on associated HPD line to default values.
+ *
+ *  @return
+ *     true on success, false otherwise
+ */
+bool program_hpd_filter(const struct dc_link *link);
+/* Query hot plug status of USB4 DP tunnel.
+ * Returns true if HPD high.
+ */
+bool dpia_query_hpd_status(struct dc_link *link);
+bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high);
+#endif /* __DC_LINK_HPD_H__ */
index 06c553b..04df407 100644 (file)
@@ -1968,6 +1968,14 @@ struct dmub_cmd_psr_copy_settings_data {
         * Explicit padding to 2 byte boundary.
         */
        uint8_t pad3;
+       /**
+        * DSC Slice height.
+        */
+       uint16_t dsc_slice_height;
+       /**
+        * Explicit padding to 4 byte boundary.
+        */
+       uint16_t pad;
 };
 
 /**
@@ -3112,7 +3120,7 @@ struct dmub_rb_cmd_panel_cntl {
 struct dmub_cmd_lvtma_control_data {
        uint8_t uc_pwr_action; /**< LVTMA_ACTION */
        uint8_t bypass_panel_control_wait;
-       uint8_t reserved_0[2];
+       uint8_t reserved_0[2]; /**< For future use */
        uint8_t panel_inst; /**< LVTMA control instance */
        uint8_t reserved_1[3]; /**< For future use */
 };
index edf5845..91fe039 100644 (file)
@@ -41,4 +41,40 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
 void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
                struct dc_info_packet *info_packet);
 
+enum adaptive_sync_type {
+       ADAPTIVE_SYNC_TYPE_NONE                  = 0,
+       ADAPTIVE_SYNC_TYPE_DP                    = 1,
+       ADAPTIVE_SYNC_TYPE_PCON_IN_WHITELIST     = 2,
+       ADAPTIVE_SYNC_TYPE_PCON_NOT_IN_WHITELIST = 3,
+       ADAPTIVE_SYNC_TYPE_EDP                   = 4,
+};
+
+enum adaptive_sync_sdp_version {
+       AS_SDP_VER_0 = 0x0,
+       AS_SDP_VER_1 = 0x1,
+       AS_SDP_VER_2 = 0x2,
+};
+
+#define AS_DP_SDP_LENGTH (9)
+
+struct frame_duration_op {
+       bool          support;
+       unsigned char frame_duration_hex;
+};
+
+struct AS_Df_params {
+       bool   supportMode;
+       struct frame_duration_op increase;
+       struct frame_duration_op decrease;
+};
+
+void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
+               enum adaptive_sync_type asType, const struct AS_Df_params *param,
+               struct dc_info_packet *info_packet);
+
+void mod_build_adaptive_sync_infopacket_v2(const struct dc_stream_state *stream,
+               const struct AS_Df_params *param, struct dc_info_packet *info_packet);
+
+void mod_build_adaptive_sync_infopacket_v1(struct dc_info_packet *info_packet);
+
 #endif
index 6969105..a8a31d0 100644 (file)
@@ -519,3 +519,58 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
                info_packet->valid = true;
 }
 
+void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
+               enum adaptive_sync_type asType,
+               const struct AS_Df_params *param,
+               struct dc_info_packet *info_packet)
+{
+       info_packet->valid = false;
+
+       memset(info_packet, 0, sizeof(struct dc_info_packet));
+
+       switch (asType) {
+       case ADAPTIVE_SYNC_TYPE_DP:
+               if (stream != NULL)
+                       mod_build_adaptive_sync_infopacket_v2(stream, param, info_packet);
+               break;
+       case ADAPTIVE_SYNC_TYPE_PCON_IN_WHITELIST:
+               mod_build_adaptive_sync_infopacket_v1(info_packet);
+               break;
+       case ADAPTIVE_SYNC_TYPE_NONE:
+       case ADAPTIVE_SYNC_TYPE_PCON_NOT_IN_WHITELIST:
+       default:
+               break;
+       }
+}
+
+void mod_build_adaptive_sync_infopacket_v1(struct dc_info_packet *info_packet)
+{
+       info_packet->valid = true;
+       // HEADER {HB0, HB1, HB2, HB3} = {00, Type, Version, Length}
+       info_packet->hb0 = 0x00;
+       info_packet->hb1 = 0x22;
+       info_packet->hb2 = AS_SDP_VER_1;
+       info_packet->hb3 = 0x00;
+}
+
+void mod_build_adaptive_sync_infopacket_v2(const struct dc_stream_state *stream,
+               const struct AS_Df_params *param,
+               struct dc_info_packet *info_packet)
+{
+       info_packet->valid = true;
+       // HEADER {HB0, HB1, HB2, HB3} = {00, Type, Version, Length}
+       info_packet->hb0 = 0x00;
+       info_packet->hb1 = 0x22;
+       info_packet->hb2 = AS_SDP_VER_2;
+       info_packet->hb3 = AS_DP_SDP_LENGTH;
+
+       //Payload
+       info_packet->sb[0] = param->supportMode; //1: AVT; 0: FAVT
+       info_packet->sb[1] = (stream->timing.v_total & 0x00FF);
+       info_packet->sb[2] = (stream->timing.v_total & 0xFF00) >> 8;
+       //info_packet->sb[3] = 0x00; Target RR, not use fot AVT
+       info_packet->sb[4] = (param->increase.support << 6 | param->decrease.support << 7);
+       info_packet->sb[5] = param->increase.frame_duration_hex;
+       info_packet->sb[6] = param->decrease.frame_duration_hex;
+}
+
index cf4fa87..e39b133 100644 (file)
@@ -917,13 +917,14 @@ bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_s
        return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal);
 }
 
-bool psr_su_set_y_granularity(struct dc *dc, struct dc_link *link,
+bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
                              struct dc_stream_state *stream,
                              struct psr_config *config)
 {
        uint16_t pic_height;
-       uint8_t slice_height;
+       uint16_t slice_height;
 
+       config->dsc_slice_height = 0;
        if ((link->connector_signal & SIGNAL_TYPE_EDP) &&
            (!dc->caps.edp_dsc_support ||
            link->panel_config.dsc.disable_dsc_edp ||
@@ -934,6 +935,7 @@ bool psr_su_set_y_granularity(struct dc *dc, struct dc_link *link,
        pic_height = stream->timing.v_addressable +
                stream->timing.v_border_top + stream->timing.v_border_bottom;
        slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v;
+       config->dsc_slice_height = slice_height;
 
        if (slice_height) {
                if (config->su_y_granularity &&
@@ -941,8 +943,6 @@ bool psr_su_set_y_granularity(struct dc *dc, struct dc_link *link,
                        ASSERT(0);
                        return false;
                }
-
-               config->su_y_granularity = slice_height;
        }
 
        return true;
index bb16b37..1d3079e 100644 (file)
@@ -59,7 +59,7 @@ void mod_power_calc_psr_configs(struct psr_config *psr_config,
                const struct dc_stream_state *stream);
 bool mod_power_only_edp(const struct dc_state *context,
                const struct dc_stream_state *stream);
-bool psr_su_set_y_granularity(struct dc *dc, struct dc_link *link,
+bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
                              struct dc_stream_state *stream,
                              struct psr_config *config);
 #endif /* MODULES_POWER_POWER_HELPERS_H_ */
index d0cdc57..f89ce65 100644 (file)
@@ -145,6 +145,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
        MSG_MAP(SetBadMemoryPagesRetiredFlagsPerChannel,
                            PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel,   0),
        MSG_MAP(AllowGpo,                       PPSMC_MSG_SetGpoAllow,           0),
+       MSG_MAP(AllowIHHostInterrupt,           PPSMC_MSG_AllowIHHostInterrupt,       0),
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
index 5861b0a..847c10a 100644 (file)
@@ -3377,6 +3377,9 @@ void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr,
 
        mgr->payload_count--;
        mgr->next_start_slot -= payload->time_slots;
+
+       if (payload->delete)
+               drm_dp_mst_put_port_malloc(payload->port);
 }
 EXPORT_SYMBOL(drm_dp_remove_payload);
 
@@ -4335,7 +4338,6 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state,
 
        drm_dbg_atomic(mgr->dev, "[MST PORT:%p] TU %d -> 0\n", port, payload->time_slots);
        if (!payload->delete) {
-               drm_dp_mst_put_port_malloc(port);
                payload->pbn = 0;
                payload->delete = true;
                topology_state->payload_mask &= ~BIT(payload->vcpi - 1);
index c3753da..a93a387 100644 (file)
@@ -521,7 +521,7 @@ __printf(1, 2)
 void __drm_err(const char *format, ...);
 
 #if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG)
-#define __drm_dbg(fmt, ...)            ___drm_dbg(NULL, fmt, ##__VA_ARGS__)
+#define __drm_dbg(cat, fmt, ...)               ___drm_dbg(NULL, cat, fmt, ##__VA_ARGS__)
 #else
 #define __drm_dbg(cat, fmt, ...)                                       \
        _dynamic_func_call_cls(cat, fmt, ___drm_dbg,                    \