* [PATCH v3 1/6] drm/amd/display: Add DP 2.0 Audio Package Generator
2021-08-19 18:58 [PATCH v3 0/6] Add DP 2.0 SST Support Fangzhi Zuo
@ 2021-08-19 18:58 ` Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 2/6] drm/amd/display: Add DP 2.0 HPO Stream Encoder Fangzhi Zuo
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Fangzhi Zuo @ 2021-08-19 18:58 UTC (permalink / raw)
To: amd-gfx, nicholas.kazlauskas, harry.wentland; +Cc: wayne.lin, Fangzhi Zuo
HW Blocks:
+-----+
| HDA |
+-----+
|
|
HPO ===============|=============
| v
| +-----+
| | APG |
v +-----+
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
drivers/gpu/drm/amd/display/dc/dcn31/Makefile | 3 +-
.../gpu/drm/amd/display/dc/dcn31/dcn31_apg.c | 173 ++++++++++++++++++
.../gpu/drm/amd/display/dc/dcn31/dcn31_apg.h | 115 ++++++++++++
.../drm/amd/display/dc/dcn31/dcn31_resource.c | 38 ++++
4 files changed, 328 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
create mode 100644 drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
index 4bab97acb155..bc2087f6dcb2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
@@ -11,7 +11,8 @@
# Makefile for dcn31.
DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o \
- dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o
+ dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \
+ dcn31_apg.o
ifdef CONFIG_X86
CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -msse
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
new file mode 100644
index 000000000000..6bd7a0626665
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2019 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_bios_types.h"
+#include "hw_shared.h"
+#include "dcn31_apg.h"
+#include "reg_helper.h"
+
+#define DC_LOGGER \
+ apg31->base.ctx->logger
+
+#define REG(reg)\
+ (apg31->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+ apg31->apg_shift->field_name, apg31->apg_mask->field_name
+
+
+#define CTX \
+ apg31->base.ctx
+
+
+static void apg31_enable(
+ struct apg *apg)
+{
+ struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
+
+ /* Reset APG */
+ REG_UPDATE(APG_CONTROL, APG_RESET, 1);
+ REG_WAIT(APG_CONTROL,
+ APG_RESET_DONE, 1,
+ 1, 10);
+ REG_UPDATE(APG_CONTROL, APG_RESET, 0);
+ REG_WAIT(APG_CONTROL,
+ APG_RESET_DONE, 0,
+ 1, 10);
+
+ /* Enable APG */
+ REG_UPDATE(APG_CONTROL2, APG_ENABLE, 1);
+}
+
+static void apg31_disable(
+ struct apg *apg)
+{
+ struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
+
+ /* Disable APG */
+ REG_UPDATE(APG_CONTROL2, APG_ENABLE, 0);
+}
+
+static union audio_cea_channels speakers_to_channels(
+ struct audio_speaker_flags speaker_flags)
+{
+ union audio_cea_channels cea_channels = {0};
+
+ /* these are one to one */
+ cea_channels.channels.FL = speaker_flags.FL_FR;
+ cea_channels.channels.FR = speaker_flags.FL_FR;
+ cea_channels.channels.LFE = speaker_flags.LFE;
+ cea_channels.channels.FC = speaker_flags.FC;
+
+ /* if Rear Left and Right exist move RC speaker to channel 7
+ * otherwise to channel 5
+ */
+ if (speaker_flags.RL_RR) {
+ cea_channels.channels.RL_RC = speaker_flags.RL_RR;
+ cea_channels.channels.RR = speaker_flags.RL_RR;
+ cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
+ } else {
+ cea_channels.channels.RL_RC = speaker_flags.RC;
+ }
+
+ /* FRONT Left Right Center and REAR Left Right Center are exclusive */
+ if (speaker_flags.FLC_FRC) {
+ cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
+ cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
+ } else {
+ cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
+ cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
+ }
+
+ return cea_channels;
+}
+
+static void apg31_se_audio_setup(
+ struct apg *apg,
+ unsigned int az_inst,
+ struct audio_info *audio_info)
+{
+ struct dcn31_apg *apg31 = DCN31_APG_FROM_APG(apg);
+
+ uint32_t speakers = 0;
+ uint32_t channels = 0;
+
+ ASSERT(audio_info);
+ /* This should not happen.it does so we don't get BSOD*/
+ if (audio_info == NULL)
+ return;
+
+ speakers = audio_info->flags.info.ALLSPEAKERS;
+ channels = speakers_to_channels(audio_info->flags.speaker_flags).all;
+
+ /* DisplayPort only allows for one audio stream with stream ID 0 */
+ REG_UPDATE(APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, 0);
+
+ /* When running in "pair mode", pairs of audio channels have their own enable
+ * this is for really old audio drivers */
+ REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, 0xF);
+ // REG_UPDATE(APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, channels);
+
+ /* Disable forced mem power off */
+ REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0);
+
+ apg31_enable(apg);
+}
+
+static void apg31_audio_mute_control(
+ struct apg *apg,
+ bool mute)
+{
+ if (mute)
+ apg31_disable(apg);
+ else
+ apg31_enable(apg);
+}
+
+static struct apg_funcs dcn31_apg_funcs = {
+ .se_audio_setup = apg31_se_audio_setup,
+ .audio_mute_control = apg31_audio_mute_control,
+ .enable_apg = apg31_enable,
+ .disable_apg = apg31_disable,
+};
+
+void apg31_construct(struct dcn31_apg *apg31,
+ struct dc_context *ctx,
+ uint32_t inst,
+ const struct dcn31_apg_registers *apg_regs,
+ const struct dcn31_apg_shift *apg_shift,
+ const struct dcn31_apg_mask *apg_mask)
+{
+ apg31->base.ctx = ctx;
+
+ apg31->base.inst = inst;
+ apg31->base.funcs = &dcn31_apg_funcs;
+
+ apg31->regs = apg_regs;
+ apg31->apg_shift = apg_shift;
+ apg31->apg_mask = apg_mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
new file mode 100644
index 000000000000..24f568e120d8
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2020 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_DCN31_AGP_H__
+#define __DAL_DCN31_AGP_H__
+
+
+#define DCN31_APG_FROM_APG(apg)\
+ container_of(apg, struct dcn31_apg, base)
+
+#define APG_DCN31_REG_LIST(id) \
+ SRI(APG_CONTROL, APG, id), \
+ SRI(APG_CONTROL2, APG, id),\
+ SRI(APG_MEM_PWR, APG, id),\
+ SRI(APG_DBG_GEN_CONTROL, APG, id)
+
+struct dcn31_apg_registers {
+ uint32_t APG_CONTROL;
+ uint32_t APG_CONTROL2;
+ uint32_t APG_MEM_PWR;
+ uint32_t APG_DBG_GEN_CONTROL;
+};
+
+
+#define DCN31_APG_MASK_SH_LIST(mask_sh)\
+ SE_SF(APG0_APG_CONTROL, APG_RESET, mask_sh),\
+ SE_SF(APG0_APG_CONTROL, APG_RESET_DONE, mask_sh),\
+ SE_SF(APG0_APG_CONTROL2, APG_ENABLE, mask_sh),\
+ SE_SF(APG0_APG_CONTROL2, APG_DP_AUDIO_STREAM_ID, mask_sh),\
+ SE_SF(APG0_APG_DBG_GEN_CONTROL, APG_DBG_AUDIO_CHANNEL_ENABLE, mask_sh),\
+ SE_SF(APG0_APG_MEM_PWR, APG_MEM_PWR_FORCE, mask_sh)
+
+#define APG_DCN31_REG_FIELD_LIST(type) \
+ type APG_RESET;\
+ type APG_RESET_DONE;\
+ type APG_ENABLE;\
+ type APG_DP_AUDIO_STREAM_ID;\
+ type APG_DBG_AUDIO_CHANNEL_ENABLE;\
+ type APG_MEM_PWR_FORCE
+
+struct dcn31_apg_shift {
+ APG_DCN31_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn31_apg_mask {
+ APG_DCN31_REG_FIELD_LIST(uint32_t);
+};
+
+struct apg {
+ const struct apg_funcs *funcs;
+ struct dc_context *ctx;
+ int inst;
+};
+
+struct apg_funcs {
+
+ void (*setup_hdmi_audio)(
+ struct apg *apg);
+
+ void (*se_audio_setup)(
+ struct apg *apg,
+ unsigned int az_inst,
+ struct audio_info *audio_info);
+
+ void (*audio_mute_control)(
+ struct apg *apg,
+ bool mute);
+
+ void (*enable_apg)(
+ struct apg *apg);
+
+ void (*disable_apg)(
+ struct apg *apg);
+};
+
+
+
+struct dcn31_apg {
+ struct apg base;
+ const struct dcn31_apg_registers *regs;
+ const struct dcn31_apg_shift *apg_shift;
+ const struct dcn31_apg_mask *apg_mask;
+};
+
+void apg31_construct(struct dcn31_apg *apg3,
+ struct dc_context *ctx,
+ uint32_t inst,
+ const struct dcn31_apg_registers *apg_regs,
+ const struct dcn31_apg_shift *apg_shift,
+ const struct dcn31_apg_mask *apg_mask);
+
+
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index a7702d3c75cd..7355864117e6 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -52,6 +52,7 @@
#include "dcn30/dcn30_vpg.h"
#include "dcn30/dcn30_afmt.h"
#include "dcn30/dcn30_dio_stream_encoder.h"
+#include "dcn31/dcn31_apg.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dce/dce_clock_source.h"
#include "dce/dce_audio.h"
@@ -457,6 +458,26 @@ static const struct dcn30_afmt_mask afmt_mask = {
DCN3_AFMT_MASK_SH_LIST(_MASK)
};
+#define apg_regs(id)\
+[id] = {\
+ APG_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_apg_registers apg_regs[] = {
+ apg_regs(0),
+ apg_regs(1),
+ apg_regs(2),
+ apg_regs(3)
+};
+
+static const struct dcn31_apg_shift apg_shift = {
+ DCN31_APG_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_apg_mask apg_mask = {
+ DCN31_APG_MASK_SH_LIST(_MASK)
+};
+
#define stream_enc_regs(id)\
[id] = {\
SE_DCN3_REG_LIST(id)\
@@ -1260,6 +1281,23 @@ static struct afmt *dcn31_afmt_create(
return &afmt3->base;
}
+static struct apg *dcn31_apg_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL);
+
+ if (!apg31)
+ return NULL;
+
+ apg31_construct(apg31, ctx, inst,
+ &apg_regs[inst],
+ &apg_shift,
+ &apg_mask);
+
+ return &apg31->base;
+}
+
static struct stream_encoder *dcn31_stream_encoder_create(
enum engine_id eng_id,
struct dc_context *ctx)
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/6] drm/amd/display: Add DP 2.0 HPO Stream Encoder
2021-08-19 18:58 [PATCH v3 0/6] Add DP 2.0 SST Support Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 1/6] drm/amd/display: Add DP 2.0 Audio Package Generator Fangzhi Zuo
@ 2021-08-19 18:58 ` Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 3/6] drm/amd/display: Add DP 2.0 HPO Link Encoder Fangzhi Zuo
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Fangzhi Zuo @ 2021-08-19 18:58 UTC (permalink / raw)
To: amd-gfx, nicholas.kazlauskas, harry.wentland; +Cc: wayne.lin, Fangzhi Zuo
HW Blocks:
+--------+ +-----+ +------+
| OPTC | | HDA | | HUBP |
+--------+ +-----+ +------+
| | |
| | |
HPO ====|==========|========|====
| | v |
| | +-----+ |
| | | APG | |
| | +-----+ |
| | | |
v v v v
+----------------------+
| HPO Stream Encoder |
+----------------------+
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
.../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 33 +
drivers/gpu/drm/amd/display/dc/dcn31/Makefile | 2 +-
.../dc/dcn31/dcn31_hpo_dp_stream_encoder.c | 749 ++++++++++++++++++
.../dc/dcn31/dcn31_hpo_dp_stream_encoder.h | 241 ++++++
.../drm/amd/display/dc/dcn31/dcn31_resource.c | 85 ++
.../gpu/drm/amd/display/dc/inc/core_types.h | 10 +
.../gpu/drm/amd/display/dc/inc/hw/hw_shared.h | 3 +
.../amd/display/dc/inc/hw/stream_encoder.h | 81 ++
drivers/gpu/drm/amd/display/dc/inc/resource.h | 8 +
.../amd/display/include/grph_object_defs.h | 12 +
.../drm/amd/display/include/grph_object_id.h | 8 +
11 files changed, 1231 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
create mode 100644 drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index df8a7718a85f..be98f5513fe5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -466,6 +466,39 @@ void dcn10_log_hw_state(struct dc *dc,
log_mpc_crc(dc, log_ctx);
+ {
+ int hpo_dp_link_enc_count = 0;
+
+ if (pool->hpo_dp_stream_enc_count > 0) {
+ DTN_INFO("DP HPO S_ENC: Enabled OTG Format Depth Vid SDP Compressed Link\n");
+ for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
+ struct hpo_dp_stream_encoder_state hpo_dp_se_state = {0};
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc = pool->hpo_dp_stream_enc[i];
+
+ if (hpo_dp_stream_enc && hpo_dp_stream_enc->funcs->read_state) {
+ hpo_dp_stream_enc->funcs->read_state(hpo_dp_stream_enc, &hpo_dp_se_state);
+
+ DTN_INFO("[%d]: %d %d %6s %d %d %d %d %d\n",
+ hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0,
+ hpo_dp_se_state.stream_enc_enabled,
+ hpo_dp_se_state.otg_inst,
+ (hpo_dp_se_state.pixel_encoding == 0) ? "4:4:4" :
+ ((hpo_dp_se_state.pixel_encoding == 1) ? "4:2:2" :
+ (hpo_dp_se_state.pixel_encoding == 2) ? "4:2:0" : "Y-Only"),
+ (hpo_dp_se_state.component_depth == 0) ? 6 :
+ ((hpo_dp_se_state.component_depth == 1) ? 8 :
+ (hpo_dp_se_state.component_depth == 2) ? 10 : 12),
+ hpo_dp_se_state.vid_stream_enabled,
+ hpo_dp_se_state.sdp_enabled,
+ hpo_dp_se_state.compressed_format,
+ hpo_dp_se_state.mapped_to_link_enc);
+ }
+ }
+
+ DTN_INFO("\n");
+ }
+ }
+
DTN_INFO_END();
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
index bc2087f6dcb2..8b811f589524 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
@@ -12,7 +12,7 @@
DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o \
dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \
- dcn31_apg.o
+ dcn31_apg.o dcn31_hpo_dp_stream_encoder.o
ifdef CONFIG_X86
CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -msse
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
new file mode 100644
index 000000000000..bc265ee06824
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright 2019 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_bios_types.h"
+#include "dcn31_hpo_dp_stream_encoder.h"
+#include "reg_helper.h"
+#include "dc_link.h"
+
+#define DC_LOGGER \
+ enc3->base.ctx->logger
+
+#define REG(reg)\
+ (enc3->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+ enc3->hpo_se_shift->field_name, enc3->hpo_se_mask->field_name
+
+#define CTX \
+ enc3->base.ctx
+
+
+enum dp2_pixel_encoding {
+ DP_SYM32_ENC_PIXEL_ENCODING_RGB_YCBCR444,
+ DP_SYM32_ENC_PIXEL_ENCODING_YCBCR422,
+ DP_SYM32_ENC_PIXEL_ENCODING_YCBCR420,
+ DP_SYM32_ENC_PIXEL_ENCODING_Y_ONLY
+};
+
+enum dp2_uncompressed_component_depth {
+ DP_SYM32_ENC_COMPONENT_DEPTH_6BPC,
+ DP_SYM32_ENC_COMPONENT_DEPTH_8BPC,
+ DP_SYM32_ENC_COMPONENT_DEPTH_10BPC,
+ DP_SYM32_ENC_COMPONENT_DEPTH_12BPC
+};
+
+
+static void dcn31_hpo_dp_stream_enc_enable_stream(
+ struct hpo_dp_stream_encoder *enc)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Enable all clocks in the DP_STREAM_ENC */
+ REG_UPDATE(DP_STREAM_ENC_CLOCK_CONTROL,
+ DP_STREAM_ENC_CLOCK_EN, 1);
+
+ /* Assert reset to the DP_SYM32_ENC logic */
+ REG_UPDATE(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_RESET, 1);
+ /* Wait for reset to complete (to assert) */
+ REG_WAIT(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_RESET_DONE, 1,
+ 1, 10);
+
+ /* De-assert reset to the DP_SYM32_ENC logic */
+ REG_UPDATE(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_RESET, 0);
+ /* Wait for reset to de-assert */
+ REG_WAIT(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_RESET_DONE, 0,
+ 1, 10);
+
+ /* Enable idle pattern generation */
+ REG_UPDATE(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_ENABLE, 1);
+}
+
+static void dcn31_hpo_dp_stream_enc_dp_unblank(
+ struct hpo_dp_stream_encoder *enc,
+ uint32_t stream_source)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Set the input mux for video stream source */
+ REG_UPDATE(DP_STREAM_ENC_INPUT_MUX_CONTROL,
+ DP_STREAM_ENC_INPUT_MUX_PIXEL_STREAM_SOURCE_SEL, stream_source);
+
+ /* Enable video transmission in main framer */
+ REG_UPDATE(DP_SYM32_ENC_VID_STREAM_CONTROL,
+ VID_STREAM_ENABLE, 1);
+
+ /* Reset and Enable Pixel to Symbol FIFO */
+ REG_UPDATE(DP_SYM32_ENC_VID_FIFO_CONTROL,
+ PIXEL_TO_SYMBOL_FIFO_RESET, 1);
+ REG_WAIT(DP_SYM32_ENC_VID_FIFO_CONTROL,
+ PIXEL_TO_SYMBOL_FIFO_RESET_DONE, 1,
+ 1, 10);
+ REG_UPDATE(DP_SYM32_ENC_VID_FIFO_CONTROL,
+ PIXEL_TO_SYMBOL_FIFO_RESET, 0);
+ REG_WAIT(DP_SYM32_ENC_VID_FIFO_CONTROL, /* Disable Clock Ramp Adjuster FIFO */
+ PIXEL_TO_SYMBOL_FIFO_RESET_DONE, 0,
+ 1, 10);
+ REG_UPDATE(DP_SYM32_ENC_VID_FIFO_CONTROL,
+ PIXEL_TO_SYMBOL_FIFO_ENABLE, 1);
+
+ /* Reset and Enable Clock Ramp Adjuster FIFO */
+ REG_UPDATE(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_RESET, 1);
+ REG_WAIT(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_RESET_DONE, 1,
+ 1, 10);
+ REG_UPDATE(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_RESET, 0);
+ REG_WAIT(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_RESET_DONE, 0,
+ 1, 10);
+
+ /* For Debug -- Enable CRC */
+ REG_UPDATE_2(DP_SYM32_ENC_VID_CRC_CONTROL,
+ CRC_ENABLE, 1,
+ CRC_CONT_MODE_ENABLE, 1);
+
+ REG_UPDATE(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_ENABLE, 1);
+}
+
+static void dcn31_hpo_dp_stream_enc_dp_blank(
+ struct hpo_dp_stream_encoder *enc)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Disable video transmission */
+ REG_UPDATE(DP_SYM32_ENC_VID_STREAM_CONTROL,
+ VID_STREAM_ENABLE, 0);
+
+ /* Wait for video stream transmission disabled
+ * Larger delay to wait until VBLANK - use max retry of
+ * 10us*5000=50ms. This covers 41.7ms of minimum 24 Hz mode +
+ * a little more because we may not trust delay accuracy.
+ */
+ //REG_WAIT(DP_SYM32_ENC_VID_STREAM_CONTROL,
+ // VID_STREAM_STATUS, 0,
+ // 10, 5000);
+
+ /* Disable SDP tranmission */
+ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, 0);
+
+ /* Disable Pixel to Symbol FIFO */
+ REG_UPDATE(DP_SYM32_ENC_VID_FIFO_CONTROL,
+ PIXEL_TO_SYMBOL_FIFO_ENABLE, 0);
+
+ /* Disable Clock Ramp Adjuster FIFO */
+ REG_UPDATE(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_ENABLE, 0);
+}
+
+static void dcn31_hpo_dp_stream_enc_disable(
+ struct hpo_dp_stream_encoder *enc)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Disable DP_SYM32_ENC */
+ REG_UPDATE(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_ENABLE, 0);
+
+ /* Disable clocks in the DP_STREAM_ENC */
+ REG_UPDATE(DP_STREAM_ENC_CLOCK_CONTROL,
+ DP_STREAM_ENC_CLOCK_EN, 0);
+}
+
+static void dcn31_hpo_dp_stream_enc_set_stream_attribute(
+ struct hpo_dp_stream_encoder *enc,
+ struct dc_crtc_timing *crtc_timing,
+ enum dc_color_space output_color_space,
+ bool use_vsc_sdp_for_colorimetry,
+ bool compressed_format,
+ bool double_buffer_en)
+{
+ enum dp2_pixel_encoding pixel_encoding;
+ enum dp2_uncompressed_component_depth component_depth;
+ uint32_t h_active_start;
+ uint32_t v_active_start;
+ uint32_t h_blank;
+ uint32_t h_back_porch;
+ uint32_t h_width;
+ uint32_t v_height;
+ unsigned long long v_freq;
+ uint8_t misc0 = 0;
+ uint8_t misc1 = 0;
+ uint8_t hsp;
+ uint8_t vsp;
+
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+ struct dc_crtc_timing hw_crtc_timing = *crtc_timing;
+
+ /* MISC0[0] = 0 video and link clocks are asynchronous
+ * MISC1[0] = 0 interlace not supported
+ * MISC1[2:1] = 0 stereo field is handled by hardware
+ * MISC1[5:3] = 0 Reserved
+ */
+
+ /* Interlaced not supported */
+ if (hw_crtc_timing.flags.INTERLACE) {
+ BREAK_TO_DEBUGGER();
+ }
+
+ /* Double buffer enable for MSA and pixel format registers
+ * Only double buffer for changing stream attributes for active streams
+ * Do not double buffer when initially enabling a stream
+ */
+ REG_UPDATE(DP_SYM32_ENC_VID_MSA_DOUBLE_BUFFER_CONTROL,
+ MSA_DOUBLE_BUFFER_ENABLE, double_buffer_en);
+ REG_UPDATE(DP_SYM32_ENC_VID_PIXEL_FORMAT_DOUBLE_BUFFER_CONTROL,
+ PIXEL_FORMAT_DOUBLE_BUFFER_ENABLE, double_buffer_en);
+
+ /* Pixel Encoding */
+ switch (hw_crtc_timing.pixel_encoding) {
+ case PIXEL_ENCODING_YCBCR422:
+ pixel_encoding = DP_SYM32_ENC_PIXEL_ENCODING_YCBCR422;
+ misc0 = misc0 | 0x2; // MISC0[2:1] = 01
+ break;
+ case PIXEL_ENCODING_YCBCR444:
+ pixel_encoding = DP_SYM32_ENC_PIXEL_ENCODING_RGB_YCBCR444;
+ misc0 = misc0 | 0x4; // MISC0[2:1] = 10
+
+ if (hw_crtc_timing.flags.Y_ONLY) {
+ pixel_encoding = DP_SYM32_ENC_PIXEL_ENCODING_Y_ONLY;
+ if (hw_crtc_timing.display_color_depth != COLOR_DEPTH_666) {
+ /* HW testing only, no use case yet.
+ * Color depth of Y-only could be
+ * 8, 10, 12, 16 bits
+ */
+ misc1 = misc1 | 0x80; // MISC1[7] = 1
+ }
+ }
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ pixel_encoding = DP_SYM32_ENC_PIXEL_ENCODING_YCBCR420;
+ misc1 = misc1 | 0x40; // MISC1[6] = 1
+ break;
+ case PIXEL_ENCODING_RGB:
+ default:
+ pixel_encoding = DP_SYM32_ENC_PIXEL_ENCODING_RGB_YCBCR444;
+ break;
+ }
+
+ /* For YCbCr420 and BT2020 Colorimetry Formats, VSC SDP shall be used.
+ * When MISC1, bit 6, is Set to 1, a Source device uses a VSC SDP to indicate the
+ * Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7,
+ * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care").
+ */
+ if (use_vsc_sdp_for_colorimetry)
+ misc1 = misc1 | 0x40;
+ else
+ misc1 = misc1 & ~0x40;
+
+ /* Color depth */
+ switch (hw_crtc_timing.display_color_depth) {
+ case COLOR_DEPTH_666:
+ component_depth = DP_SYM32_ENC_COMPONENT_DEPTH_6BPC;
+ // MISC0[7:5] = 000
+ break;
+ case COLOR_DEPTH_888:
+ component_depth = DP_SYM32_ENC_COMPONENT_DEPTH_8BPC;
+ misc0 = misc0 | 0x20; // MISC0[7:5] = 001
+ break;
+ case COLOR_DEPTH_101010:
+ component_depth = DP_SYM32_ENC_COMPONENT_DEPTH_10BPC;
+ misc0 = misc0 | 0x40; // MISC0[7:5] = 010
+ break;
+ case COLOR_DEPTH_121212:
+ component_depth = DP_SYM32_ENC_COMPONENT_DEPTH_12BPC;
+ misc0 = misc0 | 0x60; // MISC0[7:5] = 011
+ break;
+ default:
+ component_depth = DP_SYM32_ENC_COMPONENT_DEPTH_6BPC;
+ break;
+ }
+
+ REG_UPDATE_3(DP_SYM32_ENC_VID_PIXEL_FORMAT,
+ PIXEL_ENCODING_TYPE, compressed_format,
+ UNCOMPRESSED_PIXEL_ENCODING, pixel_encoding,
+ UNCOMPRESSED_COMPONENT_DEPTH, component_depth);
+
+ switch (output_color_space) {
+ case COLOR_SPACE_SRGB:
+ misc1 = misc1 & ~0x80; /* bit7 = 0*/
+ break;
+ case COLOR_SPACE_SRGB_LIMITED:
+ misc0 = misc0 | 0x8; /* bit3=1 */
+ misc1 = misc1 & ~0x80; /* bit7 = 0*/
+ break;
+ case COLOR_SPACE_YCBCR601:
+ case COLOR_SPACE_YCBCR601_LIMITED:
+ misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */
+ misc1 = misc1 & ~0x80; /* bit7 = 0*/
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
+ break;
+ case COLOR_SPACE_YCBCR709:
+ case COLOR_SPACE_YCBCR709_LIMITED:
+ misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */
+ misc1 = misc1 & ~0x80; /* bit7 = 0*/
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
+ break;
+ case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
+ case COLOR_SPACE_2020_RGB_FULLRANGE:
+ case COLOR_SPACE_2020_YCBCR:
+ case COLOR_SPACE_XR_RGB:
+ case COLOR_SPACE_MSREF_SCRGB:
+ case COLOR_SPACE_ADOBERGB:
+ case COLOR_SPACE_DCIP3:
+ case COLOR_SPACE_XV_YCC_709:
+ case COLOR_SPACE_XV_YCC_601:
+ case COLOR_SPACE_DISPLAYNATIVE:
+ case COLOR_SPACE_DOLBYVISION:
+ case COLOR_SPACE_APPCTRL:
+ case COLOR_SPACE_CUSTOMPOINTS:
+ case COLOR_SPACE_UNKNOWN:
+ case COLOR_SPACE_YCBCR709_BLACK:
+ /* do nothing */
+ break;
+ }
+
+ /* calculate from vesa timing parameters
+ * h_active_start related to leading edge of sync
+ */
+ h_blank = hw_crtc_timing.h_total - hw_crtc_timing.h_border_left -
+ hw_crtc_timing.h_addressable - hw_crtc_timing.h_border_right;
+
+ h_back_porch = h_blank - hw_crtc_timing.h_front_porch -
+ hw_crtc_timing.h_sync_width;
+
+ /* start at beginning of left border */
+ h_active_start = hw_crtc_timing.h_sync_width + h_back_porch;
+
+ v_active_start = hw_crtc_timing.v_total - hw_crtc_timing.v_border_top -
+ hw_crtc_timing.v_addressable - hw_crtc_timing.v_border_bottom -
+ hw_crtc_timing.v_front_porch;
+
+ h_width = hw_crtc_timing.h_border_left + hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right;
+ v_height = hw_crtc_timing.v_border_top + hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom;
+ hsp = hw_crtc_timing.flags.HSYNC_POSITIVE_POLARITY ? 0x80 : 0;
+ vsp = hw_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? 0x80 : 0;
+ v_freq = hw_crtc_timing.pix_clk_100hz * 100;
+
+ /* MSA Packet Mapping to 32-bit Link Symbols - DP2 spec, section 2.7.4.1
+ *
+ * Lane 0 Lane 1 Lane 2 Lane 3
+ * MSA[0] = { 0, 0, 0, VFREQ[47:40]}
+ * MSA[1] = { 0, 0, 0, VFREQ[39:32]}
+ * MSA[2] = { 0, 0, 0, VFREQ[31:24]}
+ * MSA[3] = { HTotal[15:8], HStart[15:8], HWidth[15:8], VFREQ[23:16]}
+ * MSA[4] = { HTotal[ 7:0], HStart[ 7:0], HWidth[ 7:0], VFREQ[15: 8]}
+ * MSA[5] = { VTotal[15:8], VStart[15:8], VHeight[15:8], VFREQ[ 7: 0]}
+ * MSA[6] = { VTotal[ 7:0], VStart[ 7:0], VHeight[ 7:0], MISC0[ 7: 0]}
+ * MSA[7] = { HSP|HSW[14:8], VSP|VSW[14:8], 0, MISC1[ 7: 0]}
+ * MSA[8] = { HSW[ 7:0], VSW[ 7:0], 0, 0}
+ */
+ REG_SET_4(DP_SYM32_ENC_VID_MSA0, 0,
+ MSA_DATA_LANE_0, 0,
+ MSA_DATA_LANE_1, 0,
+ MSA_DATA_LANE_2, 0,
+ MSA_DATA_LANE_3, v_freq >> 40);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA1, 0,
+ MSA_DATA_LANE_0, 0,
+ MSA_DATA_LANE_1, 0,
+ MSA_DATA_LANE_2, 0,
+ MSA_DATA_LANE_3, (v_freq >> 32) & 0xff);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA2, 0,
+ MSA_DATA_LANE_0, 0,
+ MSA_DATA_LANE_1, 0,
+ MSA_DATA_LANE_2, 0,
+ MSA_DATA_LANE_3, (v_freq >> 24) & 0xff);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA3, 0,
+ MSA_DATA_LANE_0, hw_crtc_timing.h_total >> 8,
+ MSA_DATA_LANE_1, h_active_start >> 8,
+ MSA_DATA_LANE_2, h_width >> 8,
+ MSA_DATA_LANE_3, (v_freq >> 16) & 0xff);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA4, 0,
+ MSA_DATA_LANE_0, hw_crtc_timing.h_total & 0xff,
+ MSA_DATA_LANE_1, h_active_start & 0xff,
+ MSA_DATA_LANE_2, h_width & 0xff,
+ MSA_DATA_LANE_3, (v_freq >> 8) & 0xff);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA5, 0,
+ MSA_DATA_LANE_0, hw_crtc_timing.v_total >> 8,
+ MSA_DATA_LANE_1, v_active_start >> 8,
+ MSA_DATA_LANE_2, v_height >> 8,
+ MSA_DATA_LANE_3, v_freq & 0xff);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA6, 0,
+ MSA_DATA_LANE_0, hw_crtc_timing.v_total & 0xff,
+ MSA_DATA_LANE_1, v_active_start & 0xff,
+ MSA_DATA_LANE_2, v_height & 0xff,
+ MSA_DATA_LANE_3, misc0);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA7, 0,
+ MSA_DATA_LANE_0, hsp | (hw_crtc_timing.h_sync_width >> 8),
+ MSA_DATA_LANE_1, vsp | (hw_crtc_timing.v_sync_width >> 8),
+ MSA_DATA_LANE_2, 0,
+ MSA_DATA_LANE_3, misc1);
+
+ REG_SET_4(DP_SYM32_ENC_VID_MSA8, 0,
+ MSA_DATA_LANE_0, hw_crtc_timing.h_sync_width & 0xff,
+ MSA_DATA_LANE_1, hw_crtc_timing.v_sync_width & 0xff,
+ MSA_DATA_LANE_2, 0,
+ MSA_DATA_LANE_3, 0);
+}
+
+static void dcn31_hpo_dp_stream_enc_update_dp_info_packets(
+ struct hpo_dp_stream_encoder *enc,
+ const struct encoder_info_frame *info_frame)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+ uint32_t dmdata_packet_enabled = 0;
+ bool sdp_stream_enable = false;
+
+ if (info_frame->vsc.valid) {
+ enc->vpg->funcs->update_generic_info_packet(
+ enc->vpg,
+ 0, /* packetIndex */
+ &info_frame->vsc);
+ sdp_stream_enable = true;
+ }
+ if (info_frame->spd.valid) {
+ enc->vpg->funcs->update_generic_info_packet(
+ enc->vpg,
+ 2, /* packetIndex */
+ &info_frame->spd);
+ sdp_stream_enable = true;
+ }
+ if (info_frame->hdrsmd.valid) {
+ enc->vpg->funcs->update_generic_info_packet(
+ enc->vpg,
+ 3, /* packetIndex */
+ &info_frame->hdrsmd);
+ sdp_stream_enable = 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);
+
+ /* check if dynamic metadata packet transmission is enabled */
+ REG_GET(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL,
+ METADATA_PACKET_ENABLE, &dmdata_packet_enabled);
+
+ /* Enable secondary data path */
+ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, 1);
+}
+
+static void dcn31_hpo_dp_stream_enc_stop_dp_info_packets(
+ struct hpo_dp_stream_encoder *enc)
+{
+ /* stop generic packets on DP */
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+ uint32_t asp_enable = 0;
+ uint32_t atp_enable = 0;
+ uint32_t aip_enable = 0;
+ uint32_t acm_enable = 0;
+
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, 0);
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL2, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, 0);
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL3, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, 0);
+
+ /* Disable secondary data path if audio is also disabled */
+ REG_GET_4(DP_SYM32_ENC_SDP_AUDIO_CONTROL0,
+ ASP_ENABLE, &asp_enable,
+ ATP_ENABLE, &atp_enable,
+ AIP_ENABLE, &aip_enable,
+ ACM_ENABLE, &acm_enable);
+ if (!(asp_enable || atp_enable || aip_enable || acm_enable))
+ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, 0);
+}
+
+static uint32_t hpo_dp_is_gsp_enabled(
+ struct hpo_dp_stream_encoder *enc)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+ uint32_t gsp0_enabled = 0;
+ uint32_t gsp2_enabled = 0;
+ uint32_t gsp3_enabled = 0;
+ uint32_t gsp11_enabled = 0;
+
+ REG_GET(DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, &gsp0_enabled);
+ REG_GET(DP_SYM32_ENC_SDP_GSP_CONTROL2, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, &gsp2_enabled);
+ REG_GET(DP_SYM32_ENC_SDP_GSP_CONTROL3, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, &gsp3_enabled);
+ REG_GET(DP_SYM32_ENC_SDP_GSP_CONTROL11, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, &gsp11_enabled);
+
+ return (gsp0_enabled || gsp2_enabled || gsp3_enabled || gsp11_enabled);
+}
+
+static void dcn31_hpo_dp_stream_enc_set_dsc_pps_info_packet(
+ struct hpo_dp_stream_encoder *enc,
+ bool enable,
+ uint8_t *dsc_packed_pps)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ if (enable) {
+ struct dc_info_packet pps_sdp;
+ int i;
+
+ /* Configure for PPS packet size (128 bytes) */
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL11,
+ GSP_PAYLOAD_SIZE, 3);
+
+ /* Load PPS into infoframe (SDP) registers */
+ pps_sdp.valid = true;
+ pps_sdp.hb0 = 0;
+ pps_sdp.hb1 = DC_DP_INFOFRAME_TYPE_PPS;
+ pps_sdp.hb2 = 127;
+ pps_sdp.hb3 = 0;
+
+ for (i = 0; i < 4; i++) {
+ memcpy(pps_sdp.sb, &dsc_packed_pps[i * 32], 32);
+ enc3->base.vpg->funcs->update_generic_info_packet(
+ enc3->base.vpg,
+ 11 + i,
+ &pps_sdp);
+ }
+
+ /* SW should make sure VBID[6] update line number is bigger
+ * than PPS transmit line number
+ */
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL11,
+ GSP_TRANSMISSION_LINE_NUMBER, 2);
+
+ REG_UPDATE_2(DP_SYM32_ENC_VID_VBID_CONTROL,
+ VBID_6_COMPRESSEDSTREAM_FLAG_SOF_REFERENCE, 0,
+ VBID_6_COMPRESSEDSTREAM_FLAG_LINE_NUMBER, 3);
+
+ /* Send PPS data at the line number specified above. */
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL11,
+ GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, 1);
+ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, 1);
+ } else {
+ /* Disable Generic Stream Packet 11 (GSP) transmission */
+ REG_UPDATE_2(DP_SYM32_ENC_SDP_GSP_CONTROL11,
+ GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, 0,
+ GSP_PAYLOAD_SIZE, 0);
+ }
+}
+
+static void dcn31_hpo_dp_stream_enc_map_stream_to_link(
+ struct hpo_dp_stream_encoder *enc,
+ uint32_t stream_enc_inst,
+ uint32_t link_enc_inst)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ ASSERT(stream_enc_inst < 4 && link_enc_inst < 2);
+
+ switch (stream_enc_inst) {
+ case 0:
+ REG_UPDATE(DP_STREAM_MAPPER_CONTROL0,
+ DP_STREAM_LINK_TARGET, link_enc_inst);
+ break;
+ case 1:
+ REG_UPDATE(DP_STREAM_MAPPER_CONTROL1,
+ DP_STREAM_LINK_TARGET, link_enc_inst);
+ break;
+ case 2:
+ REG_UPDATE(DP_STREAM_MAPPER_CONTROL2,
+ DP_STREAM_LINK_TARGET, link_enc_inst);
+ break;
+ case 3:
+ REG_UPDATE(DP_STREAM_MAPPER_CONTROL3,
+ DP_STREAM_LINK_TARGET, link_enc_inst);
+ break;
+ }
+}
+
+static void dcn31_hpo_dp_stream_enc_mute_control(
+ struct hpo_dp_stream_encoder *enc,
+ bool mute)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ ASSERT(enc->apg);
+ enc->apg->funcs->audio_mute_control(enc->apg, mute);
+}
+
+static void dcn31_hpo_dp_stream_enc_audio_setup(
+ struct hpo_dp_stream_encoder *enc,
+ unsigned int az_inst,
+ struct audio_info *info)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Set the input mux for video stream source */
+ REG_UPDATE(DP_STREAM_ENC_AUDIO_CONTROL,
+ DP_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
+
+ ASSERT(enc->apg);
+ enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
+}
+
+static void dcn31_hpo_dp_stream_enc_audio_enable(
+ struct hpo_dp_stream_encoder *enc)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Enable Audio packets */
+ REG_UPDATE(DP_SYM32_ENC_SDP_AUDIO_CONTROL0, ASP_ENABLE, 1);
+
+ /* Program the ATP and AIP next */
+ REG_UPDATE_2(DP_SYM32_ENC_SDP_AUDIO_CONTROL0,
+ ATP_ENABLE, 1,
+ AIP_ENABLE, 1);
+
+ /* Enable secondary data path */
+ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, 1);
+
+ /* Enable APG block */
+ enc->apg->funcs->enable_apg(enc->apg);
+}
+
+static void dcn31_hpo_dp_stream_enc_audio_disable(
+ struct hpo_dp_stream_encoder *enc)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ /* Disable Audio packets */
+ REG_UPDATE_4(DP_SYM32_ENC_SDP_AUDIO_CONTROL0,
+ ASP_ENABLE, 0,
+ ATP_ENABLE, 0,
+ AIP_ENABLE, 0,
+ ACM_ENABLE, 0);
+
+ /* Disable STP Stream Enable if other SDP GSP are also disabled */
+ if (!(hpo_dp_is_gsp_enabled(enc)))
+ REG_UPDATE(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, 0);
+
+ /* Disable APG block */
+ enc->apg->funcs->disable_apg(enc->apg);
+}
+
+static void dcn31_hpo_dp_stream_enc_read_state(
+ struct hpo_dp_stream_encoder *enc,
+ struct hpo_dp_stream_encoder_state *s)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ REG_GET(DP_SYM32_ENC_CONTROL,
+ DP_SYM32_ENC_ENABLE, &s->stream_enc_enabled);
+ REG_GET(DP_SYM32_ENC_VID_STREAM_CONTROL,
+ VID_STREAM_ENABLE, &s->vid_stream_enabled);
+ REG_GET(DP_STREAM_ENC_INPUT_MUX_CONTROL,
+ DP_STREAM_ENC_INPUT_MUX_PIXEL_STREAM_SOURCE_SEL, &s->otg_inst);
+
+ REG_GET_3(DP_SYM32_ENC_VID_PIXEL_FORMAT,
+ PIXEL_ENCODING_TYPE, &s->compressed_format,
+ UNCOMPRESSED_PIXEL_ENCODING, &s->pixel_encoding,
+ UNCOMPRESSED_COMPONENT_DEPTH, &s->component_depth);
+
+ REG_GET(DP_SYM32_ENC_SDP_CONTROL,
+ SDP_STREAM_ENABLE, &s->sdp_enabled);
+
+ switch (enc->inst) {
+ case 0:
+ REG_GET(DP_STREAM_MAPPER_CONTROL0,
+ DP_STREAM_LINK_TARGET, &s->mapped_to_link_enc);
+ break;
+ case 1:
+ REG_GET(DP_STREAM_MAPPER_CONTROL1,
+ DP_STREAM_LINK_TARGET, &s->mapped_to_link_enc);
+ break;
+ case 2:
+ REG_GET(DP_STREAM_MAPPER_CONTROL2,
+ DP_STREAM_LINK_TARGET, &s->mapped_to_link_enc);
+ break;
+ case 3:
+ REG_GET(DP_STREAM_MAPPER_CONTROL3,
+ DP_STREAM_LINK_TARGET, &s->mapped_to_link_enc);
+ break;
+ }
+}
+
+static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = {
+ .enable_stream = dcn31_hpo_dp_stream_enc_enable_stream,
+ .dp_unblank = dcn31_hpo_dp_stream_enc_dp_unblank,
+ .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 = 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,
+ .map_stream_to_link = dcn31_hpo_dp_stream_enc_map_stream_to_link,
+ .audio_mute_control = dcn31_hpo_dp_stream_enc_mute_control,
+ .dp_audio_setup = dcn31_hpo_dp_stream_enc_audio_setup,
+ .dp_audio_enable = dcn31_hpo_dp_stream_enc_audio_enable,
+ .dp_audio_disable = dcn31_hpo_dp_stream_enc_audio_disable,
+ .read_state = dcn31_hpo_dp_stream_enc_read_state,
+};
+
+void dcn31_hpo_dp_stream_encoder_construct(
+ struct dcn31_hpo_dp_stream_encoder *enc3,
+ struct dc_context *ctx,
+ struct dc_bios *bp,
+ uint32_t inst,
+ enum engine_id eng_id,
+ struct vpg *vpg,
+ struct apg *apg,
+ const struct dcn31_hpo_dp_stream_encoder_registers *regs,
+ const struct dcn31_hpo_dp_stream_encoder_shift *hpo_se_shift,
+ const struct dcn31_hpo_dp_stream_encoder_mask *hpo_se_mask)
+{
+ enc3->base.funcs = &dcn30_str_enc_funcs;
+ enc3->base.ctx = ctx;
+ enc3->base.inst = inst;
+ enc3->base.id = eng_id;
+ enc3->base.bp = bp;
+ enc3->base.vpg = vpg;
+ enc3->base.apg = apg;
+ enc3->regs = regs;
+ enc3->hpo_se_shift = hpo_se_shift;
+ enc3->hpo_se_mask = hpo_se_mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
new file mode 100644
index 000000000000..70b94fc25304
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2019 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_DCN31_HPO_DP_STREAM_ENCODER_H__
+#define __DAL_DCN31_HPO_DP_STREAM_ENCODER_H__
+
+#include "dcn30/dcn30_vpg.h"
+#include "dcn31/dcn31_apg.h"
+#include "stream_encoder.h"
+
+
+#define DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(hpo_dp_stream_encoder)\
+ container_of(hpo_dp_stream_encoder, struct dcn31_hpo_dp_stream_encoder, base)
+
+
+/* Define MSA_DATA_LANE_[0-3] fields to make programming easier */
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_0__SHIFT 0x0
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_1__SHIFT 0x8
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_2__SHIFT 0x10
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_3__SHIFT 0x18
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_0_MASK 0x000000FFL
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_1_MASK 0x0000FF00L
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_2_MASK 0x00FF0000L
+#define DP_SYM32_ENC_VID_MSA__MSA_DATA_LANE_3_MASK 0xFF000000L
+
+
+#define DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id) \
+ SR(DP_STREAM_MAPPER_CONTROL0),\
+ SR(DP_STREAM_MAPPER_CONTROL1),\
+ SR(DP_STREAM_MAPPER_CONTROL2),\
+ SR(DP_STREAM_MAPPER_CONTROL3),\
+ SRI(DP_STREAM_ENC_CLOCK_CONTROL, DP_STREAM_ENC, id),\
+ SRI(DP_STREAM_ENC_INPUT_MUX_CONTROL, DP_STREAM_ENC, id),\
+ SRI(DP_STREAM_ENC_AUDIO_CONTROL, DP_STREAM_ENC, id),\
+ SRI(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, DP_STREAM_ENC, id),\
+ SRI(DP_SYM32_ENC_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_PIXEL_FORMAT, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_PIXEL_FORMAT_DOUBLE_BUFFER_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA0, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA1, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA2, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA3, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA4, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA5, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA6, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA7, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA8, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_MSA_DOUBLE_BUFFER_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_FIFO_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_STREAM_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_VBID_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_GSP_CONTROL0, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_GSP_CONTROL2, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_GSP_CONTROL3, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_GSP_CONTROL5, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_GSP_CONTROL11, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_SDP_AUDIO_CONTROL0, DP_SYM32_ENC, id),\
+ SRI(DP_SYM32_ENC_VID_CRC_CONTROL, DP_SYM32_ENC, id)
+
+#define DCN3_1_HPO_DP_STREAM_ENC_REGS \
+ uint32_t DP_STREAM_MAPPER_CONTROL0;\
+ uint32_t DP_STREAM_MAPPER_CONTROL1;\
+ uint32_t DP_STREAM_MAPPER_CONTROL2;\
+ uint32_t DP_STREAM_MAPPER_CONTROL3;\
+ uint32_t DP_STREAM_ENC_CLOCK_CONTROL;\
+ uint32_t DP_STREAM_ENC_INPUT_MUX_CONTROL;\
+ uint32_t DP_STREAM_ENC_AUDIO_CONTROL;\
+ uint32_t DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0;\
+ uint32_t DP_SYM32_ENC_CONTROL;\
+ uint32_t DP_SYM32_ENC_VID_PIXEL_FORMAT;\
+ uint32_t DP_SYM32_ENC_VID_PIXEL_FORMAT_DOUBLE_BUFFER_CONTROL;\
+ uint32_t DP_SYM32_ENC_VID_MSA0;\
+ uint32_t DP_SYM32_ENC_VID_MSA1;\
+ uint32_t DP_SYM32_ENC_VID_MSA2;\
+ uint32_t DP_SYM32_ENC_VID_MSA3;\
+ uint32_t DP_SYM32_ENC_VID_MSA4;\
+ uint32_t DP_SYM32_ENC_VID_MSA5;\
+ uint32_t DP_SYM32_ENC_VID_MSA6;\
+ uint32_t DP_SYM32_ENC_VID_MSA7;\
+ uint32_t DP_SYM32_ENC_VID_MSA8;\
+ uint32_t DP_SYM32_ENC_VID_MSA_CONTROL;\
+ uint32_t DP_SYM32_ENC_VID_MSA_DOUBLE_BUFFER_CONTROL;\
+ uint32_t DP_SYM32_ENC_VID_FIFO_CONTROL;\
+ uint32_t DP_SYM32_ENC_VID_STREAM_CONTROL;\
+ uint32_t DP_SYM32_ENC_VID_VBID_CONTROL;\
+ uint32_t DP_SYM32_ENC_SDP_CONTROL;\
+ uint32_t DP_SYM32_ENC_SDP_GSP_CONTROL0;\
+ uint32_t DP_SYM32_ENC_SDP_GSP_CONTROL2;\
+ uint32_t DP_SYM32_ENC_SDP_GSP_CONTROL3;\
+ uint32_t DP_SYM32_ENC_SDP_GSP_CONTROL5;\
+ uint32_t DP_SYM32_ENC_SDP_GSP_CONTROL11;\
+ uint32_t DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL;\
+ uint32_t DP_SYM32_ENC_SDP_AUDIO_CONTROL0;\
+ uint32_t DP_SYM32_ENC_VID_CRC_CONTROL
+
+
+#define DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(mask_sh)\
+ SE_SF(DP_STREAM_MAPPER_CONTROL0, DP_STREAM_LINK_TARGET, mask_sh),\
+ SE_SF(DP_STREAM_ENC0_DP_STREAM_ENC_CLOCK_CONTROL, DP_STREAM_ENC_CLOCK_EN, mask_sh),\
+ SE_SF(DP_STREAM_ENC0_DP_STREAM_ENC_INPUT_MUX_CONTROL, DP_STREAM_ENC_INPUT_MUX_PIXEL_STREAM_SOURCE_SEL, mask_sh),\
+ SE_SF(DP_STREAM_ENC0_DP_STREAM_ENC_AUDIO_CONTROL, DP_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, mask_sh),\
+ SE_SF(DP_STREAM_ENC0_DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET, mask_sh),\
+ SE_SF(DP_STREAM_ENC0_DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE, mask_sh),\
+ SE_SF(DP_STREAM_ENC0_DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_CONTROL, DP_SYM32_ENC_RESET, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_CONTROL, DP_SYM32_ENC_RESET_DONE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_CONTROL, DP_SYM32_ENC_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_PIXEL_FORMAT, PIXEL_ENCODING_TYPE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_PIXEL_FORMAT, UNCOMPRESSED_PIXEL_ENCODING, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_PIXEL_FORMAT, UNCOMPRESSED_COMPONENT_DEPTH, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_PIXEL_FORMAT_DOUBLE_BUFFER_CONTROL, PIXEL_FORMAT_DOUBLE_BUFFER_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_MSA_DOUBLE_BUFFER_CONTROL, MSA_DOUBLE_BUFFER_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC_VID_MSA, MSA_DATA_LANE_0, mask_sh),\
+ SE_SF(DP_SYM32_ENC_VID_MSA, MSA_DATA_LANE_1, mask_sh),\
+ SE_SF(DP_SYM32_ENC_VID_MSA, MSA_DATA_LANE_2, mask_sh),\
+ SE_SF(DP_SYM32_ENC_VID_MSA, MSA_DATA_LANE_3, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_FIFO_CONTROL, PIXEL_TO_SYMBOL_FIFO_RESET, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_FIFO_CONTROL, PIXEL_TO_SYMBOL_FIFO_RESET_DONE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_FIFO_CONTROL, PIXEL_TO_SYMBOL_FIFO_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_STREAM_CONTROL, VID_STREAM_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_STREAM_CONTROL, VID_STREAM_STATUS, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_VBID_CONTROL, VBID_6_COMPRESSEDSTREAM_FLAG_SOF_REFERENCE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_VBID_CONTROL, VBID_6_COMPRESSEDSTREAM_FLAG_LINE_NUMBER, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_CONTROL, SDP_STREAM_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_PAYLOAD_SIZE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_TRANSMISSION_LINE_NUMBER, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_TRANSMISSION_LINE_NUMBER, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_SOF_REFERENCE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL, METADATA_PACKET_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, AUDIO_MUTE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, ASP_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, ATP_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, AIP_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_SDP_AUDIO_CONTROL0, ACM_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL, CRC_ENABLE, mask_sh),\
+ SE_SF(DP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL, CRC_CONT_MODE_ENABLE, mask_sh)
+
+
+#define DCN3_1_HPO_DP_STREAM_ENC_REG_FIELD_LIST(type) \
+ type DP_STREAM_LINK_TARGET;\
+ type DP_STREAM_ENC_CLOCK_EN;\
+ type DP_STREAM_ENC_INPUT_MUX_PIXEL_STREAM_SOURCE_SEL;\
+ type DP_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL;\
+ type FIFO_RESET;\
+ type FIFO_RESET_DONE;\
+ type FIFO_ENABLE;\
+ type DP_SYM32_ENC_RESET;\
+ type DP_SYM32_ENC_RESET_DONE;\
+ type DP_SYM32_ENC_ENABLE;\
+ type PIXEL_ENCODING_TYPE;\
+ type UNCOMPRESSED_PIXEL_ENCODING;\
+ type UNCOMPRESSED_COMPONENT_DEPTH;\
+ type PIXEL_FORMAT_DOUBLE_BUFFER_ENABLE;\
+ type MSA_DOUBLE_BUFFER_ENABLE;\
+ type MSA_DATA_LANE_0;\
+ type MSA_DATA_LANE_1;\
+ type MSA_DATA_LANE_2;\
+ type MSA_DATA_LANE_3;\
+ type PIXEL_TO_SYMBOL_FIFO_RESET;\
+ type PIXEL_TO_SYMBOL_FIFO_RESET_DONE;\
+ type PIXEL_TO_SYMBOL_FIFO_ENABLE;\
+ type VID_STREAM_ENABLE;\
+ type VID_STREAM_STATUS;\
+ type VBID_6_COMPRESSEDSTREAM_FLAG_SOF_REFERENCE;\
+ type VBID_6_COMPRESSEDSTREAM_FLAG_LINE_NUMBER;\
+ type SDP_STREAM_ENABLE;\
+ type AUDIO_MUTE;\
+ type ASP_ENABLE;\
+ type ATP_ENABLE;\
+ type AIP_ENABLE;\
+ type ACM_ENABLE;\
+ type GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE;\
+ type GSP_PAYLOAD_SIZE;\
+ type GSP_TRANSMISSION_LINE_NUMBER;\
+ type GSP_SOF_REFERENCE;\
+ type METADATA_PACKET_ENABLE;\
+ type CRC_ENABLE;\
+ type CRC_CONT_MODE_ENABLE
+
+
+struct dcn31_hpo_dp_stream_encoder_registers {
+ DCN3_1_HPO_DP_STREAM_ENC_REGS;
+};
+
+struct dcn31_hpo_dp_stream_encoder_shift {
+ DCN3_1_HPO_DP_STREAM_ENC_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn31_hpo_dp_stream_encoder_mask {
+ DCN3_1_HPO_DP_STREAM_ENC_REG_FIELD_LIST(uint32_t);
+};
+
+struct dcn31_hpo_dp_stream_encoder {
+ struct hpo_dp_stream_encoder base;
+ const struct dcn31_hpo_dp_stream_encoder_registers *regs;
+ const struct dcn31_hpo_dp_stream_encoder_shift *hpo_se_shift;
+ const struct dcn31_hpo_dp_stream_encoder_mask *hpo_se_mask;
+};
+
+
+void dcn31_hpo_dp_stream_encoder_construct(
+ struct dcn31_hpo_dp_stream_encoder *enc3,
+ struct dc_context *ctx,
+ struct dc_bios *bp,
+ uint32_t inst,
+ enum engine_id eng_id,
+ struct vpg *vpg,
+ struct apg *apg,
+ const struct dcn31_hpo_dp_stream_encoder_registers *regs,
+ const struct dcn31_hpo_dp_stream_encoder_shift *hpo_se_shift,
+ const struct dcn31_hpo_dp_stream_encoder_mask *hpo_se_mask);
+
+
+#endif // __DAL_DCN31_HPO_STREAM_ENCODER_H__
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index 7355864117e6..1994a8d3883d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -52,6 +52,7 @@
#include "dcn30/dcn30_vpg.h"
#include "dcn30/dcn30_afmt.h"
#include "dcn30/dcn30_dio_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
#include "dcn31/dcn31_apg.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dce/dce_clock_source.h"
@@ -564,6 +565,26 @@ static const struct dcn10_link_enc_mask le_mask = {
DPP_REG_LIST_DCN30(id),\
}
+#define hpo_dp_stream_encoder_reg_list(id)\
+[id] = {\
+ DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\
+}
+
+static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = {
+ hpo_dp_stream_encoder_reg_list(0),
+ hpo_dp_stream_encoder_reg_list(1),
+ hpo_dp_stream_encoder_reg_list(2),
+ hpo_dp_stream_encoder_reg_list(3),
+};
+
+static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = {
+ DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = {
+ DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK)
+};
+
static const struct dcn3_dpp_registers dpp_regs[] = {
dpp_regs(0),
dpp_regs(1),
@@ -900,6 +921,7 @@ static const struct resource_caps res_cap_dcn31 = {
.num_audio = 5,
.num_stream_encoder = 5,
.num_dig_link_enc = 5,
+ .num_hpo_dp_stream_encoder = 4,
.num_pll = 5,
.num_dwb = 1,
.num_ddc = 5,
@@ -1330,6 +1352,52 @@ static struct stream_encoder *dcn31_stream_encoder_create(
return &enc1->base;
}
+static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create(
+ enum engine_id eng_id,
+ struct dc_context *ctx)
+{
+ struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31;
+ struct vpg *vpg;
+ struct apg *apg;
+ uint32_t hpo_dp_inst;
+ uint32_t vpg_inst;
+ uint32_t apg_inst;
+
+ ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3));
+ hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0;
+
+ /* Mapping of VPG register blocks to HPO DP block instance:
+ * VPG[6] -> HPO_DP[0]
+ * VPG[7] -> HPO_DP[1]
+ * VPG[8] -> HPO_DP[2]
+ * VPG[9] -> HPO_DP[3]
+ */
+ vpg_inst = hpo_dp_inst + 6;
+
+ /* Mapping of APG register blocks to HPO DP block instance:
+ * APG[0] -> HPO_DP[0]
+ * APG[1] -> HPO_DP[1]
+ * APG[2] -> HPO_DP[2]
+ * APG[3] -> HPO_DP[3]
+ */
+ apg_inst = hpo_dp_inst;
+
+ /* allocate HPO stream encoder and create VPG sub-block */
+ hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL);
+ vpg = dcn31_vpg_create(ctx, vpg_inst);
+ apg = dcn31_apg_create(ctx, apg_inst);
+
+ if (!hpo_dp_enc31 || !vpg || !apg)
+ return NULL;
+
+ dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios,
+ hpo_dp_inst, eng_id, vpg, apg,
+ &hpo_dp_stream_enc_regs[hpo_dp_inst],
+ &hpo_dp_se_shift, &hpo_dp_se_mask);
+
+ return &hpo_dp_enc31->base;
+}
+
static struct dce_hwseq *dcn31_hwseq_create(
struct dc_context *ctx)
{
@@ -1347,6 +1415,7 @@ static const struct resource_create_funcs res_create_funcs = {
.read_dce_straps = read_dce_straps,
.create_audio = dcn31_create_audio,
.create_stream_encoder = dcn31_stream_encoder_create,
+ .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
.create_hwseq = dcn31_hwseq_create,
};
@@ -1354,6 +1423,7 @@ static const struct resource_create_funcs res_create_maximus_funcs = {
.read_dce_straps = NULL,
.create_audio = NULL,
.create_stream_encoder = NULL,
+ .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
.create_hwseq = dcn31_hwseq_create,
};
@@ -1376,6 +1446,21 @@ static void dcn31_resource_destruct(struct dcn31_resource_pool *pool)
}
}
+ for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) {
+ if (pool->base.hpo_dp_stream_enc[i] != NULL) {
+ if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) {
+ kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg));
+ pool->base.hpo_dp_stream_enc[i]->vpg = NULL;
+ }
+ if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) {
+ kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg));
+ pool->base.hpo_dp_stream_enc[i]->apg = NULL;
+ }
+ kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i]));
+ pool->base.hpo_dp_stream_enc[i] = NULL;
+ }
+ }
+
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
if (pool->base.dscs[i] != NULL)
dcn20_dsc_destroy(&pool->base.dscs[i]);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 45a6216dfa2a..19dbfc8a44bb 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -246,6 +246,10 @@ struct resource_pool {
*/
unsigned int dig_link_enc_count;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ unsigned int hpo_dp_stream_enc_count;
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc[MAX_HPO_DP2_ENCODERS];
+#endif
#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_3dlut *mpc_lut[MAX_PIPES];
struct dc_transfer_func *mpc_shaper[MAX_PIPES];
@@ -298,6 +302,9 @@ struct stream_resource {
struct display_stream_compressor *dsc;
struct timing_generator *tg;
struct stream_encoder *stream_enc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc;
+#endif
struct audio *audio;
struct pixel_clk_params pix_clk_params;
@@ -388,6 +395,9 @@ struct resource_context {
struct link_enc_assignment link_enc_assignments[MAX_PIPES];
/* List of available link encoders. Uses engine ID as encoder identifier. */
enum engine_id link_enc_avail[MAX_DIG_LINK_ENCODERS];
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ bool is_hpo_dp_stream_enc_acquired[MAX_HPO_DP2_ENCODERS];
+#endif
#if defined(CONFIG_DRM_AMD_DC_DCN)
bool is_mpc_3dlut_acquired[MAX_PIPES];
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
index 31a1713bb49f..ad9e9e2d52b0 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
@@ -38,6 +38,9 @@
#define MAX_PIPES 6
#define MAX_DIG_LINK_ENCODERS 7
#define MAX_DWB_PIPES 1
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+#define MAX_HPO_DP2_ENCODERS 4
+#endif
struct gamma_curve {
uint32_t offset;
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
index 564ea6a727b0..40a138a9593f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
@@ -242,4 +242,85 @@ struct stream_encoder_funcs {
struct stream_encoder *enc);
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+struct hpo_dp_stream_encoder_state {
+ uint32_t stream_enc_enabled;
+ uint32_t vid_stream_enabled;
+ uint32_t otg_inst;
+ uint32_t pixel_encoding;
+ uint32_t component_depth;
+ uint32_t compressed_format;
+ uint32_t sdp_enabled;
+ uint32_t mapped_to_link_enc;
+};
+
+struct hpo_dp_stream_encoder {
+ const struct hpo_dp_stream_encoder_funcs *funcs;
+ struct dc_context *ctx;
+ struct dc_bios *bp;
+ uint32_t inst;
+ enum engine_id id;
+ struct vpg *vpg;
+ struct apg *apg;
+};
+
+struct hpo_dp_stream_encoder_funcs {
+ void (*enable_stream)(
+ struct hpo_dp_stream_encoder *enc);
+
+ void (*dp_unblank)(
+ struct hpo_dp_stream_encoder *enc,
+ uint32_t stream_source);
+
+ void (*dp_blank)(
+ struct hpo_dp_stream_encoder *enc);
+
+ void (*disable)(
+ struct hpo_dp_stream_encoder *enc);
+
+ void (*set_stream_attribute)(
+ struct hpo_dp_stream_encoder *enc,
+ struct dc_crtc_timing *crtc_timing,
+ enum dc_color_space output_color_space,
+ bool use_vsc_sdp_for_colorimetry,
+ bool compressed_format,
+ bool double_buffer_en);
+
+ void (*update_dp_info_packets)(
+ struct hpo_dp_stream_encoder *enc,
+ const struct encoder_info_frame *info_frame);
+
+ void (*stop_dp_info_packets)(
+ struct hpo_dp_stream_encoder *enc);
+
+ void (*dp_set_dsc_pps_info_packet)(
+ struct hpo_dp_stream_encoder *enc,
+ bool enable,
+ uint8_t *dsc_packed_pps);
+
+ void (*map_stream_to_link)(
+ struct hpo_dp_stream_encoder *enc,
+ uint32_t stream_enc_inst,
+ uint32_t link_enc_inst);
+
+ void (*audio_mute_control)(
+ struct hpo_dp_stream_encoder *enc, bool mute);
+
+ void (*dp_audio_setup)(
+ struct hpo_dp_stream_encoder *enc,
+ unsigned int az_inst,
+ struct audio_info *info);
+
+ void (*dp_audio_enable)(
+ struct hpo_dp_stream_encoder *enc);
+
+ void (*dp_audio_disable)(
+ struct hpo_dp_stream_encoder *enc);
+
+ void (*read_state)(
+ struct hpo_dp_stream_encoder *enc,
+ struct hpo_dp_stream_encoder_state *state);
+};
+#endif
+
#endif /* STREAM_ENCODER_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index fe1e5833c96a..5a2cfc899044 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -49,6 +49,9 @@ struct resource_caps {
int num_vmid;
int num_dsc;
unsigned int num_dig_link_enc; // Total number of DIGs (digital encoders) in DIO (Display Input/Output).
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ int num_hpo_dp_stream_encoder;
+#endif
int num_mpc_3dlut;
};
@@ -68,6 +71,11 @@ struct resource_create_funcs {
struct stream_encoder *(*create_stream_encoder)(
enum engine_id eng_id, struct dc_context *ctx);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct hpo_dp_stream_encoder *(*create_hpo_dp_stream_encoder)(
+ enum engine_id eng_id, struct dc_context *ctx);
+#endif
+
struct dce_hwseq *(*create_hwseq)(
struct dc_context *ctx);
};
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_defs.h
index 58bb42ed85ca..84b299ff500a 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_defs.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_defs.h
@@ -140,6 +140,18 @@ enum sync_source {
SYNC_SOURCE_DUAL_GPU_PIN
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+enum tx_ffe_id {
+ TX_FFE0 = 0,
+ TX_FFE1,
+ TX_FFE2,
+ TX_FFE3,
+ TX_FFE_DeEmphasis_Only,
+ TX_FFE_PreShoot_Only,
+ TX_FFE_No_FFE,
+};
+#endif
+
/* connector sizes in millimeters - from BiosParserTypes.hpp */
#define CONNECTOR_SIZE_DVI 40
#define CONNECTOR_SIZE_VGA 32
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_id.h b/drivers/gpu/drm/amd/display/include/grph_object_id.h
index 33b3d755fe65..01775417cf4b 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_id.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_id.h
@@ -184,6 +184,14 @@ enum engine_id {
ENGINE_ID_DACA,
ENGINE_ID_DACB,
ENGINE_ID_VCE, /* wireless display pseudo-encoder */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ ENGINE_ID_HPO_0,
+ ENGINE_ID_HPO_1,
+ ENGINE_ID_HPO_DP_0,
+ ENGINE_ID_HPO_DP_1,
+ ENGINE_ID_HPO_DP_2,
+ ENGINE_ID_HPO_DP_3,
+#endif
ENGINE_ID_VIRTUAL,
ENGINE_ID_COUNT,
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/6] drm/amd/display: Add DP 2.0 HPO Link Encoder
2021-08-19 18:58 [PATCH v3 0/6] Add DP 2.0 SST Support Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 1/6] drm/amd/display: Add DP 2.0 Audio Package Generator Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 2/6] drm/amd/display: Add DP 2.0 HPO Stream Encoder Fangzhi Zuo
@ 2021-08-19 18:58 ` Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 4/6] drm/amd/display: Add DP 2.0 DCCG Fangzhi Zuo
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Fangzhi Zuo @ 2021-08-19 18:58 UTC (permalink / raw)
To: amd-gfx, nicholas.kazlauskas, harry.wentland; +Cc: wayne.lin, Fangzhi Zuo
HW Blocks:
+--------+ +-----+ +------+
| OPTC | | HDA | | HUBP |
+--------+ +-----+ +------+
| | |
| | |
HPO ====|==========|========|====
| | v |
| | +-----+ |
| | | APG | |
| | +-----+ |
| | | |
| v v v
| +---------------------+
| | HPO Stream Encoder |
| +---------------------+
| |
| v
| +--------------------+
| | HPO Link Encoder |
v +--------------------+
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc_link.h | 4 +
.../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 32 +
drivers/gpu/drm/amd/display/dc/dcn31/Makefile | 2 +-
.../display/dc/dcn31/dcn31_dio_link_encoder.c | 4 +
.../dc/dcn31/dcn31_hpo_dp_link_encoder.c | 620 ++++++++++++++++++
.../dc/dcn31/dcn31_hpo_dp_link_encoder.h | 222 +++++++
.../drm/amd/display/dc/dcn31/dcn31_resource.c | 50 ++
.../gpu/drm/amd/display/dc/inc/core_types.h | 2 +
.../gpu/drm/amd/display/dc/inc/hw/hw_shared.h | 1 +
.../drm/amd/display/dc/inc/hw/link_encoder.h | 87 +++
drivers/gpu/drm/amd/display/dc/inc/resource.h | 5 +
.../amd/display/include/link_service_types.h | 17 +
12 files changed, 1045 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
create mode 100644 drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 83845d006c54..4450078213a2 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -45,6 +45,10 @@ struct dc_link_status {
struct link_mst_stream_allocation {
/* DIG front */
const struct stream_encoder *stream_enc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* HPO DP Stream Encoder */
+ const struct hpo_dp_stream_encoder *hpo_dp_stream_enc;
+#endif
/* associate DRM payload table with DC stream encoder */
uint8_t vcp_id;
/* number of slots required for the DP stream in transport packet */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index be98f5513fe5..70d47773c23c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -497,6 +497,38 @@ void dcn10_log_hw_state(struct dc *dc,
DTN_INFO("\n");
}
+
+ /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */
+ for (i = 0; i < dc->link_count; i++)
+ if (dc->links[i]->hpo_dp_link_enc)
+ hpo_dp_link_enc_count++;
+
+ if (hpo_dp_link_enc_count) {
+ DTN_INFO("DP HPO L_ENC: Enabled Mode Lanes Stream Slots VC Rate X VC Rate Y\n");
+
+ for (i = 0; i < dc->link_count; i++) {
+ struct hpo_dp_link_encoder *hpo_dp_link_enc = dc->links[i]->hpo_dp_link_enc;
+ struct hpo_dp_link_enc_state hpo_dp_le_state = {0};
+
+ if (hpo_dp_link_enc && hpo_dp_link_enc->funcs->read_state) {
+ hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state);
+ DTN_INFO("[%d]: %d %6s %d %d %d %d %d\n",
+ hpo_dp_link_enc->inst,
+ hpo_dp_le_state.link_enc_enabled,
+ (hpo_dp_le_state.link_mode == 0) ? "TPS1" :
+ (hpo_dp_le_state.link_mode == 1) ? "TPS2" :
+ (hpo_dp_le_state.link_mode == 2) ? "ACTIVE" : "TEST",
+ hpo_dp_le_state.lane_count,
+ hpo_dp_le_state.stream_src[0],
+ hpo_dp_le_state.slot_count[0],
+ hpo_dp_le_state.vc_rate_x[0],
+ hpo_dp_le_state.vc_rate_y[0]);
+ DTN_INFO("\n");
+ }
+ }
+
+ DTN_INFO("\n");
+ }
}
DTN_INFO_END();
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
index 8b811f589524..5197825e7965 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
@@ -12,7 +12,7 @@
DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o \
dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \
- dcn31_apg.o dcn31_hpo_dp_stream_encoder.o
+ dcn31_apg.o dcn31_hpo_dp_stream_encoder.o dcn31_hpo_dp_link_encoder.o
ifdef CONFIG_X86
CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -msse
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
index 90127c1f9e35..77b81f6c24b9 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
@@ -320,6 +320,10 @@ void dcn31_link_encoder_construct(
enc10->base.features.flags.bits.IS_HBR3_CAPABLE =
bp_cap_info.DP_HBR3_EN;
enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
+ enc10->base.features.flags.bits.IS_DP2_CAPABLE = bp_cap_info.IS_DP2_CAPABLE;
+ enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
+ enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
+ enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.DP_IS_USB_C =
bp_cap_info.DP_IS_USB_C;
} else {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
new file mode 100644
index 000000000000..ee07a0bba12b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright 2019 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_bios_types.h"
+#include "dcn31_hpo_dp_link_encoder.h"
+#include "reg_helper.h"
+#include "dc_link.h"
+#include "stream_encoder.h"
+
+#define DC_LOGGER \
+ enc3->base.ctx->logger
+
+#define REG(reg)\
+ (enc3->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+ enc3->hpo_le_shift->field_name, enc3->hpo_le_mask->field_name
+
+
+#define CTX \
+ enc3->base.ctx
+
+enum {
+ DP_SAT_UPDATE_MAX_RETRY = 200
+};
+
+void dcn31_hpo_dp_link_enc_enable(
+ struct hpo_dp_link_encoder *enc,
+ enum dc_lane_count num_lanes)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ uint32_t dp_link_enabled;
+
+ /* get current status of link enabled */
+ REG_GET(DP_DPHY_SYM32_STATUS,
+ STATUS, &dp_link_enabled);
+
+ /* Enable clocks first */
+ REG_UPDATE(DP_LINK_ENC_CLOCK_CONTROL, DP_LINK_ENC_CLOCK_EN, 1);
+
+ /* Reset DPHY. Only reset if going from disable to enable */
+ if (!dp_link_enabled) {
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL, DPHY_RESET, 1);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL, DPHY_RESET, 0);
+ }
+
+ /* Configure DPHY settings */
+ REG_UPDATE_3(DP_DPHY_SYM32_CONTROL,
+ DPHY_ENABLE, 1,
+ PRECODER_ENABLE, 1,
+ NUM_LANES, num_lanes == LANE_COUNT_ONE ? 0 : num_lanes == LANE_COUNT_TWO ? 1 : 3);
+}
+
+void dcn31_hpo_dp_link_enc_disable(
+ struct hpo_dp_link_encoder *enc)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+
+ /* Configure DPHY settings */
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ DPHY_ENABLE, 0);
+
+ /* Shut down clock last */
+ REG_UPDATE(DP_LINK_ENC_CLOCK_CONTROL, DP_LINK_ENC_CLOCK_EN, 0);
+}
+
+void dcn31_hpo_dp_link_enc_set_link_test_pattern(
+ struct hpo_dp_link_encoder *enc,
+ struct encoder_set_dp_phy_pattern_param *tp_params)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ uint32_t tp_custom;
+
+ switch (tp_params->dp_phy_pattern) {
+ case DP_TEST_PATTERN_VIDEO_MODE:
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_LINK_ACTIVE);
+ break;
+ case DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE:
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_LINK_TRAINING_TPS1);
+ break;
+ case DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE:
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_LINK_TRAINING_TPS2);
+ break;
+ case DP_TEST_PATTERN_128b_132b_TPS1:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_TPS1,
+ TP_SELECT1, DP_DPHY_TP_SELECT_TPS1,
+ TP_SELECT2, DP_DPHY_TP_SELECT_TPS1,
+ TP_SELECT3, DP_DPHY_TP_SELECT_TPS1);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_128b_132b_TPS2:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_TPS2,
+ TP_SELECT1, DP_DPHY_TP_SELECT_TPS2,
+ TP_SELECT2, DP_DPHY_TP_SELECT_TPS2,
+ TP_SELECT3, DP_DPHY_TP_SELECT_TPS2);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_PRBS7:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_PRBS_SEL0, DP_DPHY_TP_PRBS7,
+ TP_PRBS_SEL1, DP_DPHY_TP_PRBS7,
+ TP_PRBS_SEL2, DP_DPHY_TP_PRBS7,
+ TP_PRBS_SEL3, DP_DPHY_TP_PRBS7);
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT1, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT2, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT3, DP_DPHY_TP_SELECT_PRBS);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_PRBS9:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_PRBS_SEL0, DP_DPHY_TP_PRBS9,
+ TP_PRBS_SEL1, DP_DPHY_TP_PRBS9,
+ TP_PRBS_SEL2, DP_DPHY_TP_PRBS9,
+ TP_PRBS_SEL3, DP_DPHY_TP_PRBS9);
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT1, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT2, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT3, DP_DPHY_TP_SELECT_PRBS);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_PRBS11:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_PRBS_SEL0, DP_DPHY_TP_PRBS11,
+ TP_PRBS_SEL1, DP_DPHY_TP_PRBS11,
+ TP_PRBS_SEL2, DP_DPHY_TP_PRBS11,
+ TP_PRBS_SEL3, DP_DPHY_TP_PRBS11);
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT1, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT2, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT3, DP_DPHY_TP_SELECT_PRBS);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_PRBS15:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_PRBS_SEL0, DP_DPHY_TP_PRBS15,
+ TP_PRBS_SEL1, DP_DPHY_TP_PRBS15,
+ TP_PRBS_SEL2, DP_DPHY_TP_PRBS15,
+ TP_PRBS_SEL3, DP_DPHY_TP_PRBS15);
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT1, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT2, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT3, DP_DPHY_TP_SELECT_PRBS);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_PRBS23:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_PRBS_SEL0, DP_DPHY_TP_PRBS23,
+ TP_PRBS_SEL1, DP_DPHY_TP_PRBS23,
+ TP_PRBS_SEL2, DP_DPHY_TP_PRBS23,
+ TP_PRBS_SEL3, DP_DPHY_TP_PRBS23);
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT1, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT2, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT3, DP_DPHY_TP_SELECT_PRBS);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_PRBS31:
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_PRBS_SEL0, DP_DPHY_TP_PRBS31,
+ TP_PRBS_SEL1, DP_DPHY_TP_PRBS31,
+ TP_PRBS_SEL2, DP_DPHY_TP_PRBS31,
+ TP_PRBS_SEL3, DP_DPHY_TP_PRBS31);
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT1, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT2, DP_DPHY_TP_SELECT_PRBS,
+ TP_SELECT3, DP_DPHY_TP_SELECT_PRBS);
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_264BIT_CUSTOM:
+ tp_custom = (tp_params->custom_pattern[2] << 16) | (tp_params->custom_pattern[1] << 8) | tp_params->custom_pattern[0];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM0, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[5] << 16) | (tp_params->custom_pattern[4] << 8) | tp_params->custom_pattern[3];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM1, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[8] << 16) | (tp_params->custom_pattern[7] << 8) | tp_params->custom_pattern[6];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM2, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[11] << 16) | (tp_params->custom_pattern[10] << 8) | tp_params->custom_pattern[9];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM3, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[14] << 16) | (tp_params->custom_pattern[13] << 8) | tp_params->custom_pattern[12];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM4, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[17] << 16) | (tp_params->custom_pattern[16] << 8) | tp_params->custom_pattern[15];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM5, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[20] << 16) | (tp_params->custom_pattern[19] << 8) | tp_params->custom_pattern[18];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM6, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[23] << 16) | (tp_params->custom_pattern[22] << 8) | tp_params->custom_pattern[21];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM7, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[26] << 16) | (tp_params->custom_pattern[25] << 8) | tp_params->custom_pattern[24];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM8, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[29] << 16) | (tp_params->custom_pattern[28] << 8) | tp_params->custom_pattern[27];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM9, 0, TP_CUSTOM, tp_custom);
+ tp_custom = (tp_params->custom_pattern[32] << 16) | (tp_params->custom_pattern[31] << 8) | tp_params->custom_pattern[30];
+ REG_SET(DP_DPHY_SYM32_TP_CUSTOM10, 0, TP_CUSTOM, tp_custom);
+
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_CUSTOM,
+ TP_SELECT1, DP_DPHY_TP_SELECT_CUSTOM,
+ TP_SELECT2, DP_DPHY_TP_SELECT_CUSTOM,
+ TP_SELECT3, DP_DPHY_TP_SELECT_CUSTOM);
+
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ case DP_TEST_PATTERN_SQUARE_PULSE:
+ REG_SET(DP_DPHY_SYM32_TP_SQ_PULSE, 0,
+ TP_SQ_PULSE_WIDTH, tp_params->custom_pattern[0]);
+
+ REG_UPDATE_4(DP_DPHY_SYM32_TP_CONFIG,
+ TP_SELECT0, DP_DPHY_TP_SELECT_SQUARE,
+ TP_SELECT1, DP_DPHY_TP_SELECT_SQUARE,
+ TP_SELECT2, DP_DPHY_TP_SELECT_SQUARE,
+ TP_SELECT3, DP_DPHY_TP_SELECT_SQUARE);
+
+ REG_UPDATE(DP_DPHY_SYM32_CONTROL,
+ MODE, DP2_TEST_PATTERN);
+ break;
+ default:
+ break;
+ }
+}
+
+static void fill_stream_allocation_row_info(
+ const struct link_mst_stream_allocation *stream_allocation,
+ uint32_t *src,
+ uint32_t *slots)
+{
+ const struct hpo_dp_stream_encoder *stream_enc = stream_allocation->hpo_dp_stream_enc;
+
+ if (stream_enc && (stream_enc->id >= ENGINE_ID_HPO_DP_0)) {
+ *src = stream_enc->id - ENGINE_ID_HPO_DP_0;
+ *slots = stream_allocation->slot_count;
+ } else {
+ *src = 0;
+ *slots = 0;
+ }
+}
+
+/* programs DP VC payload allocation */
+void dcn31_hpo_dp_link_enc_update_stream_allocation_table(
+ struct hpo_dp_link_encoder *enc,
+ const struct link_mst_stream_allocation_table *table)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ uint32_t value0 = 0;
+ uint32_t value1 = 0;
+ uint32_t value2 = 0;
+ uint32_t slots = 0;
+ uint32_t src = 0;
+ uint32_t retries = 0;
+
+ /* --- Set MSE Stream Attribute -
+ * Setup VC Payload Table on Tx Side,
+ * Issue allocation change trigger
+ * to commit payload on both tx and rx side
+ */
+
+ /* we should clean-up table each time */
+
+ if (table->stream_count >= 1) {
+ fill_stream_allocation_row_info(
+ &table->stream_allocations[0],
+ &src,
+ &slots);
+ } else {
+ src = 0;
+ slots = 0;
+ }
+
+ REG_UPDATE_2(DP_DPHY_SYM32_SAT_VC0,
+ SAT_STREAM_SOURCE, src,
+ SAT_SLOT_COUNT, slots);
+
+ if (table->stream_count >= 2) {
+ fill_stream_allocation_row_info(
+ &table->stream_allocations[1],
+ &src,
+ &slots);
+ } else {
+ src = 0;
+ slots = 0;
+ }
+
+ REG_UPDATE_2(DP_DPHY_SYM32_SAT_VC1,
+ SAT_STREAM_SOURCE, src,
+ SAT_SLOT_COUNT, slots);
+
+ if (table->stream_count >= 3) {
+ fill_stream_allocation_row_info(
+ &table->stream_allocations[2],
+ &src,
+ &slots);
+ } else {
+ src = 0;
+ slots = 0;
+ }
+
+ REG_UPDATE_2(DP_DPHY_SYM32_SAT_VC2,
+ SAT_STREAM_SOURCE, src,
+ SAT_SLOT_COUNT, slots);
+
+ if (table->stream_count >= 4) {
+ fill_stream_allocation_row_info(
+ &table->stream_allocations[3],
+ &src,
+ &slots);
+ } else {
+ src = 0;
+ slots = 0;
+ }
+
+ REG_UPDATE_2(DP_DPHY_SYM32_SAT_VC3,
+ SAT_STREAM_SOURCE, src,
+ SAT_SLOT_COUNT, slots);
+
+ /* --- wait for transaction finish */
+
+ /* send allocation change trigger (ACT)
+ * this step first sends the ACT,
+ * then double buffers the SAT into the hardware
+ * making the new allocation active on the DP MST mode link
+ */
+
+ /* SAT_UPDATE:
+ * 0 - No Action
+ * 1 - Update SAT with trigger
+ * 2 - Update SAT without trigger
+ */
+ REG_UPDATE(DP_DPHY_SYM32_SAT_UPDATE,
+ SAT_UPDATE, 1);
+
+ /* wait for update to complete
+ * (i.e. SAT_UPDATE_PENDING field is set to 0)
+ * No need for HW to enforce keepout.
+ */
+ /* Best case and worst case wait time for SAT_UPDATE_PENDING
+ * best: 109 us
+ * worst: 868 us
+ */
+ REG_WAIT(DP_DPHY_SYM32_STATUS,
+ SAT_UPDATE_PENDING, 0,
+ 10, DP_SAT_UPDATE_MAX_RETRY);
+}
+
+void dcn31_hpo_dp_link_enc_set_throttled_vcp_size(
+ struct hpo_dp_link_encoder *enc,
+ uint32_t stream_encoder_inst,
+ struct fixed31_32 avg_time_slots_per_mtp)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ uint32_t x = dc_fixpt_floor(
+ avg_time_slots_per_mtp);
+ uint32_t y = dc_fixpt_ceil(
+ dc_fixpt_shl(
+ dc_fixpt_sub_int(
+ avg_time_slots_per_mtp,
+ x),
+ 25));
+
+ switch (stream_encoder_inst) {
+ case 0:
+ REG_SET_2(DP_DPHY_SYM32_VC_RATE_CNTL0, 0,
+ STREAM_VC_RATE_X, x,
+ STREAM_VC_RATE_Y, y);
+ break;
+ case 1:
+ REG_SET_2(DP_DPHY_SYM32_VC_RATE_CNTL1, 0,
+ STREAM_VC_RATE_X, x,
+ STREAM_VC_RATE_Y, y);
+ break;
+ case 2:
+ REG_SET_2(DP_DPHY_SYM32_VC_RATE_CNTL2, 0,
+ STREAM_VC_RATE_X, x,
+ STREAM_VC_RATE_Y, y);
+ break;
+ case 3:
+ REG_SET_2(DP_DPHY_SYM32_VC_RATE_CNTL3, 0,
+ STREAM_VC_RATE_X, x,
+ STREAM_VC_RATE_Y, y);
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ /* Best case and worst case wait time for RATE_UPDATE_PENDING
+ * best: 116 ns
+ * worst: 903 ns
+ */
+ /* wait for update to be completed on the link */
+ REG_WAIT(DP_DPHY_SYM32_STATUS,
+ RATE_UPDATE_PENDING, 0,
+ 1, 10);
+}
+
+static bool dcn31_hpo_dp_link_enc_is_in_alt_mode(
+ struct hpo_dp_link_encoder *enc)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ uint32_t dp_alt_mode_disable = 0;
+
+ ASSERT((enc->transmitter >= TRANSMITTER_UNIPHY_A) && (enc->transmitter <= TRANSMITTER_UNIPHY_E));
+
+ /* if value == 1 alt mode is disabled, otherwise it is enabled */
+ REG_GET(RDPCSTX_PHY_CNTL6[enc->transmitter], RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable);
+ return (dp_alt_mode_disable == 0);
+}
+
+void dcn31_hpo_dp_link_enc_read_state(
+ struct hpo_dp_link_encoder *enc,
+ struct hpo_dp_link_enc_state *state)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+
+ ASSERT(state);
+
+ REG_GET(DP_DPHY_SYM32_STATUS,
+ STATUS, &state->link_enc_enabled);
+ REG_GET(DP_DPHY_SYM32_CONTROL,
+ NUM_LANES, &state->lane_count);
+ REG_GET(DP_DPHY_SYM32_CONTROL,
+ MODE, (uint32_t *)&state->link_mode);
+
+ REG_GET_2(DP_DPHY_SYM32_SAT_VC0,
+ SAT_STREAM_SOURCE, &state->stream_src[0],
+ SAT_SLOT_COUNT, &state->slot_count[0]);
+ REG_GET_2(DP_DPHY_SYM32_SAT_VC1,
+ SAT_STREAM_SOURCE, &state->stream_src[1],
+ SAT_SLOT_COUNT, &state->slot_count[1]);
+ REG_GET_2(DP_DPHY_SYM32_SAT_VC2,
+ SAT_STREAM_SOURCE, &state->stream_src[2],
+ SAT_SLOT_COUNT, &state->slot_count[2]);
+ REG_GET_2(DP_DPHY_SYM32_SAT_VC3,
+ SAT_STREAM_SOURCE, &state->stream_src[3],
+ SAT_SLOT_COUNT, &state->slot_count[3]);
+
+ REG_GET_2(DP_DPHY_SYM32_VC_RATE_CNTL0,
+ STREAM_VC_RATE_X, &state->vc_rate_x[0],
+ STREAM_VC_RATE_Y, &state->vc_rate_y[0]);
+ REG_GET_2(DP_DPHY_SYM32_VC_RATE_CNTL1,
+ STREAM_VC_RATE_X, &state->vc_rate_x[1],
+ STREAM_VC_RATE_Y, &state->vc_rate_y[1]);
+ REG_GET_2(DP_DPHY_SYM32_VC_RATE_CNTL2,
+ STREAM_VC_RATE_X, &state->vc_rate_x[2],
+ STREAM_VC_RATE_Y, &state->vc_rate_y[2]);
+ REG_GET_2(DP_DPHY_SYM32_VC_RATE_CNTL3,
+ STREAM_VC_RATE_X, &state->vc_rate_x[3],
+ STREAM_VC_RATE_Y, &state->vc_rate_y[3]);
+}
+
+static enum bp_result link_transmitter_control(
+ struct dcn31_hpo_dp_link_encoder *enc3,
+ struct bp_transmitter_control *cntl)
+{
+ enum bp_result result;
+ struct dc_bios *bp = enc3->base.ctx->dc_bios;
+
+ result = bp->funcs->transmitter_control(bp, cntl);
+
+ return result;
+}
+
+/* enables DP PHY output for 128b132b encoding */
+void dcn31_hpo_dp_link_enc_enable_dp_output(
+ struct hpo_dp_link_encoder *enc,
+ const struct dc_link_settings *link_settings,
+ enum transmitter transmitter)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ struct bp_transmitter_control cntl = { 0 };
+ enum bp_result result;
+
+ /* Set the transmitter */
+ enc3->base.transmitter = transmitter;
+
+ /* Enable the PHY */
+ cntl.action = TRANSMITTER_CONTROL_ENABLE;
+ cntl.engine_id = ENGINE_ID_UNKNOWN;
+ cntl.transmitter = enc3->base.transmitter;
+ //cntl.pll_id = clock_source;
+ cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+ cntl.lanes_number = link_settings->lane_count;
+ cntl.hpd_sel = enc3->base.hpd_source;
+ cntl.pixel_clock = link_settings->link_rate * 1000;
+ cntl.color_depth = COLOR_DEPTH_UNDEFINED;
+ cntl.hpo_engine_id = enc->inst + ENGINE_ID_HPO_DP_0;
+
+ result = link_transmitter_control(enc3, &cntl);
+
+ if (result != BP_RESULT_OK) {
+ DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",
+ __func__);
+ BREAK_TO_DEBUGGER();
+ }
+}
+
+void dcn31_hpo_dp_link_enc_disable_output(
+ struct hpo_dp_link_encoder *enc,
+ enum signal_type signal)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ struct bp_transmitter_control cntl = { 0 };
+ enum bp_result result;
+
+ /* disable transmitter */
+ cntl.action = TRANSMITTER_CONTROL_DISABLE;
+ cntl.transmitter = enc3->base.transmitter;
+ cntl.hpd_sel = enc3->base.hpd_source;
+ cntl.signal = signal;
+
+ result = link_transmitter_control(enc3, &cntl);
+
+ if (result != BP_RESULT_OK) {
+ DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",
+ __func__);
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ /* disable encoder */
+ dcn31_hpo_dp_link_enc_disable(enc);
+}
+
+void dcn31_hpo_dp_link_enc_set_ffe(
+ struct hpo_dp_link_encoder *enc,
+ const struct dc_link_settings *link_settings,
+ uint8_t ffe_preset)
+{
+ struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
+ struct bp_transmitter_control cntl = { 0 };
+ enum bp_result result;
+
+ /* disable transmitter */
+ cntl.transmitter = enc3->base.transmitter;
+ cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
+ cntl.signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+ cntl.lanes_number = link_settings->lane_count;
+ cntl.pixel_clock = link_settings->link_rate * 1000;
+ cntl.lane_settings = ffe_preset;
+
+ result = link_transmitter_control(enc3, &cntl);
+
+ if (result != BP_RESULT_OK) {
+ DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",
+ __func__);
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+}
+
+static struct hpo_dp_link_encoder_funcs dcn31_hpo_dp_link_encoder_funcs = {
+ .enable_link_phy = dcn31_hpo_dp_link_enc_enable_dp_output,
+ .disable_link_phy = dcn31_hpo_dp_link_enc_disable_output,
+ .link_enable = dcn31_hpo_dp_link_enc_enable,
+ .link_disable = dcn31_hpo_dp_link_enc_disable,
+ .set_link_test_pattern = dcn31_hpo_dp_link_enc_set_link_test_pattern,
+ .update_stream_allocation_table = dcn31_hpo_dp_link_enc_update_stream_allocation_table,
+ .set_throttled_vcp_size = dcn31_hpo_dp_link_enc_set_throttled_vcp_size,
+ .is_in_alt_mode = dcn31_hpo_dp_link_enc_is_in_alt_mode,
+ .read_state = dcn31_hpo_dp_link_enc_read_state,
+ .set_ffe = dcn31_hpo_dp_link_enc_set_ffe,
+};
+
+void hpo_dp_link_encoder31_construct(struct dcn31_hpo_dp_link_encoder *enc31,
+ struct dc_context *ctx,
+ uint32_t inst,
+ const struct dcn31_hpo_dp_link_encoder_registers *hpo_le_regs,
+ const struct dcn31_hpo_dp_link_encoder_shift *hpo_le_shift,
+ const struct dcn31_hpo_dp_link_encoder_mask *hpo_le_mask)
+{
+ enc31->base.ctx = ctx;
+
+ enc31->base.inst = inst;
+ enc31->base.funcs = &dcn31_hpo_dp_link_encoder_funcs;
+ enc31->base.hpd_source = HPD_SOURCEID_UNKNOWN;
+ enc31->base.transmitter = TRANSMITTER_UNKNOWN;
+
+ enc31->regs = hpo_le_regs;
+ enc31->hpo_le_shift = hpo_le_shift;
+ enc31->hpo_le_mask = hpo_le_mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h
new file mode 100644
index 000000000000..0706ccaf6fec
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2019 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_DCN31_HPO_DP_LINK_ENCODER_H__
+#define __DAL_DCN31_HPO_DP_LINK_ENCODER_H__
+
+#include "link_encoder.h"
+
+
+#define DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(hpo_dp_link_encoder)\
+ container_of(hpo_dp_link_encoder, struct dcn31_hpo_dp_link_encoder, base)
+
+
+#define DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id) \
+ SRI(DP_LINK_ENC_CLOCK_CONTROL, DP_LINK_ENC, id), \
+ SRI(DP_DPHY_SYM32_CONTROL, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_STATUS, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CONFIG, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_PRBS_SEED0, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_PRBS_SEED1, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_PRBS_SEED2, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_PRBS_SEED3, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_SQ_PULSE, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM0, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM1, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM2, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM3, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM4, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM5, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM6, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM7, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM8, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM9, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_TP_CUSTOM10, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_SAT_VC0, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_SAT_VC1, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_SAT_VC2, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_SAT_VC3, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_VC_RATE_CNTL0, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_VC_RATE_CNTL1, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_VC_RATE_CNTL2, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_VC_RATE_CNTL3, DP_DPHY_SYM32, id), \
+ SRI(DP_DPHY_SYM32_SAT_UPDATE, DP_DPHY_SYM32, id)
+
+#define DCN3_1_RDPCSTX_REG_LIST(id) \
+ SRII(RDPCSTX_PHY_CNTL6, RDPCSTX, id)
+
+
+#define DCN3_1_HPO_DP_LINK_ENC_REGS \
+ uint32_t DP_LINK_ENC_CLOCK_CONTROL;\
+ uint32_t DP_DPHY_SYM32_CONTROL;\
+ uint32_t DP_DPHY_SYM32_STATUS;\
+ uint32_t DP_DPHY_SYM32_TP_CONFIG;\
+ uint32_t DP_DPHY_SYM32_TP_PRBS_SEED0;\
+ uint32_t DP_DPHY_SYM32_TP_PRBS_SEED1;\
+ uint32_t DP_DPHY_SYM32_TP_PRBS_SEED2;\
+ uint32_t DP_DPHY_SYM32_TP_PRBS_SEED3;\
+ uint32_t DP_DPHY_SYM32_TP_SQ_PULSE;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM0;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM1;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM2;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM3;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM4;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM5;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM6;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM7;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM8;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM9;\
+ uint32_t DP_DPHY_SYM32_TP_CUSTOM10;\
+ uint32_t DP_DPHY_SYM32_SAT_VC0;\
+ uint32_t DP_DPHY_SYM32_SAT_VC1;\
+ uint32_t DP_DPHY_SYM32_SAT_VC2;\
+ uint32_t DP_DPHY_SYM32_SAT_VC3;\
+ uint32_t DP_DPHY_SYM32_VC_RATE_CNTL0;\
+ uint32_t DP_DPHY_SYM32_VC_RATE_CNTL1;\
+ uint32_t DP_DPHY_SYM32_VC_RATE_CNTL2;\
+ uint32_t DP_DPHY_SYM32_VC_RATE_CNTL3;\
+ uint32_t DP_DPHY_SYM32_SAT_UPDATE
+
+struct dcn31_hpo_dp_link_encoder_registers {
+ DCN3_1_HPO_DP_LINK_ENC_REGS;
+ uint32_t RDPCSTX_PHY_CNTL6[5];
+};
+
+#define DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(mask_sh)\
+ SE_SF(DP_LINK_ENC0_DP_LINK_ENC_CLOCK_CONTROL, DP_LINK_ENC_CLOCK_EN, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_CONTROL, DPHY_RESET, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_CONTROL, DPHY_ENABLE, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_CONTROL, PRECODER_ENABLE, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_CONTROL, MODE, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_CONTROL, NUM_LANES, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_STATUS, STATUS, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_STATUS, SAT_UPDATE_PENDING, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_STATUS, RATE_UPDATE_PENDING, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CUSTOM0, TP_CUSTOM, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_SELECT0, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_SELECT1, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_SELECT2, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_SELECT3, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_PRBS_SEL0, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_PRBS_SEL1, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_PRBS_SEL2, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_CONFIG, TP_PRBS_SEL3, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_TP_SQ_PULSE, TP_SQ_PULSE_WIDTH, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_SAT_VC0, SAT_STREAM_SOURCE, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_SAT_VC0, SAT_SLOT_COUNT, mask_sh),\
+ SE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_VC_RATE_CNTL0, STREAM_VC_RATE_X, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_VC_RATE_CNTL0, STREAM_VC_RATE_Y, mask_sh),\
+ SE_SF(DP_DPHY_SYM320_DP_DPHY_SYM32_SAT_UPDATE, SAT_UPDATE, mask_sh)
+
+#define DCN3_1_HPO_DP_LINK_ENC_REG_FIELD_LIST(type) \
+ type DP_LINK_ENC_CLOCK_EN;\
+ type DPHY_RESET;\
+ type DPHY_ENABLE;\
+ type PRECODER_ENABLE;\
+ type NUM_LANES;\
+ type MODE;\
+ type STATUS;\
+ type SAT_UPDATE_PENDING;\
+ type RATE_UPDATE_PENDING;\
+ type TP_CUSTOM;\
+ type TP_SELECT0;\
+ type TP_SELECT1;\
+ type TP_SELECT2;\
+ type TP_SELECT3;\
+ type TP_PRBS_SEL0;\
+ type TP_PRBS_SEL1;\
+ type TP_PRBS_SEL2;\
+ type TP_PRBS_SEL3;\
+ type TP_SQ_PULSE_WIDTH;\
+ type SAT_STREAM_SOURCE;\
+ type SAT_SLOT_COUNT;\
+ type STREAM_VC_RATE_X;\
+ type STREAM_VC_RATE_Y;\
+ type SAT_UPDATE;\
+ type RDPCS_PHY_DPALT_DISABLE
+
+
+struct dcn31_hpo_dp_link_encoder_shift {
+ DCN3_1_HPO_DP_LINK_ENC_REG_FIELD_LIST(uint8_t);
+};
+
+struct dcn31_hpo_dp_link_encoder_mask {
+ DCN3_1_HPO_DP_LINK_ENC_REG_FIELD_LIST(uint32_t);
+};
+
+struct dcn31_hpo_dp_link_encoder {
+ struct hpo_dp_link_encoder base;
+ const struct dcn31_hpo_dp_link_encoder_registers *regs;
+ const struct dcn31_hpo_dp_link_encoder_shift *hpo_le_shift;
+ const struct dcn31_hpo_dp_link_encoder_mask *hpo_le_mask;
+};
+
+void hpo_dp_link_encoder31_construct(struct dcn31_hpo_dp_link_encoder *enc31,
+ struct dc_context *ctx,
+ uint32_t inst,
+ const struct dcn31_hpo_dp_link_encoder_registers *hpo_le_regs,
+ const struct dcn31_hpo_dp_link_encoder_shift *hpo_le_shift,
+ const struct dcn31_hpo_dp_link_encoder_mask *hpo_le_mask);
+
+void dcn31_hpo_dp_link_enc_enable_dp_output(
+ struct hpo_dp_link_encoder *enc,
+ const struct dc_link_settings *link_settings,
+ enum transmitter transmitter);
+
+void dcn31_hpo_dp_link_enc_disable_output(
+ struct hpo_dp_link_encoder *enc,
+ enum signal_type signal);
+
+void dcn31_hpo_dp_link_enc_enable(
+ struct hpo_dp_link_encoder *enc,
+ enum dc_lane_count num_lanes);
+
+void dcn31_hpo_dp_link_enc_disable(
+ struct hpo_dp_link_encoder *enc);
+
+void dcn31_hpo_dp_link_enc_set_link_test_pattern(
+ struct hpo_dp_link_encoder *enc,
+ struct encoder_set_dp_phy_pattern_param *tp_params);
+
+void dcn31_hpo_dp_link_enc_update_stream_allocation_table(
+ struct hpo_dp_link_encoder *enc,
+ const struct link_mst_stream_allocation_table *table);
+
+void dcn31_hpo_dp_link_enc_set_throttled_vcp_size(
+ struct hpo_dp_link_encoder *enc,
+ uint32_t stream_encoder_inst,
+ struct fixed31_32 avg_time_slots_per_mtp);
+
+void dcn31_hpo_dp_link_enc_read_state(
+ struct hpo_dp_link_encoder *enc,
+ struct hpo_dp_link_enc_state *state);
+
+void dcn31_hpo_dp_link_enc_set_ffe(
+ struct hpo_dp_link_encoder *enc,
+ const struct dc_link_settings *link_settings,
+ uint8_t ffe_preset);
+
+#endif // __DAL_DCN31_HPO_LINK_ENCODER_H__
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index 1994a8d3883d..f264a32ebade 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -53,6 +53,7 @@
#include "dcn30/dcn30_afmt.h"
#include "dcn30/dcn30_dio_stream_encoder.h"
#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_link_encoder.h"
#include "dcn31/dcn31_apg.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dce/dce_clock_source.h"
@@ -585,6 +586,29 @@ static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = {
DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK)
};
+#define hpo_dp_link_encoder_reg_list(id)\
+[id] = {\
+ DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\
+ DCN3_1_RDPCSTX_REG_LIST(0),\
+ DCN3_1_RDPCSTX_REG_LIST(1),\
+ DCN3_1_RDPCSTX_REG_LIST(2),\
+ DCN3_1_RDPCSTX_REG_LIST(3),\
+ DCN3_1_RDPCSTX_REG_LIST(4)\
+}
+
+static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = {
+ hpo_dp_link_encoder_reg_list(0),
+ hpo_dp_link_encoder_reg_list(1),
+};
+
+static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = {
+ DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {
+ DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)
+};
+
static const struct dcn3_dpp_registers dpp_regs[] = {
dpp_regs(0),
dpp_regs(1),
@@ -922,6 +946,7 @@ static const struct resource_caps res_cap_dcn31 = {
.num_stream_encoder = 5,
.num_dig_link_enc = 5,
.num_hpo_dp_stream_encoder = 4,
+ .num_hpo_dp_link_encoder = 2,
.num_pll = 5,
.num_dwb = 1,
.num_ddc = 5,
@@ -1398,6 +1423,22 @@ static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create(
return &hpo_dp_enc31->base;
}
+static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create(
+ uint8_t inst,
+ struct dc_context *ctx)
+{
+ struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31;
+
+ /* allocate HPO link encoder */
+ hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL);
+
+ hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst,
+ &hpo_dp_link_enc_regs[inst],
+ &hpo_dp_le_shift, &hpo_dp_le_mask);
+
+ return &hpo_dp_enc31->base;
+}
+
static struct dce_hwseq *dcn31_hwseq_create(
struct dc_context *ctx)
{
@@ -1416,6 +1457,7 @@ static const struct resource_create_funcs res_create_funcs = {
.create_audio = dcn31_create_audio,
.create_stream_encoder = dcn31_stream_encoder_create,
.create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
+ .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create,
.create_hwseq = dcn31_hwseq_create,
};
@@ -1424,6 +1466,7 @@ static const struct resource_create_funcs res_create_maximus_funcs = {
.create_audio = NULL,
.create_stream_encoder = NULL,
.create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
+ .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create,
.create_hwseq = dcn31_hwseq_create,
};
@@ -1461,6 +1504,13 @@ static void dcn31_resource_destruct(struct dcn31_resource_pool *pool)
}
}
+ for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) {
+ if (pool->base.hpo_dp_link_enc[i] != NULL) {
+ kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i]));
+ pool->base.hpo_dp_link_enc[i] = NULL;
+ }
+ }
+
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
if (pool->base.dscs[i] != NULL)
dcn20_dsc_destroy(&pool->base.dscs[i]);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 19dbfc8a44bb..ed254c2771f0 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -249,6 +249,8 @@ struct resource_pool {
#if defined(CONFIG_DRM_AMD_DC_DCN)
unsigned int hpo_dp_stream_enc_count;
struct hpo_dp_stream_encoder *hpo_dp_stream_enc[MAX_HPO_DP2_ENCODERS];
+ unsigned int hpo_dp_link_enc_count;
+ struct hpo_dp_link_encoder *hpo_dp_link_enc[MAX_HPO_DP2_LINK_ENCODERS];
#endif
#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_3dlut *mpc_lut[MAX_PIPES];
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
index ad9e9e2d52b0..10ecbc667ffa 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
@@ -40,6 +40,7 @@
#define MAX_DWB_PIPES 1
#if defined(CONFIG_DRM_AMD_DC_DCN)
#define MAX_HPO_DP2_ENCODERS 4
+#define MAX_HPO_DP2_LINK_ENCODERS 2
#endif
struct gamma_curve {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
index 9eaf345aa2a1..fa3a725e11dc 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
@@ -210,4 +210,91 @@ struct link_enc_assignment {
enum engine_id eng_id;
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+enum dp2_link_mode {
+ DP2_LINK_TRAINING_TPS1,
+ DP2_LINK_TRAINING_TPS2,
+ DP2_LINK_ACTIVE,
+ DP2_TEST_PATTERN
+};
+
+enum dp2_phy_tp_select {
+ DP_DPHY_TP_SELECT_TPS1,
+ DP_DPHY_TP_SELECT_TPS2,
+ DP_DPHY_TP_SELECT_PRBS,
+ DP_DPHY_TP_SELECT_CUSTOM,
+ DP_DPHY_TP_SELECT_SQUARE
+};
+
+enum dp2_phy_tp_prbs {
+ DP_DPHY_TP_PRBS7,
+ DP_DPHY_TP_PRBS9,
+ DP_DPHY_TP_PRBS11,
+ DP_DPHY_TP_PRBS15,
+ DP_DPHY_TP_PRBS23,
+ DP_DPHY_TP_PRBS31
+};
+
+struct hpo_dp_link_enc_state {
+ uint32_t link_enc_enabled;
+ uint32_t link_mode;
+ uint32_t lane_count;
+ uint32_t slot_count[4];
+ uint32_t stream_src[4];
+ uint32_t vc_rate_x[4];
+ uint32_t vc_rate_y[4];
+};
+
+struct hpo_dp_link_encoder {
+ const struct hpo_dp_link_encoder_funcs *funcs;
+ struct dc_context *ctx;
+ int inst;
+ enum engine_id preferred_engine;
+ enum transmitter transmitter;
+ enum hpd_source_id hpd_source;
+};
+
+struct hpo_dp_link_encoder_funcs {
+
+ void (*enable_link_phy)(struct hpo_dp_link_encoder *enc,
+ const struct dc_link_settings *link_settings,
+ enum transmitter transmitter);
+
+ void (*disable_link_phy)(struct hpo_dp_link_encoder *link_enc,
+ enum signal_type signal);
+
+ void (*link_enable)(
+ struct hpo_dp_link_encoder *enc,
+ enum dc_lane_count num_lanes);
+
+ void (*link_disable)(
+ struct hpo_dp_link_encoder *enc);
+
+ void (*set_link_test_pattern)(
+ struct hpo_dp_link_encoder *enc,
+ struct encoder_set_dp_phy_pattern_param *tp_params);
+
+ void (*update_stream_allocation_table)(
+ struct hpo_dp_link_encoder *enc,
+ const struct link_mst_stream_allocation_table *table);
+
+ void (*set_throttled_vcp_size)(
+ struct hpo_dp_link_encoder *enc,
+ uint32_t stream_encoder_inst,
+ struct fixed31_32 avg_time_slots_per_mtp);
+
+ bool (*is_in_alt_mode) (
+ struct hpo_dp_link_encoder *enc);
+
+ void (*read_state)(
+ struct hpo_dp_link_encoder *enc,
+ struct hpo_dp_link_enc_state *state);
+
+ void (*set_ffe)(
+ struct hpo_dp_link_encoder *enc,
+ const struct dc_link_settings *link_settings,
+ uint8_t ffe_preset);
+};
+#endif
+
#endif /* LINK_ENCODER_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 5a2cfc899044..713f6d5cf3e0 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -51,6 +51,7 @@ struct resource_caps {
unsigned int num_dig_link_enc; // Total number of DIGs (digital encoders) in DIO (Display Input/Output).
#if defined(CONFIG_DRM_AMD_DC_DCN)
int num_hpo_dp_stream_encoder;
+ int num_hpo_dp_link_encoder;
#endif
int num_mpc_3dlut;
};
@@ -74,6 +75,10 @@ struct resource_create_funcs {
#if defined(CONFIG_DRM_AMD_DC_DCN)
struct hpo_dp_stream_encoder *(*create_hpo_dp_stream_encoder)(
enum engine_id eng_id, struct dc_context *ctx);
+
+ struct hpo_dp_link_encoder *(*create_hpo_dp_link_encoder)(
+ uint8_t inst,
+ struct dc_context *ctx);
#endif
struct dce_hwseq *(*create_hwseq)(
diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
index 32f5274ed34e..efd9812c13ec 100644
--- a/drivers/gpu/drm/amd/display/include/link_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
@@ -114,13 +114,30 @@ enum dp_test_pattern {
DP_TEST_PATTERN_CP2520_2,
DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE = DP_TEST_PATTERN_CP2520_2,
DP_TEST_PATTERN_CP2520_3,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DP_TEST_PATTERN_128b_132b_TPS1,
+ DP_TEST_PATTERN_128b_132b_TPS2,
+ DP_TEST_PATTERN_PRBS9,
+ DP_TEST_PATTERN_PRBS11,
+ DP_TEST_PATTERN_PRBS15,
+ DP_TEST_PATTERN_PRBS23,
+ DP_TEST_PATTERN_PRBS31,
+ DP_TEST_PATTERN_264BIT_CUSTOM,
+ DP_TEST_PATTERN_SQUARE_PULSE,
+#endif
/* Link Training Patterns */
DP_TEST_PATTERN_TRAINING_PATTERN1,
DP_TEST_PATTERN_TRAINING_PATTERN2,
DP_TEST_PATTERN_TRAINING_PATTERN3,
DP_TEST_PATTERN_TRAINING_PATTERN4,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE,
+ DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE,
+ DP_TEST_PATTERN_PHY_PATTERN_END = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE,
+#else
DP_TEST_PATTERN_PHY_PATTERN_END = DP_TEST_PATTERN_TRAINING_PATTERN4,
+#endif
/* link test patterns*/
DP_TEST_PATTERN_COLOR_SQUARES,
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 4/6] drm/amd/display: Add DP 2.0 DCCG
2021-08-19 18:58 [PATCH v3 0/6] Add DP 2.0 SST Support Fangzhi Zuo
` (2 preceding siblings ...)
2021-08-19 18:58 ` [PATCH v3 3/6] drm/amd/display: Add DP 2.0 HPO Link Encoder Fangzhi Zuo
@ 2021-08-19 18:58 ` Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 5/6] drm/amd/display: Add DP 2.0 BIOS and DMUB Support Fangzhi Zuo
2021-08-19 18:58 ` [PATCH v3 6/6] drm/amd/display: Add DP 2.0 SST DC Support Fangzhi Zuo
5 siblings, 0 replies; 9+ messages in thread
From: Fangzhi Zuo @ 2021-08-19 18:58 UTC (permalink / raw)
To: amd-gfx, nicholas.kazlauskas, harry.wentland; +Cc: wayne.lin, Fangzhi Zuo
HW Blocks:
+--------+ +-----+ +------+
| OPTC | | HDA | | HUBP |
+--------+ +-----+ +------+
| | |
| | |
HPO ====|==========|========|====
| | v |
| | +-----+ |
| | | APG | |
| | +-----+ |
| | | |
| v v v
| +---------------------+
| | HPO Stream Encoder |
| +---------------------+
| |
| v
| +--------------------+
| | HPO Link Encoder |
| +--------------------+
| |
v ===============|=============
v
+------------------+
| DIO Output Mux |
+------------------+
|
v
+-----+
| PHY |
+-----+
| PHYD32CLK[0]
v
+------+
| DCCG |
+------+
|
v
SYMCLK32
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
.../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c | 162 ++++++++++++++++++
.../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h | 18 ++
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 23 +++
.../amd/display/dc/inc/hw/timing_generator.h | 3 +
4 files changed, 206 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
index 696c9307715d..9896adf67425 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
@@ -42,6 +42,155 @@
#define DC_LOGGER \
dccg->ctx->logger
+void dccg31_set_dpstreamclk(
+ struct dccg *dccg,
+ enum hdmistreamclk_source src,
+ int otg_inst)
+{
+ struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+ /* enabled to select one of the DTBCLKs for pipe */
+ switch (otg_inst) {
+ case 0:
+ REG_UPDATE(DPSTREAMCLK_CNTL,
+ DPSTREAMCLK_PIPE0_EN, (src == REFCLK) ? 0 : 1);
+ break;
+ case 1:
+ REG_UPDATE(DPSTREAMCLK_CNTL,
+ DPSTREAMCLK_PIPE1_EN, (src == REFCLK) ? 0 : 1);
+ break;
+ case 2:
+ REG_UPDATE(DPSTREAMCLK_CNTL,
+ DPSTREAMCLK_PIPE2_EN, (src == REFCLK) ? 0 : 1);
+ break;
+ case 3:
+ REG_UPDATE(DPSTREAMCLK_CNTL,
+ DPSTREAMCLK_PIPE3_EN, (src == REFCLK) ? 0 : 1);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+}
+
+void dccg31_enable_symclk32_se(
+ struct dccg *dccg,
+ int hpo_se_inst,
+ enum phyd32clk_clock_source phyd32clk)
+{
+ struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+ /* select one of the PHYD32CLKs as the source for symclk32_se */
+ switch (hpo_se_inst) {
+ case 0:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE0_SRC_SEL, phyd32clk,
+ SYMCLK32_SE0_EN, 1);
+ break;
+ case 1:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE1_SRC_SEL, phyd32clk,
+ SYMCLK32_SE1_EN, 1);
+ break;
+ case 2:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE2_SRC_SEL, phyd32clk,
+ SYMCLK32_SE2_EN, 1);
+ break;
+ case 3:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE3_SRC_SEL, phyd32clk,
+ SYMCLK32_SE3_EN, 1);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+}
+
+void dccg31_disable_symclk32_se(
+ struct dccg *dccg,
+ int hpo_se_inst)
+{
+ struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+ /* set refclk as the source for symclk32_se */
+ switch (hpo_se_inst) {
+ case 0:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE0_SRC_SEL, 0,
+ SYMCLK32_SE0_EN, 0);
+ break;
+ case 1:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE1_SRC_SEL, 0,
+ SYMCLK32_SE1_EN, 0);
+ break;
+ case 2:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE2_SRC_SEL, 0,
+ SYMCLK32_SE2_EN, 0);
+ break;
+ case 3:
+ REG_UPDATE_2(SYMCLK32_SE_CNTL,
+ SYMCLK32_SE3_SRC_SEL, 0,
+ SYMCLK32_SE3_EN, 0);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+}
+
+void dccg31_enable_symclk32_le(
+ struct dccg *dccg,
+ int hpo_le_inst,
+ enum phyd32clk_clock_source phyd32clk)
+{
+ struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+ /* select one of the PHYD32CLKs as the source for symclk32_le */
+ switch (hpo_le_inst) {
+ case 0:
+ REG_UPDATE_2(SYMCLK32_LE_CNTL,
+ SYMCLK32_LE0_SRC_SEL, phyd32clk,
+ SYMCLK32_LE0_EN, 1);
+ break;
+ case 1:
+ REG_UPDATE_2(SYMCLK32_LE_CNTL,
+ SYMCLK32_LE1_SRC_SEL, phyd32clk,
+ SYMCLK32_LE1_EN, 1);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+}
+
+void dccg31_disable_symclk32_le(
+ struct dccg *dccg,
+ int hpo_le_inst)
+{
+ struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+ /* set refclk as the source for symclk32_le */
+ switch (hpo_le_inst) {
+ case 0:
+ REG_UPDATE_2(SYMCLK32_LE_CNTL,
+ SYMCLK32_LE0_SRC_SEL, 0,
+ SYMCLK32_LE0_EN, 0);
+ break;
+ case 1:
+ REG_UPDATE_2(SYMCLK32_LE_CNTL,
+ SYMCLK32_LE1_SRC_SEL, 0,
+ SYMCLK32_LE1_EN, 0);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+}
+
void dccg31_set_physymclk(
struct dccg *dccg,
int phy_inst,
@@ -241,12 +390,25 @@ static void dccg31_set_dispclk_change_mode(
void dccg31_init(struct dccg *dccg)
{
+ /* Set HPO stream encoder to use refclk to avoid case where PHY is
+ * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which
+ * will cause DCN to hang.
+ */
+ dccg31_disable_symclk32_se(dccg, 0);
+ dccg31_disable_symclk32_se(dccg, 1);
+ dccg31_disable_symclk32_se(dccg, 2);
+ dccg31_disable_symclk32_se(dccg, 3);
}
static const struct dccg_funcs dccg31_funcs = {
.update_dpp_dto = dccg2_update_dpp_dto,
.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
.dccg_init = dccg31_init,
+ .set_dpstreamclk = dccg31_set_dpstreamclk,
+ .enable_symclk32_se = dccg31_enable_symclk32_se,
+ .disable_symclk32_se = dccg31_disable_symclk32_se,
+ .enable_symclk32_le = dccg31_enable_symclk32_le,
+ .disable_symclk32_le = dccg31_disable_symclk32_le,
.set_physymclk = dccg31_set_physymclk,
.set_dtbclk_dto = dccg31_set_dtbclk_dto,
.set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
index 706ad80ba873..1e5aabcb7799 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
@@ -130,6 +130,24 @@ struct dccg *dccg31_create(
void dccg31_init(struct dccg *dccg);
+void dccg31_enable_symclk32_se(
+ struct dccg *dccg,
+ int hpo_se_inst,
+ enum phyd32clk_clock_source phyd32clk);
+
+void dccg31_disable_symclk32_se(
+ struct dccg *dccg,
+ int hpo_se_inst);
+
+void dccg31_enable_symclk32_le(
+ struct dccg *dccg,
+ int hpo_le_inst,
+ enum phyd32clk_clock_source phyd32clk);
+
+void dccg31_disable_symclk32_le(
+ struct dccg *dccg,
+ int hpo_le_inst);
+
void dccg31_set_physymclk(
struct dccg *dccg,
int phy_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index 0afa2364a986..09237d5819f4 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -79,7 +79,30 @@ struct dccg_funcs {
void (*otg_drop_pixel)(struct dccg *dccg,
uint32_t otg_inst);
void (*dccg_init)(struct dccg *dccg);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ void (*set_dpstreamclk)(
+ struct dccg *dccg,
+ enum hdmistreamclk_source src,
+ int otg_inst);
+
+ void (*enable_symclk32_se)(
+ struct dccg *dccg,
+ int hpo_se_inst,
+ enum phyd32clk_clock_source phyd32clk);
+
+ void (*disable_symclk32_se)(
+ struct dccg *dccg,
+ int hpo_se_inst);
+
+ void (*enable_symclk32_le)(
+ struct dccg *dccg,
+ int hpo_le_inst,
+ enum phyd32clk_clock_source phyd32clk);
+ void (*disable_symclk32_le)(
+ struct dccg *dccg,
+ int hpo_le_inst);
+#endif
void (*set_physymclk)(
struct dccg *dccg,
int phy_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index 03f47f23fb65..7390baf916b5 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -100,6 +100,9 @@ enum crc_selection {
enum otg_out_mux_dest {
OUT_MUX_DIO = 0,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ OUT_MUX_HPO_DP = 2,
+#endif
};
enum h_timing_div_mode {
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 5/6] drm/amd/display: Add DP 2.0 BIOS and DMUB Support
2021-08-19 18:58 [PATCH v3 0/6] Add DP 2.0 SST Support Fangzhi Zuo
` (3 preceding siblings ...)
2021-08-19 18:58 ` [PATCH v3 4/6] drm/amd/display: Add DP 2.0 DCCG Fangzhi Zuo
@ 2021-08-19 18:58 ` Fangzhi Zuo
2021-08-20 14:14 ` Kazlauskas, Nicholas
2021-08-19 18:58 ` [PATCH v3 6/6] drm/amd/display: Add DP 2.0 SST DC Support Fangzhi Zuo
5 siblings, 1 reply; 9+ messages in thread
From: Fangzhi Zuo @ 2021-08-19 18:58 UTC (permalink / raw)
To: amd-gfx, nicholas.kazlauskas, harry.wentland; +Cc: wayne.lin, Fangzhi Zuo
Parse DP2 encoder caps and hpo instance from bios
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 10 ++++++++++
drivers/gpu/drm/amd/display/dc/bios/command_table2.c | 10 ++++++++++
.../drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c | 4 ++++
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 6 ++++++
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 4 ++++
.../gpu/drm/amd/display/include/bios_parser_types.h | 10 ++++++++++
drivers/gpu/drm/amd/include/atomfirmware.h | 6 ++++++
7 files changed, 50 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index 6dbde74c1e06..cdb5c027411a 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -1604,6 +1604,16 @@ static enum bp_result bios_parser_get_encoder_cap_info(
ATOM_ENCODER_CAP_RECORD_HBR3_EN) ? 1 : 0;
info->HDMI_6GB_EN = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN) ? 1 : 0;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ info->IS_DP2_CAPABLE = (record->encodercaps &
+ ATOM_ENCODER_CAP_RECORD_DP2) ? 1 : 0;
+ info->DP_UHBR10_EN = (record->encodercaps &
+ ATOM_ENCODER_CAP_RECORD_UHBR10_EN) ? 1 : 0;
+ info->DP_UHBR13_5_EN = (record->encodercaps &
+ ATOM_ENCODER_CAP_RECORD_UHBR13_5_EN) ? 1 : 0;
+ info->DP_UHBR20_EN = (record->encodercaps &
+ ATOM_ENCODER_CAP_RECORD_UHBR20_EN) ? 1 : 0;
+#endif
info->DP_IS_USB_C = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_USB_C_TYPE) ? 1 : 0;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
index f1f672a997d7..6e333b4af7d6 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
@@ -340,6 +340,13 @@ static enum bp_result transmitter_control_v1_7(
const struct command_table_helper *cmd = bp->cmd_helper;
struct dmub_dig_transmitter_control_data_v1_7 dig_v1_7 = {0};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint8_t hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_0;
+
+ if (dc_is_dp_signal(cntl->signal))
+ hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_DP_0;
+#endif
+
dig_v1_7.phyid = cmd->phy_id_to_atom(cntl->transmitter);
dig_v1_7.action = (uint8_t)cntl->action;
@@ -353,6 +360,9 @@ static enum bp_result transmitter_control_v1_7(
dig_v1_7.hpdsel = cmd->hpd_sel_to_atom(cntl->hpd_sel);
dig_v1_7.digfe_sel = cmd->dig_encoder_sel_to_atom(cntl->engine_id);
dig_v1_7.connobj_id = (uint8_t)cntl->connector_obj_id.id;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ dig_v1_7.HPO_instance = hpo_instance;
+#endif
dig_v1_7.symclk_units.symclk_10khz = cntl->pixel_clock/10;
if (cntl->action == TRANSMITTER_CONTROL_ENABLE ||
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
index 46ea39f5ef8d..6f3c2fb60790 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
@@ -192,6 +192,10 @@ void dcn30_link_encoder_construct(
enc10->base.features.flags.bits.IS_HBR3_CAPABLE =
bp_cap_info.DP_HBR3_EN;
enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
+ enc10->base.features.flags.bits.IS_DP2_CAPABLE = bp_cap_info.IS_DP2_CAPABLE;
+ enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
+ enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
+ enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.DP_IS_USB_C =
bp_cap_info.DP_IS_USB_C;
} else {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
index fa3a725e11dc..b99efcf4712f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
@@ -59,6 +59,12 @@ struct encoder_feature_support {
uint32_t IS_TPS3_CAPABLE:1;
uint32_t IS_TPS4_CAPABLE:1;
uint32_t HDMI_6GB_EN:1;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint32_t IS_DP2_CAPABLE:1;
+ uint32_t IS_UHBR10_CAPABLE:1;
+ uint32_t IS_UHBR13_5_CAPABLE:1;
+ uint32_t IS_UHBR20_CAPABLE:1;
+#endif
uint32_t DP_IS_USB_C:1;
} bits;
uint32_t raw;
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 5950da7bf252..15c823c8ae93 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -959,7 +959,11 @@ struct dmub_dig_transmitter_control_data_v1_7 {
uint8_t hpdsel; /**< =1: HPD1, =2: HPD2, ..., =6: HPD6, =0: HPD is not assigned */
uint8_t digfe_sel; /**< DIG front-end selection, bit0 means DIG0 FE is enabled */
uint8_t connobj_id; /**< Connector Object Id defined in ObjectId.h */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint8_t HPO_instance; /**< HPO instance (0: inst0, 1: inst1) */
+#else
uint8_t reserved0; /**< For future use */
+#endif
uint8_t reserved1; /**< For future use */
uint8_t reserved2[3]; /**< For future use */
uint32_t reserved3[11]; /**< For future use */
diff --git a/drivers/gpu/drm/amd/display/include/bios_parser_types.h b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
index 76a87b682883..d2fb018d31d0 100644
--- a/drivers/gpu/drm/amd/display/include/bios_parser_types.h
+++ b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
@@ -152,6 +152,10 @@ struct bp_transmitter_control {
enum signal_type signal;
enum dc_color_depth color_depth; /* not used for DCE6.0 */
enum hpd_source_id hpd_sel; /* ucHPDSel, used for DCe6.0 */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ enum tx_ffe_id txffe_sel; /* used for DCN3 */
+ enum engine_id hpo_engine_id; /* used for DCN3 */
+#endif
struct graphics_object_id connector_obj_id;
/* symClock; in 10kHz, pixel clock, in HDMI deep color mode, it should
* be pixel clock * deep_color_ratio (in KHz)
@@ -319,6 +323,12 @@ struct bp_encoder_cap_info {
uint32_t DP_HBR2_EN:1;
uint32_t DP_HBR3_EN:1;
uint32_t HDMI_6GB_EN:1;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint32_t IS_DP2_CAPABLE:1;
+ uint32_t DP_UHBR10_EN:1;
+ uint32_t DP_UHBR13_5_EN:1;
+ uint32_t DP_UHBR20_EN:1;
+#endif
uint32_t DP_IS_USB_C:1;
uint32_t RESERVED:27;
};
diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h
index 44955458fe38..d4b245f12651 100644
--- a/drivers/gpu/drm/amd/include/atomfirmware.h
+++ b/drivers/gpu/drm/amd/include/atomfirmware.h
@@ -768,6 +768,12 @@ enum atom_encoder_caps_def
ATOM_ENCODER_CAP_RECORD_HBR2_EN =0x02, // DP1.2 HBR2 setting is qualified and HBR2 can be enabled
ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN =0x04, // HDMI2.0 6Gbps enable or not.
ATOM_ENCODER_CAP_RECORD_HBR3_EN =0x08, // DP1.3 HBR3 is supported by board.
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ ATOM_ENCODER_CAP_RECORD_DP2 =0x10, // DP2 is supported by ASIC/board.
+ ATOM_ENCODER_CAP_RECORD_UHBR10_EN =0x20, // DP2.0 UHBR10 settings is supported by board
+ ATOM_ENCODER_CAP_RECORD_UHBR13_5_EN =0x40, // DP2.0 UHBR13.5 settings is supported by board
+ ATOM_ENCODER_CAP_RECORD_UHBR20_EN =0x80, // DP2.0 UHBR20 settings is supported by board
+#endif
ATOM_ENCODER_CAP_RECORD_USB_C_TYPE =0x100, // the DP connector is a USB-C type.
};
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 5/6] drm/amd/display: Add DP 2.0 BIOS and DMUB Support
2021-08-19 18:58 ` [PATCH v3 5/6] drm/amd/display: Add DP 2.0 BIOS and DMUB Support Fangzhi Zuo
@ 2021-08-20 14:14 ` Kazlauskas, Nicholas
0 siblings, 0 replies; 9+ messages in thread
From: Kazlauskas, Nicholas @ 2021-08-20 14:14 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx, harry.wentland; +Cc: wayne.lin
On 2021-08-19 2:58 p.m., Fangzhi Zuo wrote:
> Parse DP2 encoder caps and hpo instance from bios
>
> Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
> ---
> drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 10 ++++++++++
> drivers/gpu/drm/amd/display/dc/bios/command_table2.c | 10 ++++++++++
> .../drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c | 4 ++++
> drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 6 ++++++
> drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 4 ++++
> .../gpu/drm/amd/display/include/bios_parser_types.h | 10 ++++++++++
> drivers/gpu/drm/amd/include/atomfirmware.h | 6 ++++++
> 7 files changed, 50 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
> index 6dbde74c1e06..cdb5c027411a 100644
> --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
> +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
> @@ -1604,6 +1604,16 @@ static enum bp_result bios_parser_get_encoder_cap_info(
> ATOM_ENCODER_CAP_RECORD_HBR3_EN) ? 1 : 0;
> info->HDMI_6GB_EN = (record->encodercaps &
> ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN) ? 1 : 0;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + info->IS_DP2_CAPABLE = (record->encodercaps &
> + ATOM_ENCODER_CAP_RECORD_DP2) ? 1 : 0;
> + info->DP_UHBR10_EN = (record->encodercaps &
> + ATOM_ENCODER_CAP_RECORD_UHBR10_EN) ? 1 : 0;
> + info->DP_UHBR13_5_EN = (record->encodercaps &
> + ATOM_ENCODER_CAP_RECORD_UHBR13_5_EN) ? 1 : 0;
> + info->DP_UHBR20_EN = (record->encodercaps &
> + ATOM_ENCODER_CAP_RECORD_UHBR20_EN) ? 1 : 0;
> +#endif
> info->DP_IS_USB_C = (record->encodercaps &
> ATOM_ENCODER_CAP_RECORD_USB_C_TYPE) ? 1 : 0;
>
> diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
> index f1f672a997d7..6e333b4af7d6 100644
> --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
> +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
> @@ -340,6 +340,13 @@ static enum bp_result transmitter_control_v1_7(
> const struct command_table_helper *cmd = bp->cmd_helper;
> struct dmub_dig_transmitter_control_data_v1_7 dig_v1_7 = {0};
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint8_t hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_0;
> +
> + if (dc_is_dp_signal(cntl->signal))
> + hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_DP_0;
> +#endif
> +
> dig_v1_7.phyid = cmd->phy_id_to_atom(cntl->transmitter);
> dig_v1_7.action = (uint8_t)cntl->action;
>
> @@ -353,6 +360,9 @@ static enum bp_result transmitter_control_v1_7(
> dig_v1_7.hpdsel = cmd->hpd_sel_to_atom(cntl->hpd_sel);
> dig_v1_7.digfe_sel = cmd->dig_encoder_sel_to_atom(cntl->engine_id);
> dig_v1_7.connobj_id = (uint8_t)cntl->connector_obj_id.id;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + dig_v1_7.HPO_instance = hpo_instance;
> +#endif
> dig_v1_7.symclk_units.symclk_10khz = cntl->pixel_clock/10;
>
> if (cntl->action == TRANSMITTER_CONTROL_ENABLE ||
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
> index 46ea39f5ef8d..6f3c2fb60790 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
> @@ -192,6 +192,10 @@ void dcn30_link_encoder_construct(
> enc10->base.features.flags.bits.IS_HBR3_CAPABLE =
> bp_cap_info.DP_HBR3_EN;
> enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
> + enc10->base.features.flags.bits.IS_DP2_CAPABLE = bp_cap_info.IS_DP2_CAPABLE;
> + enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
> + enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
> + enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
Please drop the DCN guards around this section - don't want to modify
the bit field structure based on DCN vs DCE only.
> enc10->base.features.flags.bits.DP_IS_USB_C =
> bp_cap_info.DP_IS_USB_C;
> } else {
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
> index fa3a725e11dc..b99efcf4712f 100644
> --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
> +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
> @@ -59,6 +59,12 @@ struct encoder_feature_support {
> uint32_t IS_TPS3_CAPABLE:1;
> uint32_t IS_TPS4_CAPABLE:1;
> uint32_t HDMI_6GB_EN:1;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint32_t IS_DP2_CAPABLE:1;
> + uint32_t IS_UHBR10_CAPABLE:1;
> + uint32_t IS_UHBR13_5_CAPABLE:1;
> + uint32_t IS_UHBR20_CAPABLE:1;
> +#endif
Drop them here as well.
> uint32_t DP_IS_USB_C:1;
> } bits;
> uint32_t raw;
> diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
> index 5950da7bf252..15c823c8ae93 100644
> --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
> +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
> @@ -959,7 +959,11 @@ struct dmub_dig_transmitter_control_data_v1_7 {
> uint8_t hpdsel; /**< =1: HPD1, =2: HPD2, ..., =6: HPD6, =0: HPD is not assigned */
> uint8_t digfe_sel; /**< DIG front-end selection, bit0 means DIG0 FE is enabled */
> uint8_t connobj_id; /**< Connector Object Id defined in ObjectId.h */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint8_t HPO_instance; /**< HPO instance (0: inst0, 1: inst1) */
> +#else
> uint8_t reserved0; /**< For future use */
> +#endif
> uint8_t reserved1; /**< For future use */
> uint8_t reserved2[3]; /**< For future use */
> uint32_t reserved3[11]; /**< For future use */
> diff --git a/drivers/gpu/drm/amd/display/include/bios_parser_types.h b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
> index 76a87b682883..d2fb018d31d0 100644
> --- a/drivers/gpu/drm/amd/display/include/bios_parser_types.h
> +++ b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
> @@ -152,6 +152,10 @@ struct bp_transmitter_control {
> enum signal_type signal;
> enum dc_color_depth color_depth; /* not used for DCE6.0 */
> enum hpd_source_id hpd_sel; /* ucHPDSel, used for DCe6.0 */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + enum tx_ffe_id txffe_sel; /* used for DCN3 */
> + enum engine_id hpo_engine_id; /* used for DCN3 */
> +#endif
> struct graphics_object_id connector_obj_id;
> /* symClock; in 10kHz, pixel clock, in HDMI deep color mode, it should
> * be pixel clock * deep_color_ratio (in KHz)
> @@ -319,6 +323,12 @@ struct bp_encoder_cap_info {
> uint32_t DP_HBR2_EN:1;
> uint32_t DP_HBR3_EN:1;
> uint32_t HDMI_6GB_EN:1;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint32_t IS_DP2_CAPABLE:1;
> + uint32_t DP_UHBR10_EN:1;
> + uint32_t DP_UHBR13_5_EN:1;
> + uint32_t DP_UHBR20_EN:1;
> +#endif
And from this file as well.
> uint32_t DP_IS_USB_C:1;
> uint32_t RESERVED:27;
> };
> diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h
> index 44955458fe38..d4b245f12651 100644
> --- a/drivers/gpu/drm/amd/include/atomfirmware.h
> +++ b/drivers/gpu/drm/amd/include/atomfirmware.h
> @@ -768,6 +768,12 @@ enum atom_encoder_caps_def
> ATOM_ENCODER_CAP_RECORD_HBR2_EN =0x02, // DP1.2 HBR2 setting is qualified and HBR2 can be enabled
> ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN =0x04, // HDMI2.0 6Gbps enable or not.
> ATOM_ENCODER_CAP_RECORD_HBR3_EN =0x08, // DP1.3 HBR3 is supported by board.
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + ATOM_ENCODER_CAP_RECORD_DP2 =0x10, // DP2 is supported by ASIC/board.
> + ATOM_ENCODER_CAP_RECORD_UHBR10_EN =0x20, // DP2.0 UHBR10 settings is supported by board
> + ATOM_ENCODER_CAP_RECORD_UHBR13_5_EN =0x40, // DP2.0 UHBR13.5 settings is supported by board
> + ATOM_ENCODER_CAP_RECORD_UHBR20_EN =0x80, // DP2.0 UHBR20 settings is supported by board
> +#endif
And lastly from this file. We don't want to modify this shared header
with DAL specific guards.
Regards,
Nicholas Kazlauskas
> ATOM_ENCODER_CAP_RECORD_USB_C_TYPE =0x100, // the DP connector is a USB-C type.
> };
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 6/6] drm/amd/display: Add DP 2.0 SST DC Support
2021-08-19 18:58 [PATCH v3 0/6] Add DP 2.0 SST Support Fangzhi Zuo
` (4 preceding siblings ...)
2021-08-19 18:58 ` [PATCH v3 5/6] drm/amd/display: Add DP 2.0 BIOS and DMUB Support Fangzhi Zuo
@ 2021-08-19 18:58 ` Fangzhi Zuo
2021-08-20 14:19 ` Kazlauskas, Nicholas
5 siblings, 1 reply; 9+ messages in thread
From: Fangzhi Zuo @ 2021-08-19 18:58 UTC (permalink / raw)
To: amd-gfx, nicholas.kazlauskas, harry.wentland; +Cc: wayne.lin, Fangzhi Zuo
1. Retrieve 128/132b link cap.
2. 128/132b link training and payload allocation.
3. UHBR10 link rate support.
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +
drivers/gpu/drm/amd/display/dc/core/dc.c | 21 +
drivers/gpu/drm/amd/display/dc/core/dc_link.c | 520 +++++++-
.../gpu/drm/amd/display/dc/core/dc_link_dp.c | 1168 ++++++++++++++++-
.../drm/amd/display/dc/core/dc_link_hwss.c | 314 ++++-
.../gpu/drm/amd/display/dc/core/dc_resource.c | 118 ++
drivers/gpu/drm/amd/display/dc/dc.h | 27 +-
drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 222 ++++
drivers/gpu/drm/amd/display/dc/dc_link.h | 3 +
drivers/gpu/drm/amd/display/dc/dc_types.h | 21 +
.../display/dc/dce110/dce110_hw_sequencer.c | 104 +-
.../amd/display/dc/dcn10/dcn10_link_encoder.c | 9 +
.../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 26 +-
.../drm/amd/display/dc/dcn20/dcn20_resource.c | 4 +
.../drm/amd/display/dc/dcn31/dcn31_resource.c | 18 +-
drivers/gpu/drm/amd/display/dc/dm_cp_psp.h | 1 +
drivers/gpu/drm/amd/display/dc/dm_helpers.h | 2 +
.../gpu/drm/amd/display/dc/inc/dc_link_dp.h | 22 +
.../amd/display/dc/inc/hw_sequencer_private.h | 3 +
drivers/gpu/drm/amd/display/dc/inc/resource.h | 5 +
.../gpu/drm/amd/display/include/dpcd_defs.h | 16 +
.../amd/display/include/link_service_types.h | 24 +-
.../drm/amd/display/include/logger_types.h | 6 +
23 files changed, 2619 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 6fee12c91ef5..22ddd8d71bcf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -751,3 +751,11 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
&new_downspread.raw,
sizeof(new_downspread));
}
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
+{
+ // FPGA programming for this clock in diags framework that
+ // needs to go through dm layer, therefore leave dummy interace here
+}
+#endif
\ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 7a442fcfa6ac..8d4d804df5b2 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -186,6 +186,9 @@ static bool create_links(
int i;
int connectors_num;
struct dc_bios *bios = dc->ctx->dc_bios;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ int dp_hpo_link_count = 0;
+#endif
dc->link_count = 0;
@@ -255,6 +258,24 @@ static bool create_links(
goto failed_alloc;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) &&
+ dc->caps.dp_hpo &&
+ link->dc->res_pool->res_cap->num_hpo_dp_link_encoder > 0) {
+ /* FPGA case - Allocate HPO DP link encoder */
+ if (i < link->dc->res_pool->res_cap->num_hpo_dp_link_encoder) {
+ link->hpo_dp_link_enc = link->dc->res_pool->hpo_dp_link_enc[i];
+
+ if (link->hpo_dp_link_enc == NULL) {
+ BREAK_TO_DEBUGGER();
+ goto failed_alloc;
+ }
+ link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source;
+ link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter;
+ }
+ }
+#endif
+
link->link_status.dpcd_caps = &link->dpcd_caps;
enc_init.ctx = dc->ctx;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index 8bd7f42a8053..bb06d8e3312e 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -64,6 +64,31 @@
/*******************************************************************************
* Private functions
******************************************************************************/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static bool add_dp_hpo_link_encoder_to_link(struct dc_link *link)
+{
+ struct hpo_dp_link_encoder *enc = resource_get_unused_hpo_dp_link_encoder(
+ link->dc->res_pool);
+
+ if (!link->hpo_dp_link_enc && enc) {
+ link->hpo_dp_link_enc = enc;
+ link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter;
+ link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source;
+ }
+
+ return (link->hpo_dp_link_enc != NULL);
+}
+
+static void remove_dp_hpo_link_encoder_from_link(struct dc_link *link)
+{
+ if (link->hpo_dp_link_enc) {
+ link->hpo_dp_link_enc->hpd_source = HPD_SOURCEID_UNKNOWN;
+ link->hpo_dp_link_enc->transmitter = TRANSMITTER_UNKNOWN;
+ link->hpo_dp_link_enc = NULL;
+ }
+}
+#endif
+
static void dc_link_destruct(struct dc_link *link)
{
int i;
@@ -91,6 +116,12 @@ static void dc_link_destruct(struct dc_link *link)
link->link_enc->funcs->destroy(&link->link_enc);
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (link->hpo_dp_link_enc) {
+ remove_dp_hpo_link_encoder_from_link(link);
+ }
+#endif
+
if (link->local_sink)
dc_sink_release(link->local_sink);
@@ -928,6 +959,11 @@ static bool dc_link_detect_helper(struct dc_link *link,
return false;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING)
+ add_dp_hpo_link_encoder_to_link(link);
+#endif
+
if (link->type == dc_connection_mst_branch) {
LINK_INFO("link=%d, mst branch is now Connected\n",
link->link_index);
@@ -1173,6 +1209,11 @@ static bool dc_link_detect_helper(struct dc_link *link,
sizeof(link->mst_stream_alloc_table.stream_allocations));
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
+ reset_dp_hpo_stream_encoders_for_link(link);
+#endif
+
link->type = dc_connection_none;
sink_caps.signal = SIGNAL_TYPE_NONE;
/* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk
@@ -1549,6 +1590,9 @@ static bool dc_link_construct(struct dc_link *link,
}
DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
+#endif
/* Update link encoder tracking variables. These are used for the dynamic
* assignment of link encoders to streams.
@@ -1741,17 +1785,36 @@ static enum dc_status enable_link_dp(struct dc_state *state,
/* get link settings for video mode timing */
decide_link_settings(stream, &link_settings);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING &&
+ pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
+ dp_enable_mst_on_sink(link, true);
+ }
+#endif
+
if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
/*in case it is not on*/
link->dc->hwss.edp_power_control(link, true);
link->dc->hwss.edp_wait_for_hpd_ready(link, true);
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
+ /* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */
+ } else {
+ pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
+ link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
+ if (state->clk_mgr && !apply_seamless_boot_optimization)
+ state->clk_mgr->funcs->update_clocks(state->clk_mgr,
+ state, false);
+ }
+#else
pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
- link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
+ link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
if (state->clk_mgr && !apply_seamless_boot_optimization)
state->clk_mgr->funcs->update_clocks(state->clk_mgr,
- state, false);
+ state, false);
+#endif
// during mode switch we do DP_SET_POWER off then on, and OUI is lost
dpcd_set_source_specific_data(link);
@@ -1780,7 +1843,12 @@ static enum dc_status enable_link_dp(struct dc_state *state,
else
fec_enable = true;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
+ dp_set_fec_enable(link, fec_enable);
+#else
dp_set_fec_enable(link, fec_enable);
+#endif
// during mode set we do DP_SET_POWER off then on, aux writes are lost
if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
@@ -2284,6 +2352,9 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
if (dc_is_dp_signal(signal)) {
/* SST DP, eDP */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct dc_link_settings link_settings = link->cur_link_settings;
+#endif
if (dc_is_dp_sst_signal(signal))
dp_disable_link_phy(link, signal);
else
@@ -2291,8 +2362,15 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
if (dc_is_dp_sst_signal(signal) ||
link->mst_stream_alloc_table.stream_count == 0) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) {
+ dp_set_fec_enable(link, false);
+ dp_set_fec_ready(link, false);
+ }
+#else
dp_set_fec_enable(link, false);
dp_set_fec_ready(link, false);
+#endif
}
} else {
if (signal != SIGNAL_TYPE_VIRTUAL)
@@ -2475,9 +2553,14 @@ static bool dp_active_dongle_validate_timing(
break;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER &&
+ dongle_caps->extendedCapValid == true) {
+#else
if (dpcd_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
dongle_caps->extendedCapValid == false)
return true;
+#endif
/* Check Pixel Encoding */
switch (timing->pixel_encoding) {
@@ -2520,6 +2603,87 @@ static bool dp_active_dongle_validate_timing(
if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
return false;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ }
+
+ if (dongle_caps->dfp_cap_ext.supported) {
+
+ if (dongle_caps->dfp_cap_ext.max_pixel_rate_in_mps < (timing->pix_clk_100hz / 10000))
+ return false;
+
+ if (dongle_caps->dfp_cap_ext.max_video_h_active_width < timing->h_addressable)
+ return false;
+
+ if (dongle_caps->dfp_cap_ext.max_video_v_active_height < timing->v_addressable)
+ return false;
+
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_666 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_6bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_16bpc)
+ return false;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_16bpc)
+ return false;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_16bpc)
+ return false;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_16bpc)
+ return false;
+ }
+ }
+#endif
+
return true;
}
@@ -3016,6 +3180,159 @@ static void update_mst_stream_alloc_table(
link->mst_stream_alloc_table.stream_allocations[i] =
work_table[i];
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+/* TODO: Temp function for Diags FPGA */
+static void dp2_update_mst_stream_alloc_table(
+ struct dc_link *link,
+ struct stream_encoder *dio_stream_enc,
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
+ const struct dp_mst_stream_allocation_table *proposed_table)
+{
+ struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = {
+ { 0 } };
+ struct link_mst_stream_allocation *dc_alloc;
+
+ int i;
+ int j;
+
+ /* if DRM proposed_table has more than one new payload */
+ ASSERT(proposed_table->stream_count -
+ link->mst_stream_alloc_table.stream_count < 2);
+
+ /* copy proposed_table to link, add stream encoder */
+ for (i = 0; i < proposed_table->stream_count; i++) {
+
+ for (j = 0; j < link->mst_stream_alloc_table.stream_count; j++) {
+ dc_alloc =
+ &link->mst_stream_alloc_table.stream_allocations[j];
+
+ if (dc_alloc->vcp_id ==
+ proposed_table->stream_allocations[i].vcp_id) {
+
+ work_table[i] = *dc_alloc;
+ break; /* exit j loop */
+ }
+ }
+
+ /* new vcp_id */
+ if (j == link->mst_stream_alloc_table.stream_count) {
+ work_table[i].vcp_id =
+ proposed_table->stream_allocations[i].vcp_id;
+ work_table[i].slot_count =
+ proposed_table->stream_allocations[i].slot_count;
+ work_table[i].stream_enc = dio_stream_enc;
+ work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc;
+ }
+ }
+
+ /* update link->mst_stream_alloc_table with work_table */
+ link->mst_stream_alloc_table.stream_count =
+ proposed_table->stream_count;
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++)
+ link->mst_stream_alloc_table.stream_allocations[i] =
+ work_table[i];
+}
+
+/*
+ * Payload allocation/deallocation for SST introduced in DP2.0
+ */
+enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx, bool allocate)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc;
+ struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
+ struct link_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp;
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ /* slot X.Y for SST payload deallocate */
+ if (!allocate) {
+ avg_time_slots_per_mtp = dc_fixpt_from_int(0);
+
+ DC_LOG_DP2("SST Update Payload: set_throttled_vcp_size slot X.Y for SST stream"
+ "X: %d "
+ "Y: %d",
+ dc_fixpt_floor(
+ avg_time_slots_per_mtp),
+ dc_fixpt_ceil(
+ dc_fixpt_shl(
+ dc_fixpt_sub_int(
+ avg_time_slots_per_mtp,
+ dc_fixpt_floor(
+ avg_time_slots_per_mtp)),
+ 26)));
+
+ hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
+ hpo_dp_link_encoder,
+ hpo_dp_stream_encoder->inst,
+ avg_time_slots_per_mtp);
+ }
+
+ /* calculate VC payload and update branch with new payload allocation table*/
+ if (!dpcd_write_128b_132b_sst_payload_allocation_table(
+ stream,
+ link,
+ &proposed_table,
+ allocate)) {
+ DC_LOG_ERROR("SST Update Payload: Failed to update "
+ "allocation table for "
+ "pipe idx: %d\n",
+ pipe_ctx->pipe_idx);
+ }
+
+ proposed_table.stream_allocations[0].hpo_dp_stream_enc = hpo_dp_stream_encoder;
+
+ ASSERT(proposed_table.stream_count == 1);
+
+ //TODO - DP2.0 Logging: Instead of hpo_dp_stream_enc pointer, log instance id
+ DC_LOG_DP2("SST Update Payload: hpo_dp_stream_enc: %p "
+ "vcp_id: %d "
+ "slot_count: %d\n",
+ (void *) proposed_table.stream_allocations[0].hpo_dp_stream_enc,
+ proposed_table.stream_allocations[0].vcp_id,
+ proposed_table.stream_allocations[0].slot_count);
+
+ /* program DP source TX for payload */
+ hpo_dp_link_encoder->funcs->update_stream_allocation_table(
+ hpo_dp_link_encoder,
+ &proposed_table);
+
+ /* poll for ACT handled */
+ if (!dpcd_poll_for_allocation_change_trigger(link)) {
+ // Failures will result in blackscreen and errors logged
+ BREAK_TO_DEBUGGER();
+ }
+
+ /* slot X.Y for SST payload allocate */
+ if (allocate) {
+ avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
+
+ DC_LOG_DP2("SST Update Payload: "
+ "slot.X: %d "
+ "slot.Y: %d",
+ dc_fixpt_floor(
+ avg_time_slots_per_mtp),
+ dc_fixpt_ceil(
+ dc_fixpt_shl(
+ dc_fixpt_sub_int(
+ avg_time_slots_per_mtp,
+ dc_fixpt_floor(
+ avg_time_slots_per_mtp)),
+ 26)));
+
+ hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
+ hpo_dp_link_encoder,
+ hpo_dp_stream_encoder->inst,
+ avg_time_slots_per_mtp);
+ }
+
+ /* Always return DC_OK.
+ * If part of sequence fails, log failure(s) and show blackscreen
+ */
+ return DC_OK;
+}
+#endif
/* convert link_mst_stream_alloc_table to dm dp_mst_stream_alloc_table
* because stream_encoder is not exposed to dm
@@ -3203,6 +3520,11 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
config.link_enc_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A;
config.phy_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A;
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
+ config.link_enc_idx = pipe_ctx->stream->link->hpo_dp_link_enc->inst;
+ config.dp2_enabled = 1;
+ }
#endif
config.dpms_off = dpms_off;
config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context;
@@ -3214,6 +3536,88 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
}
#endif
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct link_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp;
+ uint8_t req_slot_count = 0;
+ uint8_t vc_id = 1; /// VC ID always 1 for SST
+
+ struct dc_link_settings link_settings = {0};
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ decide_link_settings(stream, &link_settings);
+ stream->link->cur_link_settings = link_settings;
+
+ /* Enable clock, Configure lane count, and Enable Link Encoder*/
+ enable_dp_hpo_output(stream->link, &stream->link->cur_link_settings);
+
+#ifdef DIAGS_BUILD
+ /* Workaround for FPGA HPO capture DP link data:
+ * HPO capture will set link to active mode
+ * This workaround is required to get a capture from start of frame
+ */
+ if (!dc->debug.fpga_hpo_capture_en) {
+ struct encoder_set_dp_phy_pattern_param params = {0};
+ params.dp_phy_pattern = DP_TEST_PATTERN_VIDEO_MODE;
+
+ /* Set link active */
+ stream->link->hpo_dp_link_enc->funcs->set_link_test_pattern(
+ stream->link->hpo_dp_link_enc,
+ ¶ms);
+ }
+#endif
+
+ /* Enable DP_STREAM_ENC */
+ dc->hwss.enable_stream(pipe_ctx);
+
+ /* Set DPS PPS SDP (AKA "info frames") */
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ dp_set_dsc_pps_sdp(pipe_ctx, true);
+ }
+
+ /* Allocate Payload */
+ if ((stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) && (state->stream_count > 1)) {
+ // MST case
+ uint8_t i;
+
+ proposed_table.stream_count = state->stream_count;
+ for (i = 0; i < state->stream_count; i++) {
+ avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(state->streams[i], state->streams[i]->link);
+ req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
+ proposed_table.stream_allocations[i].slot_count = req_slot_count;
+ proposed_table.stream_allocations[i].vcp_id = i+1;
+ /* NOTE: This makes assumption that pipe_ctx index is same as stream index */
+ proposed_table.stream_allocations[i].hpo_dp_stream_enc = state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc;
+ }
+ } else {
+ // SST case
+ avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, stream->link);
+ req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
+ proposed_table.stream_count = 1; /// Always 1 stream for SST
+ proposed_table.stream_allocations[0].slot_count = req_slot_count;
+ proposed_table.stream_allocations[0].vcp_id = vc_id;
+ proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+ }
+
+ stream->link->hpo_dp_link_enc->funcs->update_stream_allocation_table(
+ stream->link->hpo_dp_link_enc,
+ &proposed_table);
+
+ stream->link->hpo_dp_link_enc->funcs->set_throttled_vcp_size(
+ stream->link->hpo_dp_link_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
+ avg_time_slots_per_mtp);
+
+
+
+ dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
+}
+#endif
+
void core_link_enable_stream(
struct dc_state *state,
struct pipe_ctx *pipe_ctx)
@@ -3230,7 +3634,12 @@ void core_link_enable_stream(
dc_is_virtual_signal(pipe_ctx->stream->signal))
return;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
+ && !is_dp_128b_132b_signal(pipe_ctx)) {
+#else
if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) {
+#endif
stream->link->link_enc->funcs->setup(
stream->link->link_enc,
pipe_ctx->stream->signal);
@@ -3240,13 +3649,32 @@ void core_link_enable_stream(
stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
}
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->set_stream_attribute(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &stream->timing,
+ stream->output_color_space,
+ stream->use_vsc_sdp_for_colorimetry,
+ stream->timing.flags.DSC,
+ false);
+ otg_out_dest = OUT_MUX_HPO_DP;
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(
+ pipe_ctx->stream_res.stream_enc,
+ &stream->timing,
+ stream->output_color_space,
+ stream->use_vsc_sdp_for_colorimetry,
+ stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
+ }
+#else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(
pipe_ctx->stream_res.stream_enc,
&stream->timing,
stream->output_color_space,
stream->use_vsc_sdp_for_colorimetry,
stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
+#endif
if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
pipe_ctx->stream_res.stream_enc->funcs->hdmi_set_stream_attribute(
@@ -3357,7 +3785,12 @@ void core_link_enable_stream(
* as a workaround for the incorrect value being applied
* from transmitter control.
*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
+ is_dp_128b_132b_signal(pipe_ctx)))
+#else
if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
+#endif
stream->link->link_enc->funcs->setup(
stream->link->link_enc,
pipe_ctx->stream->signal);
@@ -3375,6 +3808,11 @@ void core_link_enable_stream(
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
dc_link_allocate_mst_payload(pipe_ctx);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ is_dp_128b_132b_signal(pipe_ctx))
+ dc_link_update_sst_payload(pipe_ctx, true);
+#endif
dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->link->cur_link_settings);
@@ -3391,6 +3829,11 @@ void core_link_enable_stream(
dc->hwss.enable_audio_stream(pipe_ctx);
} else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ fpga_dp_hpo_enable_link_and_stream(state, pipe_ctx);
+ }
+#endif
if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
dc_is_virtual_signal(pipe_ctx->stream->signal))
dp_set_dsc_enable(pipe_ctx, true);
@@ -3426,6 +3869,11 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
deallocate_mst_payload(pipe_ctx);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ is_dp_128b_132b_signal(pipe_ctx))
+ dc_link_update_sst_payload(pipe_ctx, false);
+#endif
if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
struct ext_hdmi_settings settings = {0};
@@ -3452,14 +3900,39 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
}
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ !is_dp_128b_132b_signal(pipe_ctx)) {
+
+ /* In DP1.x SST mode, our encoder will go to TPS1
+ * when link is on but stream is off.
+ * Disabling link before stream will avoid exposing TPS1 pattern
+ * during the disable sequence as it will confuse some receivers
+ * state machine.
+ * In DP2 or MST mode, our encoder will stay video active
+ */
+ disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
+ dc->hwss.disable_stream(pipe_ctx);
+ } else {
+ dc->hwss.disable_stream(pipe_ctx);
+ disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
+ }
+#else
disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
dc->hwss.disable_stream(pipe_ctx);
+#endif
if (pipe_ctx->stream->timing.flags.DSC) {
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dp_set_dsc_enable(pipe_ctx, false);
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
+ pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO);
+ }
+#endif
}
void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
@@ -3592,6 +4065,13 @@ void dc_link_set_preferred_training_settings(struct dc *dc,
if (link_setting != NULL) {
link->preferred_link_setting = *link_setting;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(link_setting) ==
+ DP_128b_132b_ENCODING && !link->hpo_dp_link_enc) {
+ if (!add_dp_hpo_link_encoder_to_link(link))
+ memset(&link->preferred_link_setting, 0, sizeof(link->preferred_link_setting));
+ }
+#endif
} else {
link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
@@ -3633,6 +4113,38 @@ uint32_t dc_link_bandwidth_kbps(
const struct dc_link *link,
const struct dc_link_settings *link_setting)
{
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint32_t total_data_bw_efficiency_x10000 = 0;
+ uint32_t link_rate_per_lane_kbps = 0;
+
+ switch (dp_get_link_encoding_format(link_setting)) {
+ case DP_8b_10b_ENCODING:
+ /* For 8b/10b encoding:
+ * link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane.
+ * data bandwidth efficiency is 80% with additional 3% overhead if FEC is supported.
+ */
+ link_rate_per_lane_kbps = link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE;
+ total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000;
+ if (dc_link_should_enable_fec(link)) {
+ total_data_bw_efficiency_x10000 /= 100;
+ total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100;
+ }
+ break;
+ case DP_128b_132b_ENCODING:
+ /* For 128b/132b encoding:
+ * link rate is defined in the unit of 10mbps per lane.
+ * total data bandwidth efficiency is always 96.71%.
+ */
+ link_rate_per_lane_kbps = link_setting->link_rate * 10000;
+ total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_128b_132b_x10000;
+ break;
+ default:
+ break;
+ }
+
+ /* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */
+ return link_rate_per_lane_kbps * link_setting->lane_count / 10000 * total_data_bw_efficiency_x10000;
+#else
uint32_t link_bw_kbps =
link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ; /* bytes per sec */
@@ -3663,9 +4175,9 @@ uint32_t dc_link_bandwidth_kbps(
long long fec_link_bw_kbps = link_bw_kbps * 970LL;
link_bw_kbps = (uint32_t)(div64_s64(fec_link_bw_kbps, 1000LL));
}
-
return link_bw_kbps;
+#endif
}
const struct dc_link_settings *dc_link_get_link_cap(
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
index cd025c12f17b..fc122c8c2318 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -39,6 +39,43 @@ enum {
POST_LT_ADJ_REQ_TIMEOUT = 200
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+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},
+};
+#endif
+
static bool decide_fallback_link_setting(
struct dc_link_settings initial_link_settings,
struct dc_link_settings *current_link_setting,
@@ -52,15 +89,27 @@ static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link,
{
union training_aux_rd_interval training_rd_interval;
uint32_t wait_in_micro_secs = 100;
-
+#if defined(CONFIG_DRM_AMD_DC_DCN)
memset(&training_rd_interval, 0, sizeof(training_rd_interval));
+ if (dp_get_link_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;
+ }
+#else
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;
+ wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+#endif
return wait_in_micro_secs;
}
@@ -68,6 +117,36 @@ static uint32_t get_eq_training_aux_rd_interval(
struct dc_link *link,
const struct dc_link_settings *link_settings)
{
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ union training_aux_rd_interval training_rd_interval;
+
+ memset(&training_rd_interval, 0, sizeof(training_rd_interval));
+ if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ core_link_read_dpcd(
+ link,
+ DP_128b_132b_TRAINING_AUX_RD_INTERVAL,
+ (uint8_t *)&training_rd_interval,
+ sizeof(training_rd_interval));
+ } else if (dp_get_link_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;
+ }
+#else
union training_aux_rd_interval training_rd_interval;
uint32_t wait_in_micro_secs = 400;
@@ -87,13 +166,21 @@ static uint32_t get_eq_training_aux_rd_interval(
}
return wait_in_micro_secs;
+#endif
}
void dp_wait_for_training_aux_rd_interval(
struct dc_link *link,
uint32_t wait_in_micro_secs)
{
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (wait_in_micro_secs > 16000)
+ msleep(wait_in_micro_secs/1000);
+ else
+ udelay(wait_in_micro_secs);
+#else
udelay(wait_in_micro_secs);
+#endif
DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
__func__,
@@ -121,6 +208,17 @@ enum dpcd_training_patterns
case DP_TRAINING_PATTERN_SEQUENCE_4:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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;
+#endif
case DP_TRAINING_PATTERN_VIDEOIDLE:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
break;
@@ -159,13 +257,62 @@ static void dpcd_set_training_pattern(
static enum dc_dp_training_pattern decide_cr_training_pattern(
const struct dc_link_settings *link_settings)
{
- return DP_TRAINING_PATTERN_SEQUENCE_1;
+ enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
+
+ switch (dp_get_link_encoding_format(link_settings)) {
+ case DP_8b_10b_ENCODING:
+ pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
+ break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ case DP_128b_132b_ENCODING:
+ pattern = DP_128b_132b_TPS1;
+ break;
+#endif
+ }
+
+ return pattern;
}
static 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;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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;
+
+ /* Access link encoder capability based on whether it is statically
+ * or dynamically assigned to a link.
+ */
+ if (link->is_dig_mapping_flexible &&
+ link->dc->res_pool->funcs->link_encs_assign)
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
+ else
+ link_enc = link->link_enc;
+ ASSERT(link_enc);
+ enc_caps = &link_enc->features;
+
+ switch (dp_get_link_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;
+#else
enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
struct encoder_feature_support *features;
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
@@ -196,7 +343,38 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li
return DP_TRAINING_PATTERN_SEQUENCE_3;
return DP_TRAINING_PATTERN_SEQUENCE_2;
+#endif
+}
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
+{
+ uint8_t link_rate = 0;
+ enum dp_link_encoding encoding = dp_get_link_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;
}
+#endif
enum dc_status dpcd_set_link_settings(
struct dc_link *link,
@@ -247,7 +425,11 @@ enum dc_status dpcd_set_link_settings(
status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
<_settings->link_settings.link_rate_set, 1);
} else {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ rate = get_dpcd_link_rate(<_settings->link_settings);
+#else
rate = (uint8_t) (lt_settings->link_settings.link_rate);
+#endif
status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
}
@@ -289,6 +471,10 @@ uint8_t dc_dp_initialize_scrambling_data_symbols(
disable_scrabled_data_symbols = 1;
break;
case DP_TRAINING_PATTERN_SEQUENCE_4:
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ case DP_128b_132b_TPS1:
+ case DP_128b_132b_TPS2:
+#endif
disable_scrabled_data_symbols = 0;
break;
default:
@@ -356,6 +542,26 @@ static void dpcd_set_lt_pattern_and_lane_settings(
for (lane = 0; lane <
(uint32_t)(lt_settings->link_settings.lane_count); lane++) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(<_settings->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ dpcd_lane[lane].tx_ffe.PRESET_VALUE =
+ lt_settings->lane_settings[lane].FFE_PRESET.settings.level;
+ } else if (dp_get_link_encoding_format(<_settings->link_settings) ==
+ DP_8b_10b_ENCODING) {
+ dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
+ (uint8_t)(lt_settings->lane_settings[lane].VOLTAGE_SWING);
+ dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
+ (uint8_t)(lt_settings->lane_settings[lane].PRE_EMPHASIS);
+
+ dpcd_lane[lane].bits.MAX_SWING_REACHED =
+ (lt_settings->lane_settings[lane].VOLTAGE_SWING ==
+ VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
+ dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
+ (lt_settings->lane_settings[lane].PRE_EMPHASIS ==
+ PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
+ }
+#else
dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
(uint8_t)(lt_settings->lane_settings[lane].VOLTAGE_SWING);
dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
@@ -367,6 +573,7 @@ static void dpcd_set_lt_pattern_and_lane_settings(
dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
(lt_settings->lane_settings[lane].PRE_EMPHASIS ==
PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
+#endif
}
/* concatenate everything into one buffer*/
@@ -380,6 +587,18 @@ static void dpcd_set_lt_pattern_and_lane_settings(
size_in_bytes);
if (is_repeater(link, offset)) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(<_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,
+ dpcd_lane[0].tx_ffe.PRESET_VALUE);
+ else if (dp_get_link_encoding_format(<_settings->link_settings) ==
+ DP_8b_10b_ENCODING)
+#endif
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__,
@@ -390,6 +609,16 @@ static void dpcd_set_lt_pattern_and_lane_settings(
dpcd_lane[0].bits.MAX_SWING_REACHED,
dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
} else {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(<_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,
+ dpcd_lane[0].tx_ffe.PRESET_VALUE);
+ else if (dp_get_link_encoding_format(<_settings->link_settings) ==
+ DP_8b_10b_ENCODING)
+#endif
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,
@@ -414,6 +643,15 @@ static void dpcd_set_lt_pattern_and_lane_settings(
(uint8_t *)(dpcd_lane),
size_in_bytes);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ } else if (dp_get_link_encoding_format(<_settings->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ core_link_write_dpcd(
+ link,
+ dpcd_base_lt_offset,
+ dpcd_lt_buffer,
+ sizeof(dpcd_lt_buffer));
+#endif
} else
/* write it all in (1 + number-of-lanes)-byte burst*/
core_link_write_dpcd(
@@ -484,6 +722,13 @@ void dp_update_drive_settings(
dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2;
else
dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2;
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dest->ffe_preset == NULL)
+ dest->lane_settings[lane].FFE_PRESET = src.lane_settings[lane].FFE_PRESET;
+ else
+ dest->lane_settings[lane].FFE_PRESET = *dest->ffe_preset;
+#endif
}
}
@@ -529,6 +774,10 @@ static void find_max_drive_settings(
lane_settings[0].PRE_EMPHASIS;
/*max_requested.postCursor2 =
* link_training_setting->laneSettings[0].postCursor2;*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ max_requested.FFE_PRESET =
+ link_training_setting->lane_settings[0].FFE_PRESET;
+#endif
/* Determine what the maximum of the requested settings are*/
for (lane = 1; lane < link_training_setting->link_settings.lane_count;
@@ -554,6 +803,13 @@ static void find_max_drive_settings(
link_training_setting->laneSettings[lane].postCursor2;
}
*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (link_training_setting->lane_settings[lane].FFE_PRESET.settings.level >
+ max_requested.FFE_PRESET.settings.level)
+ max_requested.FFE_PRESET.settings.level =
+ link_training_setting->
+ lane_settings[lane].FFE_PRESET.settings.level;
+#endif
}
/* make sure the requested settings are
@@ -567,6 +823,10 @@ static void find_max_drive_settings(
if (max_requested.postCursor2 > PostCursor2_MaxLevel)
max_requested.postCursor2 = PostCursor2_MaxLevel;
*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
+ max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
+#endif
/* make sure the pre-emphasis matches the voltage swing*/
if (max_requested.PRE_EMPHASIS >
@@ -604,6 +864,10 @@ static void find_max_drive_settings(
/*max_lt_setting->laneSettings[lane].postCursor2 =
* max_requested.postCursor2;
*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ max_lt_setting->lane_settings[lane].FFE_PRESET =
+ max_requested.FFE_PRESET;
+#endif
}
}
@@ -701,12 +965,28 @@ enum dc_status dp_get_lane_status_and_drive_settings(
(uint32_t)(link_training_setting->link_settings.lane_count);
lane++) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ request_settings.lane_settings[lane].FFE_PRESET.raw =
+ dpcd_lane_adjust[lane].tx_ffe.PRESET_VALUE;
+ } else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_8b_10b_ENCODING) {
+ request_settings.lane_settings[lane].VOLTAGE_SWING =
+ (enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits.
+ VOLTAGE_SWING_LANE);
+ request_settings.lane_settings[lane].PRE_EMPHASIS =
+ (enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits.
+ PRE_EMPHASIS_LANE);
+ }
+#else
request_settings.lane_settings[lane].VOLTAGE_SWING =
(enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits.
VOLTAGE_SWING_LANE);
request_settings.lane_settings[lane].PRE_EMPHASIS =
(enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits.
PRE_EMPHASIS_LANE);
+#endif
}
/*Note: for postcursor2, read adjusted
@@ -745,6 +1025,26 @@ enum dc_status dpcd_set_lane_settings(
(uint32_t)(link_training_setting->
link_settings.lane_count);
lane++) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ dpcd_lane[lane].tx_ffe.PRESET_VALUE =
+ link_training_setting->lane_settings[lane].FFE_PRESET.settings.level;
+ } else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_8b_10b_ENCODING) {
+ dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
+ (uint8_t)(link_training_setting->lane_settings[lane].VOLTAGE_SWING);
+ dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
+ (uint8_t)(link_training_setting->lane_settings[lane].PRE_EMPHASIS);
+
+ dpcd_lane[lane].bits.MAX_SWING_REACHED =
+ (link_training_setting->lane_settings[lane].VOLTAGE_SWING ==
+ VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
+ dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
+ (link_training_setting->lane_settings[lane].PRE_EMPHASIS ==
+ PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
+ }
+#else
dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
(uint8_t)(link_training_setting->
lane_settings[lane].VOLTAGE_SWING);
@@ -759,6 +1059,7 @@ enum dc_status dpcd_set_lane_settings(
(link_training_setting->
lane_settings[lane].PRE_EMPHASIS ==
PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
+#endif
}
status = core_link_write_dpcd(link,
@@ -786,6 +1087,18 @@ enum dc_status dpcd_set_lane_settings(
*/
if (is_repeater(link, offset)) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_training_setting->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,
+ lane0_set_address,
+ dpcd_lane[0].tx_ffe.PRESET_VALUE);
+ else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_8b_10b_ENCODING)
+#endif
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__,
@@ -797,6 +1110,16 @@ enum dc_status dpcd_set_lane_settings(
dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
} else {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_128b_132b_ENCODING)
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
+ __func__,
+ lane0_set_address,
+ dpcd_lane[0].tx_ffe.PRESET_VALUE);
+ else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
+ DP_8b_10b_ENCODING)
+#endif
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,
@@ -932,6 +1255,14 @@ uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval
case 0x04:
aux_rd_interval_us = 16000;
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ case 0x05:
+ aux_rd_interval_us = 32000;
+ break;
+ case 0x06:
+ aux_rd_interval_us = 64000;
+ break;
+#endif
default:
break;
}
@@ -972,8 +1303,13 @@ static enum link_training_result perform_channel_equalization_sequence(
tr_pattern = lt_settings->pattern_for_eq;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_repeater(link, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING)
+ tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+#else
if (is_repeater(link, offset))
tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+#endif
dp_set_hw_training_pattern(link, tr_pattern, offset);
@@ -1125,9 +1461,28 @@ static enum link_training_result perform_clock_recovery_sequence(
return LINK_TRAINING_SUCCESS;
/* 6. max VS reached*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if ((dp_get_link_encoding_format(<_settings->link_settings) ==
+ DP_8b_10b_ENCODING) &&
+ dp_is_max_vs_reached(lt_settings))
+ break;
+#else
if (dp_is_max_vs_reached(lt_settings))
break;
+#endif
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) &&
+ lt_settings->lane_settings[0].FFE_PRESET.settings.level ==
+ req_settings.lane_settings[0].FFE_PRESET.settings.level)
+ retries_cr++;
+ else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) &&
+ lt_settings->lane_settings[0].VOLTAGE_SWING ==
+ req_settings.lane_settings[0].VOLTAGE_SWING)
+ retries_cr++;
+ else
+ retries_cr = 0;
+#else
/* 7. same lane settings*/
/* Note: settings are the same for all lanes,
* so comparing first lane is sufficient*/
@@ -1138,6 +1493,7 @@ static enum link_training_result perform_clock_recovery_sequence(
retries_cr++;
else
retries_cr = 0;
+#endif
/* 8. update VS/PE/PC2 in lt_settings*/
dp_update_drive_settings(lt_settings, req_settings);
@@ -1172,7 +1528,11 @@ static inline enum link_training_result dp_transition_to_video_idle(
* TPS4 must be used instead of POST_LT_ADJ_REQ.
*/
if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
+#else
lt_settings->pattern_for_eq == DP_TRAINING_PATTERN_SEQUENCE_4) {
+#endif
/* delay 5ms after Main Link output idle pattern and then check
* DPCD 0202h.
*/
@@ -1268,6 +1628,32 @@ static inline void decide_8b_10b_training_settings(
lt_settings->should_set_fec_ready = true;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static inline 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_convert_to_count(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
+ lt_settings->lttpr_mode = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ?
+ LTTPR_MODE_NON_TRANSPARENT : LTTPR_MODE_TRANSPARENT;
+}
+#endif
+
void dp_decide_training_settings(
struct dc_link *link,
const struct dc_link_settings *link_settings,
@@ -1275,6 +1661,10 @@ void dp_decide_training_settings(
{
if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING)
decide_8b_10b_training_settings(link, link_settings, lt_settings);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ else if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING)
+ decide_128b_132b_training_settings(link, link_settings, lt_settings);
+#endif
}
static void override_training_settings(
@@ -1303,6 +1693,11 @@ static void override_training_settings(
lt_settings->pre_emphasis = overrides->pre_emphasis;
if (overrides->post_cursor2 != NULL)
lt_settings->post_cursor2 = overrides->post_cursor2;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (overrides->ffe_preset != NULL)
+ lt_settings->ffe_preset = overrides->ffe_preset;
+#endif
+
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
lt_settings->lane_settings[lane].VOLTAGE_SWING =
lt_settings->voltage_swing != NULL ?
@@ -1489,6 +1884,17 @@ static void print_status_message(
case LINK_RATE_HIGH3:
link_rate = "HBR3";
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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;
+#endif
default:
break;
}
@@ -1518,6 +1924,20 @@ static void print_status_message(
case LINK_TRAINING_LINK_LOSS:
lt_result = "Link loss";
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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;
+#endif
default:
break;
}
@@ -1537,6 +1957,9 @@ static void print_status_message(
}
/* Connectivity log: link training */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
+#endif
CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
link_rate,
lt_settings->link_settings.lane_count,
@@ -1619,9 +2042,23 @@ enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_train
static void dpcd_exit_training_mode(struct dc_link *link)
{
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint8_t sink_status = 0;
+ uint8_t i;
+#endif
/* clear training pattern set */
dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* 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);
+ }
+#endif
}
enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
@@ -1645,6 +2082,131 @@ enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
return status;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+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_128b_132b_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,
+ struct link_training_settings *lt_settings)
+{
+ uint8_t loop_count = 0;
+ uint32_t aux_rd_interval = 0;
+ uint32_t wait_time = 0;
+ struct link_training_settings req_settings;
+ union lane_align_status_updated dpcd_lane_status_updated = { {0} };
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+
+ /* Transmit 128b/132b_TPS1 over Main-Link and Set TRAINING_PATTERN_SET to 01h */
+ dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, DPRX);
+ dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
+
+ /* Adjust TX_FFE_PRESET_VALUE as requested */
+ dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, &req_settings, DPRX);
+ dp_update_drive_settings(lt_settings, req_settings);
+ dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
+ dp_set_hw_lane_settings(link, lt_settings, DPRX);
+ dpcd_set_lane_settings(link, lt_settings, DPRX);
+
+ /* Transmit 128b/132b_TPS2 over Main-Link and Set TRAINING_PATTERN_SET to 02h */
+ dp_set_hw_training_pattern(link, lt_settings->pattern_for_eq, DPRX);
+ dpcd_set_training_pattern(link, lt_settings->pattern_for_eq);
+
+ /* poll for channel EQ done */
+ while (status == LINK_TRAINING_SUCCESS) {
+ loop_count++;
+ dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
+ wait_time += aux_rd_interval;
+ dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, &req_settings, DPRX);
+ dp_update_drive_settings(lt_settings, req_settings);
+ dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
+ 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) {
+ status = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
+ } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+ status = DP_128b_132b_LT_FAILED;
+ } else {
+ dp_set_hw_lane_settings(link, lt_settings, DPRX);
+ dpcd_set_lane_settings(link, lt_settings, DPRX);
+ }
+ }
+
+ /* poll for EQ interlane align done */
+ while (status == LINK_TRAINING_SUCCESS) {
+ if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
+ /* pass */
+ break;
+ } else if (wait_time >= lt_settings->eq_wait_time_limit) {
+ status = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
+ } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+ status = 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;
+ dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, &req_settings, DPRX);
+ }
+ }
+
+ return status;
+}
+
+static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
+ struct dc_link *link,
+ struct link_training_settings *lt_settings)
+{
+ /* Assumption: assume hardware has transmitted eq pattern */
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ struct link_training_settings req_settings;
+ union lane_align_status_updated dpcd_lane_status_updated = { {0} };
+ union lane_status dpcd_lane_status[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 (status == LINK_TRAINING_SUCCESS) {
+ dp_wait_for_training_aux_rd_interval(link,
+ lt_settings->cds_pattern_time);
+ wait_time += lt_settings->cds_pattern_time;
+ dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, &req_settings, DPRX);
+ 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) {
+ status = DP_128b_132b_LT_FAILED;
+ } else if (wait_time >= lt_settings->cds_wait_time_limit) {
+ status = DP_128b_132b_CDS_DONE_TIMEOUT;
+ }
+ }
+
+ return status;
+}
+#endif
+
static enum link_training_result dp_perform_8b_10b_link_training(
struct dc_link *link,
struct link_training_settings *lt_settings)
@@ -1701,6 +2263,35 @@ static enum link_training_result dp_perform_8b_10b_link_training(
return status;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static enum link_training_result dp_perform_128b_132b_link_training(
+ struct dc_link *link,
+ 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,
+ <_settings->link_settings,
+ &legacy_settings);
+ return dp_perform_8b_10b_link_training(link, &legacy_settings);
+ }
+
+ dpcd_set_link_settings(link, lt_settings);
+
+ if (result == LINK_TRAINING_SUCCESS)
+ result = dp_perform_128b_132b_channel_eq_done_sequence(link, lt_settings);
+
+ if (result == LINK_TRAINING_SUCCESS)
+ result = dp_perform_128b_132b_cds_done_sequence(link, lt_settings);
+
+ return result;
+}
+#endif
+
enum link_training_result dc_link_dp_perform_link_training(
struct dc_link *link,
const struct dc_link_settings *link_settings,
@@ -1735,6 +2326,10 @@ enum link_training_result dc_link_dp_perform_link_training(
*/
if (encoding == DP_8b_10b_ENCODING)
status = dp_perform_8b_10b_link_training(link, <_settings);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ else if (encoding == DP_128b_132b_ENCODING)
+ status = dp_perform_128b_132b_link_training(link, <_settings);
+#endif
else
ASSERT(0);
@@ -1780,7 +2375,10 @@ bool perform_link_training_with_retries(
/* 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_enc->funcs->connect_dig_be_to_fe(link_enc,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(¤t_setting) == DP_8b_10b_ENCODING)
+#endif
+ link_enc->funcs->connect_dig_be_to_fe(link_enc,
pipe_ctx->stream_res.stream_enc->id, true);
for (j = 0; j < attempts; ++j) {
@@ -1950,8 +2548,14 @@ enum link_training_result dc_link_dp_sync_lt_attempt(
dp_cs_id, link_settings);
/* Set FEC enable */
- fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
- dp_set_fec_ready(link, fec_enable);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
+#endif
+ fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
+ dp_set_fec_ready(link, fec_enable);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ }
+#endif
if (lt_overrides->alternate_scrambler_reset) {
if (*lt_overrides->alternate_scrambler_reset)
@@ -1993,14 +2597,36 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
* Still shouldn't turn off dp_receiver (DPCD:600h)
*/
if (link_down == true) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct dc_link_settings link_settings = link->cur_link_settings;
+#endif
dp_disable_link_phy(link, link->connector_signal);
- dp_set_fec_ready(link, false);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
+#endif
+ dp_set_fec_ready(link, false);
}
link->sync_lt_in_progress = false;
return true;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+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;
+}
+#endif
+
bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
{
if (!max_link_enc_cap) {
@@ -2025,6 +2651,11 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link)
/* get max link encoder capability */
link->link_enc->funcs->get_max_link_cap(link->link_enc, &max_link_cap);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (max_link_cap.link_rate >= LINK_RATE_UHBR10 &&
+ !link->hpo_dp_link_enc)
+ max_link_cap.link_rate = LINK_RATE_HIGH3;
+#endif
/* Lower link settings based on sink's link cap */
if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
@@ -2045,8 +2676,15 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *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;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ enum dc_link_rate 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;
+#else
if (link->dpcd_caps.lttpr_caps.max_link_rate < max_link_cap.link_rate)
max_link_cap.link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
+#endif
DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",
__func__,
@@ -2205,6 +2843,10 @@ bool dp_verify_link_cap(
core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
+ reset_dp_hpo_stream_encoders_for_link(link);
+#endif
/* TODO implement override and monitor patch later */
/* try to train the link from high to low to
@@ -2360,7 +3002,17 @@ static struct dc_link_settings get_common_supported_link_settings(
* We map it to the maximum supported link rate that
* is smaller than MAX_LINK_BW in this case.
*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (link_settings.link_rate > LINK_RATE_UHBR20) {
+ link_settings.link_rate = LINK_RATE_UHBR20;
+ } else if (link_settings.link_rate < LINK_RATE_UHBR20 &&
+ link_settings.link_rate > LINK_RATE_UHBR13_5) {
+ link_settings.link_rate = LINK_RATE_UHBR13_5;
+ } else if (link_settings.link_rate < LINK_RATE_UHBR10 &&
+ link_settings.link_rate > LINK_RATE_HIGH3) {
+#else
if (link_settings.link_rate > LINK_RATE_HIGH3) {
+#endif
link_settings.link_rate = LINK_RATE_HIGH3;
} else if (link_settings.link_rate < LINK_RATE_HIGH3
&& link_settings.link_rate > LINK_RATE_HIGH2) {
@@ -2405,6 +3057,14 @@ static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
{
switch (link_rate) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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;
+#endif
case LINK_RATE_HIGH3:
return LINK_RATE_HIGH2;
case LINK_RATE_HIGH2:
@@ -2439,11 +3099,55 @@ static enum dc_link_rate increase_link_rate(enum dc_link_rate link_rate)
return LINK_RATE_HIGH2;
case LINK_RATE_HIGH2:
return LINK_RATE_HIGH3;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ case LINK_RATE_HIGH3:
+ return LINK_RATE_UHBR10;
+ case LINK_RATE_UHBR10:
+ return LINK_RATE_UHBR13_5;
+ case LINK_RATE_UHBR13_5:
+ return LINK_RATE_UHBR20;
+#endif
default:
return LINK_RATE_UNKNOWN;
}
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static bool decide_fallback_link_setting_max_bw_policy(
+ const struct dc_link_settings *max,
+ struct dc_link_settings *cur)
+{
+ uint8_t cur_idx = 0, next_idx;
+ bool found = 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)
+ break;
+ else
+ next_idx++;
+
+ 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;
+}
+#endif
+
/*
* function: set link rate and lane count fallback based
* on current link setting and last link training result
@@ -2459,6 +3163,11 @@ static bool decide_fallback_link_setting(
{
if (!current_link_setting)
return false;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&initial_link_settings) == DP_128b_132b_ENCODING)
+ return decide_fallback_link_setting_max_bw_policy(&initial_link_settings,
+ current_link_setting);
+#endif
switch (training_result) {
case LINK_TRAINING_CR_FAIL_LANE0:
@@ -2831,9 +3540,15 @@ 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;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ unsigned char test_pattern_buffer[
+ (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
+ DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
+#else
unsigned char test_pattern_buffer[
(DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
DP_TEST_80BIT_CUSTOM_PATTERN_7_0)+1] = {0};
+#endif
unsigned int test_pattern_size = 0;
enum dp_test_pattern test_pattern;
struct dc_link_training_settings link_settings;
@@ -2899,6 +3614,35 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
case PHY_TEST_PATTERN_CP2520_3:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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_PULSE:
+ test_pattern = DP_TEST_PATTERN_SQUARE_PULSE;
+ break;
+#endif
default:
test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
break;
@@ -2914,6 +3658,27 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
test_pattern_size);
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) {
+ 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);
+ }
+#endif
+
/* prepare link training settings */
link_settings.link = link->cur_link_settings;
@@ -2922,6 +3687,24 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
lane++) {
dpcd_lane_adjust.raw =
get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link->cur_link_settings) ==
+ DP_128b_132b_ENCODING) {
+ link_settings.lane_settings[lane].FFE_PRESET.raw =
+ dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
+ } else if (dp_get_link_encoding_format(&link->cur_link_settings) ==
+ DP_8b_10b_ENCODING) {
+ link_settings.lane_settings[lane].VOLTAGE_SWING =
+ (enum dc_voltage_swing)
+ (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
+ link_settings.lane_settings[lane].PRE_EMPHASIS =
+ (enum dc_pre_emphasis)
+ (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
+ link_settings.lane_settings[lane].POST_CURSOR2 =
+ (enum dc_post_cursor2)
+ ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
+ }
+#else
link_settings.lane_settings[lane].VOLTAGE_SWING =
(enum dc_voltage_swing)
(dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
@@ -2931,6 +3714,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
link_settings.lane_settings[lane].POST_CURSOR2 =
(enum dc_post_cursor2)
((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
+#endif
}
for (i = 0; i < 4; i++)
@@ -3535,6 +4319,43 @@ static void get_active_converter_info(
dp_hw_fw_revision.ieee_fw_rev,
sizeof(dp_hw_fw_revision.ieee_fw_rev));
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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);
+ }
+#endif
}
static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
@@ -3594,7 +4415,11 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
bool dp_retrieve_lttpr_cap(struct dc_link *link)
{
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint8_t lttpr_dpcd_data[8];
+#else
uint8_t lttpr_dpcd_data[6];
+#endif
bool vbios_lttpr_enable = link->dc->caps.vbios_lttpr_enable;
bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
enum dc_status status = DC_ERROR_UNEXPECTED;
@@ -3602,6 +4427,18 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data));
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ bool allow_lttpr_non_transparent_mode = 0;
+
+ if ((link->dc->config.allow_lttpr_non_transparent_mode.bits.DP2_0 &&
+ link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED)) {
+ allow_lttpr_non_transparent_mode = 1;
+ } else if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
+ !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
+ allow_lttpr_non_transparent_mode = 1;
+ }
+#endif
+
/*
* Logic to determine LTTPR mode
*/
@@ -3609,13 +4446,21 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
if (vbios_lttpr_enable && vbios_lttpr_interop)
link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
else if (!vbios_lttpr_enable && vbios_lttpr_interop) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (allow_lttpr_non_transparent_mode)
+#else
if (link->dc->config.allow_lttpr_non_transparent_mode)
+#endif
link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
else
link->lttpr_mode = LTTPR_MODE_TRANSPARENT;
} else if (!vbios_lttpr_enable && !vbios_lttpr_interop) {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (!allow_lttpr_non_transparent_mode || !link->dc->caps.extended_aux_timeout_support)
+#else
if (!link->dc->config.allow_lttpr_non_transparent_mode
|| !link->dc->caps.extended_aux_timeout_support)
+#endif
link->lttpr_mode = LTTPR_MODE_NON_LTTPR;
else
link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
@@ -3659,6 +4504,16 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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_128b_132b_RATES -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+#endif
+
/* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
is_lttpr_present = (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
@@ -3909,16 +4764,82 @@ static bool retrieve_link_cap(struct dc_link *link)
DP_DSC_SUPPORT,
link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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);
+ }
+#else
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));
+#endif
}
if (!dpcd_read_sink_ext_caps(link))
link->dpcd_sink_ext_caps.raw = 0;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ link->dpcd_caps.channel_coding_cap.raw = dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_CAP - DP_DPCD_REV];
+
+ 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_128b_132b_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");
+ }
+#endif
+
/* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
@@ -4389,6 +5310,35 @@ bool dc_link_dp_set_test_pattern(
case DP_TEST_PATTERN_CP2520_3:
pattern = PHY_TEST_PATTERN_CP2520_3;
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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_PULSE:
+ pattern = PHY_TEST_PATTERN_SQUARE_PULSE;
+ break;
+#endif
default:
return false;
}
@@ -4964,6 +5914,210 @@ enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings
if ((link_settings->link_rate >= LINK_RATE_LOW) &&
(link_settings->link_rate <= LINK_RATE_HIGH3))
return DP_8b_10b_ENCODING;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
+ (link_settings->link_rate <= LINK_RATE_UHBR20))
+ return DP_128b_132b_ENCODING;
+#endif
return DP_UNKNOWN_ENCODING;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+// 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;
+
+ if (status == NULL || status_updated == NULL) {
+ return;
+ }
+
+ uint8_t dpcd_buf[3] = {0};
+
+ 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 };
+
+ 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);
+ } else {
+ /// Leave req_slot_count = 0 if allocate is false.
+ }
+
+ union payload_table_update_status update_status = { 0 };
+
+ /// 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);
+
+ ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT); /// Validation should filter out modes that exceed link BW
+ 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)
+ const uint32_t max_retries = 30;
+ uint32_t retries = 0;
+
+ 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++;
+ udelay(5000);
+ }
+
+ 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
+ }
+
+ 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;
+
+ 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;
+
+ 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;
+ }
+
+ udelay(5000);
+ }
+
+ 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;
+}
+
+bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
+{
+ return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
+ pipe_ctx->stream->link->hpo_dp_link_enc &&
+ dc_is_dp_signal(pipe_ctx->stream->signal));
+}
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
index 9c51cd09dcf1..0d3800896333 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
@@ -17,6 +17,7 @@
#include "link_enc_cfg.h"
#include "clk_mgr.h"
#include "inc/link_dpcd.h"
+#include "dccg.h"
static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
{
@@ -111,12 +112,37 @@ void dp_enable_link_phy(
link->cur_link_settings = *link_settings;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ /* TODO - DP2.0 HW: notify link rate change here */
+ } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
+ if (dc->clk_mgr->funcs->notify_link_rate_change)
+ dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
+ }
+#else
if (dc->clk_mgr->funcs->notify_link_rate_change)
dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
-
+#endif
if (dmcu != NULL && dmcu->funcs->lock_phy)
dmcu->funcs->lock_phy(dmcu);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ enable_dp_hpo_output(link, link_settings);
+ } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
+ 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);
+ }
+ }
+#else
if (dc_is_dp_sst_signal(signal)) {
link_enc->funcs->enable_dp_output(
link_enc,
@@ -128,7 +154,7 @@ void dp_enable_link_phy(
link_settings,
clock_source);
}
-
+#endif
if (dmcu != NULL && dmcu->funcs->unlock_phy)
dmcu->funcs->unlock_phy(dmcu);
@@ -206,6 +232,9 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
{
struct dc *dc = link->ctx->dc;
struct dmcu *dmcu = dc->res_pool->dmcu;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct hpo_dp_link_encoder *hpo_link_enc = link->hpo_dp_link_enc;
+#endif
struct link_encoder *link_enc;
/* Link should always be assigned encoder when en-/disabling. */
@@ -221,14 +250,28 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
if (signal == SIGNAL_TYPE_EDP) {
if (link->dc->hwss.edp_backlight_control)
link->dc->hwss.edp_backlight_control(link, false);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
+ disable_dp_hpo_output(link, signal);
+ else
+ link_enc->funcs->disable_output(link_enc, signal);
+#else
link_enc->funcs->disable_output(link_enc, signal);
+#endif
link->dc->hwss.edp_power_control(link, false);
} else {
if (dmcu != NULL && dmcu->funcs->lock_phy)
dmcu->funcs->lock_phy(dmcu);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING &&
+ hpo_link_enc)
+ disable_dp_hpo_output(link, signal);
+ else
+ link_enc->funcs->disable_output(link_enc, signal);
+#else
link_enc->funcs->disable_output(link_enc, signal);
-
+#endif
if (dmcu != NULL && dmcu->funcs->unlock_phy)
dmcu->funcs->unlock_phy(dmcu);
}
@@ -273,6 +316,14 @@ bool dp_set_hw_training_pattern(
case DP_TRAINING_PATTERN_SEQUENCE_4:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
break;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ 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;
+#endif
default:
break;
}
@@ -282,6 +333,10 @@ bool dp_set_hw_training_pattern(
return true;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+#define DC_LOGGER \
+ link->ctx->logger
+#endif
void dp_set_hw_lane_settings(
struct dc_link *link,
const struct link_training_settings *link_settings,
@@ -293,7 +348,20 @@ void dp_set_hw_lane_settings(
return;
/* call Encoder to set lane settings */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dp_get_link_encoding_format(&link_settings->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ link->hpo_dp_link_enc->funcs->set_ffe(
+ link->hpo_dp_link_enc,
+ &link_settings->link_settings,
+ link_settings->lane_settings[0].FFE_PRESET.raw);
+ } else if (dp_get_link_encoding_format(&link_settings->link_settings)
+ == DP_8b_10b_ENCODING) {
+ encoder->funcs->dp_set_lane_settings(encoder, link_settings);
+ }
+#else
encoder->funcs->dp_set_lane_settings(encoder, link_settings);
+#endif
}
void dp_set_hw_test_pattern(
@@ -319,8 +387,28 @@ void dp_set_hw_test_pattern(
pattern_param.custom_pattern_size = custom_pattern_size;
pattern_param.dp_panel_mode = dp_get_panel_mode(link);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ enum dp_link_encoding link_encoding_format = dp_get_link_encoding_format(&link->cur_link_settings);
+ switch (link_encoding_format) {
+ case DP_128b_132b_ENCODING:
+ link->hpo_dp_link_enc->funcs->set_link_test_pattern(
+ link->hpo_dp_link_enc, &pattern_param);
+ break;
+ case DP_8b_10b_ENCODING:
+ ASSERT(encoder);
+ encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
+ break;
+ default:
+ DC_LOG_ERROR("%s: Unknown link encoding format.", __func__);
+ break;
+ }
+#else
encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
+#endif
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+#undef DC_LOGGER
+#endif
void dp_retrain_link_dp_test(struct dc_link *link,
struct dc_link_settings *link_setting,
@@ -468,7 +556,12 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
/* Enable DSC in encoder */
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
+ && !is_dp_128b_132b_signal(pipe_ctx)) {
+#else
if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+#endif
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,
@@ -495,13 +588,21 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
/* disable DSC in stream encoder */
if (dc_is_dp_signal(stream->signal)) {
- 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);
- }
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (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);
+ else
+#endif
+ 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);
+ }
}
/* disable DSC block */
@@ -562,16 +663,32 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable)
dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
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);
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc,
- true,
- &dsc_packed_pps[0]);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (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]);
+ else
+#endif
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc,
+ true,
+ &dsc_packed_pps[0]);
}
} else {
/* disable DSC PPS in stream encoder */
if (dc_is_dp_signal(stream->signal)) {
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc, false, NULL);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (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);
+ else
+#endif
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL);
}
}
@@ -593,3 +710,168 @@ bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
return true;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+#undef DC_LOGGER
+#define DC_LOGGER \
+ link->ctx->logger
+
+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;
+ }
+
+ //BREAK_TO_DEBUGGER();
+ return TRANSMITTER_UNIPHY_A;
+}
+
+void enable_dp_hpo_output(struct dc_link *link, const struct dc_link_settings *link_settings)
+{
+ const struct dc *dc = link->dc;
+ enum phyd32clk_clock_source phyd32clk;
+
+ /* Enable PHY PLL at target bit rate
+ * UHBR10 = 10Gbps (SYMCLK32 = 312.5MHz)
+ * UBR13.5 = 13.5Gbps (SYMCLK32 = 421.875MHz)
+ * UHBR20 = 20Gbps (SYMCLK32 = 625MHz)
+ */
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ switch (link_settings->link_rate) {
+ case LINK_RATE_UHBR10:
+ dm_set_phyd32clk(dc->ctx, 312500);
+ break;
+ case LINK_RATE_UHBR13_5:
+ dm_set_phyd32clk(dc->ctx, 412875);
+ break;
+ case LINK_RATE_UHBR20:
+ dm_set_phyd32clk(dc->ctx, 625000);
+ break;
+ default:
+ return;
+ }
+ } else {
+ /* DP2.0 HW: call transmitter control to enable PHY */
+ link->hpo_dp_link_enc->funcs->enable_link_phy(
+ link->hpo_dp_link_enc,
+ link_settings,
+ link->link_enc->transmitter);
+ }
+
+ /* DCCG muxing and DTBCLK DTO */
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ dc->res_pool->dccg->funcs->set_physymclk(
+ dc->res_pool->dccg,
+ link->link_enc_hw_inst,
+ PHYSYMCLK_FORCE_SRC_PHYD32CLK,
+ true);
+
+ phyd32clk = get_phyd32clk_src(link);
+ dc->res_pool->dccg->funcs->enable_symclk32_le(
+ dc->res_pool->dccg,
+ link->hpo_dp_link_enc->inst,
+ phyd32clk);
+ link->hpo_dp_link_enc->funcs->link_enable(
+ link->hpo_dp_link_enc,
+ link_settings->lane_count);
+ }
+}
+
+void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal)
+{
+ const struct dc *dc = link->dc;
+
+ link->hpo_dp_link_enc->funcs->link_disable(link->hpo_dp_link_enc);
+
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ dc->res_pool->dccg->funcs->disable_symclk32_le(
+ dc->res_pool->dccg,
+ link->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);
+ } else {
+ /* DP2.0 HW: call transmitter control to disable PHY */
+ link->hpo_dp_link_enc->funcs->disable_link_phy(
+ link->hpo_dp_link_enc,
+ signal);
+ }
+}
+
+void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct pipe_ctx *odm_pipe;
+ int odm_combine_num_segments = 1;
+ enum phyd32clk_clock_source phyd32clk;
+
+ if (enable) {
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ odm_combine_num_segments++;
+
+ dc->res_pool->dccg->funcs->set_dpstreamclk(
+ dc->res_pool->dccg,
+ DTBCLK0,
+ pipe_ctx->stream_res.tg->inst);
+
+ phyd32clk = get_phyd32clk_src(stream->link);
+ dc->res_pool->dccg->funcs->enable_symclk32_se(
+ dc->res_pool->dccg,
+ pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
+ phyd32clk);
+
+ dc->res_pool->dccg->funcs->set_dtbclk_dto(
+ dc->res_pool->dccg,
+ pipe_ctx->stream_res.tg->inst,
+ stream->phy_pix_clk,
+ odm_combine_num_segments,
+ &stream->timing);
+ } else {
+ dc->res_pool->dccg->funcs->set_dtbclk_dto(
+ dc->res_pool->dccg,
+ pipe_ctx->stream_res.tg->inst,
+ 0,
+ 0,
+ &stream->timing);
+ dc->res_pool->dccg->funcs->disable_symclk32_se(
+ dc->res_pool->dccg,
+ pipe_ctx->stream_res.hpo_dp_stream_enc->inst);
+ dc->res_pool->dccg->funcs->set_dpstreamclk(
+ dc->res_pool->dccg,
+ REFCLK,
+ pipe_ctx->stream_res.tg->inst);
+ }
+}
+
+void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link)
+{
+ const struct dc *dc = link->dc;
+ struct dc_state *state = dc->current_state;
+ uint8_t i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc &&
+ state->res_ctx.pipe_ctx[i].stream &&
+ state->res_ctx.pipe_ctx[i].stream->link == link &&
+ !state->res_ctx.pipe_ctx[i].stream->dpms_off) {
+ setup_dp_hpo_stream(&state->res_ctx.pipe_ctx[i], false);
+ }
+ }
+}
+
+#undef DC_LOGGER
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index a60396d5be44..57420bf10786 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -41,6 +41,7 @@
#include "set_mode_types.h"
#include "virtual/virtual_stream_encoder.h"
#include "dpcd_defs.h"
+#include "dc_link_dp.h"
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
@@ -346,6 +347,29 @@ bool resource_construct(
}
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ pool->hpo_dp_stream_enc_count = 0;
+ if (create_funcs->create_hpo_dp_stream_encoder) {
+ for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
+ pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
+ if (pool->hpo_dp_stream_enc[i] == NULL)
+ DC_ERR("DC: failed to create HPO DP stream encoder!\n");
+ pool->hpo_dp_stream_enc_count++;
+
+ }
+ }
+
+ pool->hpo_dp_link_enc_count = 0;
+ if (create_funcs->create_hpo_dp_link_encoder) {
+ for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
+ pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
+ if (pool->hpo_dp_link_enc[i] == NULL)
+ DC_ERR("DC: failed to create HPO DP link encoder!\n");
+ pool->hpo_dp_link_enc_count++;
+ }
+ }
+#endif
+
#if defined(CONFIG_DRM_AMD_DC_DCN)
for (i = 0; i < caps->num_mpc_3dlut; i++) {
pool->mpc_lut[i] = dc_create_3dlut_func();
@@ -1665,6 +1689,22 @@ static void update_stream_engine_usage(
}
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static void update_hpo_dp_stream_engine_usage(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
+ bool acquired)
+{
+ int i;
+
+ for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
+ if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
+ res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
+ }
+}
+#endif
+
/* TODO: release audio object */
void update_audio_usage(
struct resource_context *res_ctx,
@@ -1709,6 +1749,26 @@ static int acquire_first_free_pipe(
return -1;
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct dc_stream_state *stream)
+{
+ int i;
+
+ for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
+ if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
+ pool->hpo_dp_stream_enc[i]) {
+
+ return pool->hpo_dp_stream_enc[i];
+ }
+ }
+
+ return NULL;
+}
+#endif
+
static struct audio *find_first_free_audio(
struct resource_context *res_ctx,
const struct resource_pool *pool,
@@ -1799,6 +1859,15 @@ enum dc_status dc_remove_stream_from_ctx(
if (dc->res_pool->funcs->link_enc_unassign)
dc->res_pool->funcs->link_enc_unassign(new_ctx, del_pipe->stream);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(del_pipe)) {
+ update_hpo_dp_stream_engine_usage(
+ &new_ctx->res_ctx, dc->res_pool,
+ del_pipe->stream_res.hpo_dp_stream_enc,
+ false);
+ }
+#endif
+
if (del_pipe->stream_res.audio)
update_audio_usage(
&new_ctx->res_ctx,
@@ -2051,6 +2120,31 @@ enum dc_status resource_map_pool_resources(
pipe_ctx->stream_res.stream_enc,
true);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* Allocate DP HPO Stream Encoder based on signal, hw capabilities
+ * and link settings
+ */
+ if (dc_is_dp_signal(stream->signal) &&
+ dc->caps.dp_hpo) {
+ struct dc_link_settings link_settings = {0};
+
+ decide_link_settings(stream, &link_settings);
+ if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc =
+ find_first_free_match_hpo_dp_stream_enc_for_link(
+ &context->res_ctx, pool, stream);
+
+ if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
+ return DC_NO_STREAM_ENC_RESOURCE;
+
+ update_hpo_dp_stream_engine_usage(
+ &context->res_ctx, pool,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ true);
+ }
+ }
+#endif
+
/* TODO: Add check if ASIC support and EDID audio */
if (!stream->converter_disable_audio &&
dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
@@ -2726,6 +2820,11 @@ bool pipe_need_reprogram(
if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
return true;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
+ return true;
+#endif
+
/* DIG link encoder resource assignment for stream changed. */
if (pipe_ctx_old->stream->link_enc != pipe_ctx->stream->link_enc)
return true;
@@ -2975,3 +3074,22 @@ void get_audio_check(struct audio_info *aud_modes,
}
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
+ const struct resource_pool *pool)
+{
+ uint8_t i;
+ struct hpo_dp_link_encoder *enc = NULL;
+
+ ASSERT(pool->hpo_dp_link_enc_count <= MAX_HPO_DP2_LINK_ENCODERS);
+
+ for (i = 0; i < pool->hpo_dp_link_enc_count; i++) {
+ if (pool->hpo_dp_link_enc[i]->transmitter == TRANSMITTER_UNKNOWN) {
+ enc = pool->hpo_dp_link_enc[i];
+ break;
+ }
+ }
+
+ return enc;
+}
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 03b81e5c5d67..19114cd3abf6 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -183,6 +183,9 @@ struct dc_caps {
unsigned int cursor_cache_size;
struct dc_plane_cap planes[MAX_PLANES];
struct dc_color_caps color;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ bool dp_hpo;
+#endif
bool vbios_lttpr_aware;
bool vbios_lttpr_enable;
};
@@ -289,7 +292,15 @@ struct dc_cap_funcs {
struct link_training_settings;
-
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+union allow_lttpr_non_transparent_mode {
+ struct {
+ bool DP1_4A : 1;
+ bool DP2_0 : 1;
+ } bits;
+ unsigned char raw;
+};
+#endif
/* Structure to hold configuration flags set by dm at dc creation. */
struct dc_config {
bool gpu_vm_support;
@@ -302,7 +313,11 @@ struct dc_config {
bool edp_no_power_sequencing;
bool force_enum_edp;
bool forced_clocks;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ union allow_lttpr_non_transparent_mode allow_lttpr_non_transparent_mode;
+#else
bool allow_lttpr_non_transparent_mode;
+#endif
bool multi_mon_pp_mclk_switch;
bool disable_dmcu;
bool enable_4to1MPC;
@@ -614,6 +629,10 @@ struct dc_debug_options {
bool enable_dmcub_surface_flip;
bool usbc_combo_phy_reset_wa;
bool enable_dram_clock_change_one_display_vactive;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* TODO - remove once tested */
+ bool legacy_dp2_lt;
+#endif
union mem_low_power_enable_options enable_mem_low_power;
bool force_vblank_alignment;
@@ -1146,6 +1165,12 @@ struct dpcd_caps {
struct dc_lttpr_caps lttpr_caps;
struct psr_caps psr_caps;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ union dp_128b_132b_supported_link_rates dp_128b_132b_supported_link_rates;
+ union dp_main_line_channel_coding_cap channel_coding_cap;
+ union dp_sink_video_fallback_formats fallback_formats;
+ union dp_fec_capability1 fec_cap1;
+#endif
};
union dpcd_sink_ext_caps {
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 4f54bde1bb1c..a5e798b5da79 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -53,7 +53,17 @@ enum dc_link_rate {
LINK_RATE_RBR2 = 0x0C, // Rate_5 (RBR2)- 3.24 Gbps/Lane
LINK_RATE_RATE_6 = 0x10, // Rate_6 - 4.32 Gbps/Lane
LINK_RATE_HIGH2 = 0x14, // Rate_7 (HBR2)- 5.40 Gbps/Lane
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ LINK_RATE_HIGH3 = 0x1E, // Rate_8 (HBR3)- 8.10 Gbps/Lane
+ /* Starting from DP2.0 link rate enum directly represents actual
+ * link rate value in unit of 10 mbps
+ */
+ LINK_RATE_UHBR10 = 1000, // UHBR10 - 10.0 Gbps/Lane
+ LINK_RATE_UHBR13_5 = 1350, // UHBR13.5 - 13.5 Gbps/Lane
+ LINK_RATE_UHBR20 = 2000, // UHBR10 - 20.0 Gbps/Lane
+#else
LINK_RATE_HIGH3 = 0x1E // Rate_8 (HBR3)- 8.10 Gbps/Lane
+#endif
};
enum dc_link_spread {
@@ -90,17 +100,47 @@ enum dc_post_cursor2 {
POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3,
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+enum dc_dp_ffe_preset_level {
+ DP_FFE_PRESET_LEVEL0 = 0,
+ DP_FFE_PRESET_LEVEL1,
+ DP_FFE_PRESET_LEVEL2,
+ DP_FFE_PRESET_LEVEL3,
+ DP_FFE_PRESET_LEVEL4,
+ DP_FFE_PRESET_LEVEL5,
+ DP_FFE_PRESET_LEVEL6,
+ DP_FFE_PRESET_LEVEL7,
+ DP_FFE_PRESET_LEVEL8,
+ DP_FFE_PRESET_LEVEL9,
+ DP_FFE_PRESET_LEVEL10,
+ DP_FFE_PRESET_LEVEL11,
+ DP_FFE_PRESET_LEVEL12,
+ DP_FFE_PRESET_LEVEL13,
+ DP_FFE_PRESET_LEVEL14,
+ DP_FFE_PRESET_LEVEL15,
+ DP_FFE_PRESET_MAX_LEVEL = DP_FFE_PRESET_LEVEL15,
+};
+#endif
+
enum dc_dp_training_pattern {
DP_TRAINING_PATTERN_SEQUENCE_1 = 0,
DP_TRAINING_PATTERN_SEQUENCE_2,
DP_TRAINING_PATTERN_SEQUENCE_3,
DP_TRAINING_PATTERN_SEQUENCE_4,
DP_TRAINING_PATTERN_VIDEOIDLE,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DP_128b_132b_TPS1,
+ DP_128b_132b_TPS2,
+ DP_128b_132b_TPS2_CDS,
+#endif
};
enum dp_link_encoding {
DP_UNKNOWN_ENCODING = 0,
DP_8b_10b_ENCODING = 1,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DP_128b_132b_ENCODING = 2,
+#endif
};
struct dc_link_settings {
@@ -112,10 +152,26 @@ struct dc_link_settings {
bool dpcd_source_device_specific_field_support;
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+union dc_dp_ffe_preset {
+ struct {
+ uint8_t level : 4;
+ uint8_t reserved : 1;
+ uint8_t no_preshoot : 1;
+ uint8_t no_deemphasis : 1;
+ uint8_t method2 : 1;
+ } settings;
+ uint8_t raw;
+};
+#endif
+
struct dc_lane_settings {
enum dc_voltage_swing VOLTAGE_SWING;
enum dc_pre_emphasis PRE_EMPHASIS;
enum dc_post_cursor2 POST_CURSOR2;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ union dc_dp_ffe_preset FFE_PRESET;
+#endif
};
struct dc_link_training_settings {
@@ -127,6 +183,9 @@ struct dc_link_training_overrides {
enum dc_voltage_swing *voltage_swing;
enum dc_pre_emphasis *pre_emphasis;
enum dc_post_cursor2 *post_cursor2;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ union dc_dp_ffe_preset *ffe_preset;
+#endif
uint16_t *cr_pattern_time;
uint16_t *eq_pattern_time;
@@ -140,6 +199,16 @@ struct dc_link_training_overrides {
bool *fec_enable;
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+union payload_table_update_status {
+ struct {
+ uint8_t VC_PAYLOAD_TABLE_UPDATED:1;
+ uint8_t ACT_HANDLED:1;
+ } bits;
+ uint8_t raw;
+};
+#endif
+
union dpcd_rev {
struct {
uint8_t MINOR:4;
@@ -227,7 +296,14 @@ union lane_align_status_updated {
struct {
uint8_t INTERLANE_ALIGN_DONE:1;
uint8_t POST_LT_ADJ_REQ_IN_PROGRESS:1;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint8_t EQ_INTERLANE_ALIGN_DONE_128b_132b:1;
+ uint8_t CDS_INTERLANE_ALIGN_DONE_128b_132b:1;
+ uint8_t LT_FAILED_128b_132b:1;
+ uint8_t RESERVED:1;
+#else
uint8_t RESERVED:4;
+#endif
uint8_t DOWNSTREAM_PORT_STATUS_CHANGED:1;
uint8_t LINK_STATUS_UPDATED:1;
} bits;
@@ -240,6 +316,12 @@ union lane_adjust {
uint8_t PRE_EMPHASIS_LANE:2;
uint8_t RESERVED:4;
} bits;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct {
+ uint8_t PRESET_VALUE :4;
+ uint8_t RESERVED :4;
+ } tx_ffe;
+#endif
uint8_t raw;
};
@@ -269,6 +351,12 @@ union dpcd_training_lane {
uint8_t MAX_PRE_EMPHASIS_REACHED:1;
uint8_t RESERVED:2;
} bits;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct {
+ uint8_t PRESET_VALUE :4;
+ uint8_t RESERVED :4;
+ } tx_ffe;
+#endif
uint8_t raw;
};
@@ -551,12 +639,18 @@ union test_response {
union phy_test_pattern {
struct {
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* This field is 7 bits for DP2.0 */
+ uint8_t PATTERN :7;
+ uint8_t RESERVED :1;
+#else
/* DpcdPhyTestPatterns. This field is 2 bits for DP1.1
* and 3 bits for DP1.2.
*/
uint8_t PATTERN :3;
/* BY speci, bit7:2 is 0 for DP1.1. */
uint8_t RESERVED :5;
+#endif
} bits;
uint8_t raw;
};
@@ -634,7 +728,14 @@ union dpcd_fec_capability {
uint8_t UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
uint8_t CORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
uint8_t BIT_ERROR_COUNT_CAPABLE:1;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint8_t PARITY_BLOCK_ERROR_COUNT_CAPABLE:1;
+ uint8_t ARITY_BIT_ERROR_COUNT_CAPABLE:1;
+ uint8_t FEC_RUNNING_INDICATOR_SUPPORTED:1;
+ uint8_t FEC_ERROR_REPORTING_POLICY_SUPPORTED:1;
+#else
uint8_t RESERVED:4;
+#endif
} bits;
uint8_t raw;
};
@@ -758,4 +859,125 @@ struct psr_caps {
bool psr_exit_link_training_required;
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+#define DP_MAIN_LINK_CHANNEL_CODING_CAP 0x006
+#define DP_SINK_VIDEO_FALLBACK_FORMATS 0x020
+#define DP_FEC_CAPABILITY_1 0x091
+#define DP_DFP_CAPABILITY_EXTENSION_SUPPORT 0x0A3
+#define DP_DSC_CONFIGURATION 0x161
+#define DP_PHY_SQUARE_PATTERN 0x249
+#define DP_128b_132b_SUPPORTED_LINK_RATES 0x2215
+#define DP_128b_132b_TRAINING_AUX_RD_INTERVAL 0x2216
+#define DP_TEST_264BIT_CUSTOM_PATTERN_7_0 0X2230
+#define DP_TEST_264BIT_CUSTOM_PATTERN_263_256 0X2250
+#define DP_DSC_SUPPORT_AND_DECODER_COUNT 0x2260
+#define DP_DSC_MAX_SLICE_COUNT_AND_AGGREGATION_0 0x2270
+# define DP_DSC_DECODER_0_MAXIMUM_SLICE_COUNT_MASK (1 << 0)
+# define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_MASK (0b111 << 1)
+# define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_SHIFT 1
+# define DP_DSC_DECODER_COUNT_MASK (0b111 << 5)
+# define DP_DSC_DECODER_COUNT_SHIFT 5
+#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108
+#define DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER 0xF0006
+#define DP_PHY_REPEATER_128b_132b_RATES 0xF0007
+#define DP_128b_132b_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xF0022
+#define DP_INTRA_HOP_AUX_REPLY_INDICATION (1 << 3)
+/* TODO - Use DRM header to replace above once available */
+
+union dp_main_line_channel_coding_cap {
+ struct {
+ uint8_t DP_8b_10b_SUPPORTED :1;
+ uint8_t DP_128b_132b_SUPPORTED :1;
+ uint8_t RESERVED :6;
+ } bits;
+ uint8_t raw;
+};
+
+union dp_main_link_channel_coding_lttpr_cap {
+ struct {
+ uint8_t DP_128b_132b_SUPPORTED :1;
+ uint8_t RESERVED :7;
+ } bits;
+ uint8_t raw;
+};
+
+union dp_128b_132b_supported_link_rates {
+ struct {
+ uint8_t UHBR10 :1;
+ uint8_t UHBR20 :1;
+ uint8_t UHBR13_5:1;
+ uint8_t RESERVED:5;
+ } bits;
+ uint8_t raw;
+};
+
+union dp_128b_132b_supported_lttpr_link_rates {
+ struct {
+ uint8_t UHBR10 :1;
+ uint8_t UHBR13_5:1;
+ uint8_t UHBR20 :1;
+ uint8_t RESERVED:5;
+ } bits;
+ uint8_t raw;
+};
+
+union dp_sink_video_fallback_formats {
+ struct {
+ uint8_t dp_1024x768_60Hz_24bpp_support :1;
+ uint8_t dp_1280x720_60Hz_24bpp_support :1;
+ uint8_t dp_1920x1080_60Hz_24bpp_support :1;
+ uint8_t RESERVED :5;
+ } bits;
+ uint8_t raw;
+};
+
+union dp_fec_capability1 {
+ struct {
+ uint8_t AGGREGATED_ERROR_COUNTERS_CAPABLE :1;
+ uint8_t RESERVED :7;
+ } bits;
+ uint8_t raw;
+};
+
+struct dp_color_depth_caps {
+ uint8_t support_6bpc :1;
+ uint8_t support_8bpc :1;
+ uint8_t support_10bpc :1;
+ uint8_t support_12bpc :1;
+ uint8_t support_16bpc :1;
+ uint8_t RESERVED :3;
+};
+
+struct dp_encoding_format_caps {
+ uint8_t support_rgb :1;
+ uint8_t support_ycbcr444:1;
+ uint8_t support_ycbcr422:1;
+ uint8_t support_ycbcr420:1;
+ uint8_t RESERVED :4;
+};
+
+union dp_dfp_cap_ext {
+ struct {
+ uint8_t supported;
+ uint8_t max_pixel_rate_in_mps[2];
+ uint8_t max_video_h_active_width[2];
+ uint8_t max_video_v_active_height[2];
+ struct dp_encoding_format_caps encoding_format_caps;
+ struct dp_color_depth_caps rgb_color_depth_caps;
+ struct dp_color_depth_caps ycbcr444_color_depth_caps;
+ struct dp_color_depth_caps ycbcr422_color_depth_caps;
+ struct dp_color_depth_caps ycbcr420_color_depth_caps;
+ } fields;
+ uint8_t raw[12];
+};
+
+union dp_128b_132b_training_aux_rd_interval {
+ struct {
+ uint8_t VALUE :7;
+ uint8_t UNIT :1;
+ } bits;
+ uint8_t raw;
+};
+#endif
+
#endif /* DC_DP_TYPES_H */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 4450078213a2..4fdb24ba24af 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -154,6 +154,9 @@ struct dc_link {
struct panel_cntl *panel_cntl;
struct link_encoder *link_enc;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct hpo_dp_link_encoder *hpo_dp_link_enc;
+#endif
struct graphics_object_id link_id;
/* Endpoint type distinguishes display endpoints which do not have entries
* in the BIOS connector table from those that do. Helps when tracking link
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index c1532930169b..3c109c805447 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -395,9 +395,27 @@ struct dc_lttpr_caps {
uint8_t max_link_rate;
uint8_t phy_repeater_cnt;
uint8_t max_ext_timeout;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
+ union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
+#endif
uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
};
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+struct dc_dongle_dfp_cap_ext {
+ bool supported;
+ uint16_t max_pixel_rate_in_mps;
+ uint16_t max_video_h_active_width;
+ uint16_t max_video_v_active_height;
+ struct dp_encoding_format_caps encoding_format_caps;
+ struct dp_color_depth_caps rgb_color_depth_caps;
+ struct dp_color_depth_caps ycbcr444_color_depth_caps;
+ struct dp_color_depth_caps ycbcr422_color_depth_caps;
+ struct dp_color_depth_caps ycbcr420_color_depth_caps;
+};
+#endif
+
struct dc_dongle_caps {
/* dongle type (DP converter, CV smart dongle) */
enum display_dongle_type dongle_type;
@@ -411,6 +429,9 @@ struct dc_dongle_caps {
bool is_dp_hdmi_ycbcr420_converter;
uint32_t dp_hdmi_max_bpc;
uint32_t dp_hdmi_max_pixel_clk_in_khz;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ struct dc_dongle_dfp_cap_ext dfp_cap_ext;
+#endif
};
/* Scaling format */
enum scaling_transformation {
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
index 62d595ded866..33743dc2631c 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -1108,8 +1108,17 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
clk_mgr->funcs->enable_pme_wa(clk_mgr);
/* un-mute audio */
/* TODO: audio should be per stream rather than per link */
- pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_res.hpo_dp_stream_enc, false);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, false);
+#else
+ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_res.stream_enc, false);
+#endif
if (pipe_ctx->stream_res.audio)
pipe_ctx->stream_res.audio->enabled = true;
}
@@ -1129,14 +1138,32 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false)
return;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_res.hpo_dp_stream_enc, true);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_res.stream_enc, true);
+#else
pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, true);
+#endif
if (pipe_ctx->stream_res.audio) {
pipe_ctx->stream_res.audio->enabled = false;
if (dc_is_dp_signal(pipe_ctx->stream->signal))
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
+ pipe_ctx->stream_res.stream_enc);
+#else
pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
pipe_ctx->stream_res.stream_enc);
+#endif
else
pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
pipe_ctx->stream_res.stream_enc);
@@ -1166,16 +1193,37 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc);
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal))
+#else
if (dc_is_dp_signal(pipe_ctx->stream->signal))
+#endif
pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets(
pipe_ctx->stream_res.stream_enc);
dc->hwss.disable_audio_stream(pipe_ctx);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->disable(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ setup_dp_hpo_stream(pipe_ctx, false);
+ /* TODO - DP2.0 HW: unmap stream from link encoder here */
+ } else {
+ link->link_enc->funcs->connect_dig_be_to_fe(
+ link->link_enc,
+ pipe_ctx->stream_res.stream_enc->id,
+ false);
+ }
+#else
link->link_enc->funcs->connect_dig_be_to_fe(
link->link_enc,
pipe_ctx->stream_res.stream_enc->id,
false);
+#endif
}
@@ -1210,7 +1258,15 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
}
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+#else
if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+#endif
pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) {
@@ -1451,10 +1507,23 @@ static enum dc_status apply_single_controller_ctx_to_hw(
build_audio_output(context, pipe_ctx, &audio_output);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ pipe_ctx->stream_res.audio->inst,
+ &pipe_ctx->stream->audio_info);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.audio->inst,
+ &pipe_ctx->stream->audio_info);
+#else
pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
pipe_ctx->stream_res.stream_enc,
pipe_ctx->stream_res.audio->inst,
&pipe_ctx->stream->audio_info);
+#endif
else
pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
pipe_ctx->stream_res.stream_enc,
@@ -1469,10 +1538,17 @@ static enum dc_status apply_single_controller_ctx_to_hw(
&pipe_ctx->stream->audio_info);
}
- /* */
- /* Do not touch stream timing on seamless boot optimization. */
- if (!pipe_ctx->stream->apply_seamless_boot_optimization)
- hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (!(hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)))
+ /* */
+ /* Do not touch stream timing on seamless boot optimization. */
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
+ hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
if (hws->funcs.setup_vupdate_interrupt)
hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
@@ -1482,6 +1558,12 @@ static enum dc_status apply_single_controller_ctx_to_hw(
if (pipe_ctx->stream_res.tg->funcs->set_drr)
pipe_ctx->stream_res.tg->funcs->set_drr(
pipe_ctx->stream_res.tg, ¶ms);
+#else
+ /* */
+ /* Do not touch stream timing on seamless boot optimization. */
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
+ hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
+#endif
// DRR should set trigger event to monitor surface update event
if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
@@ -1526,6 +1608,18 @@ static enum dc_status apply_single_controller_ctx_to_hw(
if (!stream->dpms_off)
core_link_enable_stream(context, pipe_ctx);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)) {
+ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
+ hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
+ }
+#endif
+
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
index e4701825b5a0..2dc4b4e4ba02 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
@@ -1460,5 +1460,14 @@ void dcn10_link_encoder_get_max_link_cap(struct link_encoder *enc,
if (enc->features.flags.bits.IS_HBR3_CAPABLE)
max_link_cap.link_rate = LINK_RATE_HIGH3;
+ if (enc->features.flags.bits.IS_UHBR10_CAPABLE)
+ max_link_cap.link_rate = LINK_RATE_UHBR10;
+
+ if (enc->features.flags.bits.IS_UHBR13_5_CAPABLE)
+ max_link_cap.link_rate = LINK_RATE_UHBR13_5;
+
+ if (enc->features.flags.bits.IS_UHBR20_CAPABLE)
+ max_link_cap.link_rate = LINK_RATE_UHBR20;
+
*link_settings = max_link_cap;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index a47ba1d45be9..b9276da87872 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -2135,7 +2135,12 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
params.link_settings.link_rate = link_settings->link_rate;
- if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ pipe_ctx->stream_res.tg->inst);
+ } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1)
params.timing.pix_clk_100hz /= 2;
pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
@@ -2380,8 +2385,19 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
* disconnect them during disable_stream
* BY this, it is logic clean to separate stream and link
*/
- link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
- pipe_ctx->stream_res.stream_enc->id, true);
+ if (is_dp_128b_132b_signal(pipe_ctx)) {
+ setup_dp_hpo_stream(pipe_ctx, true);
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->enable_stream(
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->map_stream_to_link(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
+ link->hpo_dp_link_enc->inst);
+ }
+
+ if (!is_dp_128b_132b_signal(pipe_ctx))
+ link->link_enc->funcs->connect_dig_be_to_fe(
+ link->link_enc, pipe_ctx->stream_res.stream_enc->id, true);
if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
if (link->dc->hwss.program_dmdata_engine)
@@ -2406,7 +2422,9 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
/* enable audio only within mode set */
if (pipe_ctx->stream_res.audio != NULL) {
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.hpo_dp_stream_enc);
+ else 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);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
index e3e01b17c164..0159700c148a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
@@ -63,6 +63,7 @@
#include "dcn20_dccg.h"
#include "dcn20_vmid.h"
#include "dc_link_ddc.h"
+#include "dc_link_dp.h"
#include "dce/dce_panel_cntl.h"
#include "navi10_ip_offset.h"
@@ -1604,6 +1605,7 @@ static void get_pixel_clock_parameters(
pixel_clk_params->signal_type = pipe_ctx->stream->signal;
pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1;
/* TODO: un-hardcode*/
+ /* TODO - DP2.0 HW: calculate requested_sym_clk for UHBR rates */
pixel_clk_params->requested_sym_clk = LINK_RATE_LOW *
LINK_RATE_REF_FREQ_IN_KHZ;
pixel_clk_params->flags.ENABLE_SS = 0;
@@ -3044,6 +3046,8 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (!context->res_ctx.pipe_ctx[i].stream)
continue;
+ if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
+ return true;
}
return false;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index f264a32ebade..463e96f8f14c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -561,11 +561,6 @@ static const struct dcn10_link_enc_mask le_mask = {
DPCS_DCN31_MASK_SH_LIST(_MASK)
};
-#define dpp_regs(id)\
-[id] = {\
- DPP_REG_LIST_DCN30(id),\
-}
-
#define hpo_dp_stream_encoder_reg_list(id)\
[id] = {\
DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\
@@ -609,6 +604,11 @@ static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {
DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)
};
+#define dpp_regs(id)\
+[id] = {\
+ DPP_REG_LIST_DCN30(id),\
+}
+
static const struct dcn3_dpp_registers dpp_regs[] = {
dpp_regs(0),
dpp_regs(1),
@@ -1449,6 +1449,13 @@ static struct dce_hwseq *dcn31_hwseq_create(
hws->regs = &hwseq_reg;
hws->shifts = &hwseq_shift;
hws->masks = &hwseq_mask;
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
+ hws->wa.dp_hpo_and_otg_sequence = true;
}
return hws;
}
@@ -2102,6 +2109,7 @@ static bool dcn31_resource_construct(
dc->caps.max_slave_rgb_planes = 1;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
+ dc->caps.dp_hpo = true;
dc->caps.extended_aux_timeout_support = true;
dc->caps.dmcub_support = true;
dc->caps.is_apu = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h
index a9170b9f84d3..43f33e186088 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h
@@ -37,6 +37,7 @@ struct cp_psp_stream_config {
uint8_t phy_idx;
uint8_t assr_enabled;
uint8_t mst_enabled;
+ uint8_t dp2_enabled;
void *dm_stream_ctx;
bool dpms_off;
};
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 9ab854293ace..8de554fb98b9 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -160,6 +160,8 @@ void dm_set_dcn_clocks(
struct dc_context *ctx,
struct dc_clocks *clks);
+void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz);
+
bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable);
void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us);
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
index 01c3a31be191..3cc110e13213 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
@@ -30,6 +30,7 @@
#define LINK_TRAINING_RETRY_DELAY 50 /* ms */
#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
+#define MAX_MTP_SLOT_COUNT 64
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
#define TRAINING_AUX_RD_INTERVAL 100 //us
@@ -189,5 +190,26 @@ enum dc_status dpcd_configure_lttpr_mode(
struct link_training_settings *lt_settings);
enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_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);
+
+enum dc_status dpcd_configure_channel_coding(
+ struct dc_link *link,
+ struct link_training_settings *lt_settings);
+
+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 dc_link_settings *link_settings);
+void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal);
+void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
+bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx);
+void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link);
+
bool dp_retrieve_lttpr_cap(struct dc_link *link);
#endif /* __DC_LINK_DP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
index f7f7e4fff0c2..d09eed7bcc4a 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
@@ -41,6 +41,9 @@ struct dce_hwseq_wa {
bool DEGVIDCN10_254;
bool DEGVIDCN21;
bool disallow_self_refresh_during_multi_plane_transition;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ bool dp_hpo_and_otg_sequence;
+#endif
};
struct hwseq_wa_state {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 713f6d5cf3e0..3fbda9d7e257 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -200,4 +200,9 @@ int get_num_mpc_splits(struct pipe_ctx *pipe);
int get_num_odm_splits(struct pipe_ctx *pipe);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
+ const struct resource_pool *pool);
+#endif
+
#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
index aec7389aff37..6fb7c0145cb6 100644
--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
@@ -80,6 +80,15 @@ enum dpcd_phy_test_patterns {
PHY_TEST_PATTERN_CP2520_1,
PHY_TEST_PATTERN_CP2520_2,
PHY_TEST_PATTERN_CP2520_3, /* same as TPS4 */
+ PHY_TEST_PATTERN_128b_132b_TPS1 = 0x8,
+ PHY_TEST_PATTERN_128b_132b_TPS2 = 0x10,
+ PHY_TEST_PATTERN_PRBS9 = 0x18,
+ PHY_TEST_PATTERN_PRBS11 = 0x20,
+ PHY_TEST_PATTERN_PRBS15 = 0x28,
+ PHY_TEST_PATTERN_PRBS23 = 0x30,
+ PHY_TEST_PATTERN_PRBS31 = 0x38,
+ PHY_TEST_PATTERN_264BIT_CUSTOM = 0x40,
+ PHY_TEST_PATTERN_SQUARE_PULSE = 0x48,
};
enum dpcd_test_dyn_range {
@@ -135,7 +144,14 @@ enum dpcd_training_patterns {
DPCD_TRAINING_PATTERN_1,
DPCD_TRAINING_PATTERN_2,
DPCD_TRAINING_PATTERN_3,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DPCD_TRAINING_PATTERN_4 = 7,
+ DPCD_128b_132b_TPS1 = 1,
+ DPCD_128b_132b_TPS2 = 2,
+ DPCD_128b_132b_TPS2_CDS = 3,
+#else
DPCD_TRAINING_PATTERN_4 = 7
+#endif
};
/* This enum is for use with PsrSinkPsrStatus.bits.sinkSelfRefreshStatus
diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
index efd9812c13ec..c729b50c4f20 100644
--- a/drivers/gpu/drm/amd/display/include/link_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
@@ -53,7 +53,11 @@ enum edp_revision {
};
enum {
- LINK_RATE_REF_FREQ_IN_KHZ = 27000 /*27MHz*/
+ LINK_RATE_REF_FREQ_IN_KHZ = 27000, /*27MHz*/
+ BITS_PER_DP_BYTE = 10,
+ DATA_EFFICIENCY_8b_10b_x10000 = 8000, /* 80% data efficiency */
+ DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100 = 97, /* 97% data efficiency when FEC is enabled */
+ DATA_EFFICIENCY_128b_132b_x10000 = 9646, /* 96.71% data efficiency x 99.75% downspread factor */
};
enum link_training_result {
@@ -70,6 +74,12 @@ enum link_training_result {
LINK_TRAINING_LINK_LOSS,
/* Abort link training (because sink unplugged) */
LINK_TRAINING_ABORT,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ DP_128b_132b_LT_FAILED,
+ DP_128b_132b_MAX_LOOP_COUNT_REACHED,
+ DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT,
+ DP_128b_132b_CDS_DONE_TIMEOUT,
+#endif
};
enum lttpr_mode {
@@ -86,11 +96,23 @@ struct link_training_settings {
enum dc_pre_emphasis *pre_emphasis;
enum dc_post_cursor2 *post_cursor2;
bool should_set_fec_ready;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* TODO - factor lane_settings out because it changes during LT */
+ union dc_dp_ffe_preset *ffe_preset;
+#endif
uint16_t cr_pattern_time;
uint16_t eq_pattern_time;
+ uint16_t cds_pattern_time;
enum dc_dp_training_pattern pattern_for_cr;
enum dc_dp_training_pattern pattern_for_eq;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ enum dc_dp_training_pattern pattern_for_cds;
+
+ uint32_t eq_wait_time_limit;
+ uint8_t eq_loop_count_limit;
+ uint32_t cds_wait_time_limit;
+#endif
bool enhanced_framing;
bool allow_invalid_msa_timing_param;
diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h
index 571fcf23cea9..370fad883e33 100644
--- a/drivers/gpu/drm/amd/display/include/logger_types.h
+++ b/drivers/gpu/drm/amd/display/include/logger_types.h
@@ -72,6 +72,9 @@
#define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__)
#define DC_LOG_SMU(...) pr_debug("[SMU_MSG]:"__VA_ARGS__)
#define DC_LOG_DWB(...) DRM_DEBUG_KMS(__VA_ARGS__)
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+#define DC_LOG_DP2(...) DRM_DEBUG_KMS(__VA_ARGS__)
+#endif
struct dal_logger;
@@ -123,6 +126,9 @@ enum dc_log_type {
LOG_MAX_HW_POINTS,
LOG_ALL_TF_CHANNELS,
LOG_SAMPLE_1DLUT,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ LOG_DP2,
+#endif
LOG_SECTION_TOTAL_COUNT
};
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 6/6] drm/amd/display: Add DP 2.0 SST DC Support
2021-08-19 18:58 ` [PATCH v3 6/6] drm/amd/display: Add DP 2.0 SST DC Support Fangzhi Zuo
@ 2021-08-20 14:19 ` Kazlauskas, Nicholas
0 siblings, 0 replies; 9+ messages in thread
From: Kazlauskas, Nicholas @ 2021-08-20 14:19 UTC (permalink / raw)
To: Fangzhi Zuo, amd-gfx, harry.wentland; +Cc: wayne.lin
On 2021-08-19 2:58 p.m., Fangzhi Zuo wrote:
> 1. Retrieve 128/132b link cap.
> 2. 128/132b link training and payload allocation.
> 3. UHBR10 link rate support.
>
> Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Minor nitpick with some of the guarding, but otherwise this is probably
okay to merge in. Series is
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Please make sure you fix the guarding mentioned on the other patch
before merge though.
Regards,
Nicholas Kazlauskas
> ---
> .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +
> drivers/gpu/drm/amd/display/dc/core/dc.c | 21 +
> drivers/gpu/drm/amd/display/dc/core/dc_link.c | 520 +++++++-
> .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 1168 ++++++++++++++++-
> .../drm/amd/display/dc/core/dc_link_hwss.c | 314 ++++-
> .../gpu/drm/amd/display/dc/core/dc_resource.c | 118 ++
> drivers/gpu/drm/amd/display/dc/dc.h | 27 +-
> drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 222 ++++
> drivers/gpu/drm/amd/display/dc/dc_link.h | 3 +
> drivers/gpu/drm/amd/display/dc/dc_types.h | 21 +
> .../display/dc/dce110/dce110_hw_sequencer.c | 104 +-
> .../amd/display/dc/dcn10/dcn10_link_encoder.c | 9 +
> .../drm/amd/display/dc/dcn20/dcn20_hwseq.c | 26 +-
> .../drm/amd/display/dc/dcn20/dcn20_resource.c | 4 +
> .../drm/amd/display/dc/dcn31/dcn31_resource.c | 18 +-
> drivers/gpu/drm/amd/display/dc/dm_cp_psp.h | 1 +
> drivers/gpu/drm/amd/display/dc/dm_helpers.h | 2 +
> .../gpu/drm/amd/display/dc/inc/dc_link_dp.h | 22 +
> .../amd/display/dc/inc/hw_sequencer_private.h | 3 +
> drivers/gpu/drm/amd/display/dc/inc/resource.h | 5 +
> .../gpu/drm/amd/display/include/dpcd_defs.h | 16 +
> .../amd/display/include/link_service_types.h | 24 +-
> .../drm/amd/display/include/logger_types.h | 6 +
> 23 files changed, 2619 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> index 6fee12c91ef5..22ddd8d71bcf 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> @@ -751,3 +751,11 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
> &new_downspread.raw,
> sizeof(new_downspread));
> }
> +
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
> +{
> + // FPGA programming for this clock in diags framework that
> + // needs to go through dm layer, therefore leave dummy interace here
> +}
> +#endif
> \ No newline at end of file
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
> index 7a442fcfa6ac..8d4d804df5b2 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
> @@ -186,6 +186,9 @@ static bool create_links(
> int i;
> int connectors_num;
> struct dc_bios *bios = dc->ctx->dc_bios;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + int dp_hpo_link_count = 0;
> +#endif
>
> dc->link_count = 0;
>
> @@ -255,6 +258,24 @@ static bool create_links(
> goto failed_alloc;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) &&
> + dc->caps.dp_hpo &&
> + link->dc->res_pool->res_cap->num_hpo_dp_link_encoder > 0) {
> + /* FPGA case - Allocate HPO DP link encoder */
> + if (i < link->dc->res_pool->res_cap->num_hpo_dp_link_encoder) {
> + link->hpo_dp_link_enc = link->dc->res_pool->hpo_dp_link_enc[i];
> +
> + if (link->hpo_dp_link_enc == NULL) {
> + BREAK_TO_DEBUGGER();
> + goto failed_alloc;
> + }
> + link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source;
> + link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter;
> + }
> + }
> +#endif
> +
> link->link_status.dpcd_caps = &link->dpcd_caps;
>
> enc_init.ctx = dc->ctx;
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
> index 8bd7f42a8053..bb06d8e3312e 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
> @@ -64,6 +64,31 @@
> /*******************************************************************************
> * Private functions
> ******************************************************************************/
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static bool add_dp_hpo_link_encoder_to_link(struct dc_link *link)
> +{
> + struct hpo_dp_link_encoder *enc = resource_get_unused_hpo_dp_link_encoder(
> + link->dc->res_pool);
> +
> + if (!link->hpo_dp_link_enc && enc) {
> + link->hpo_dp_link_enc = enc;
> + link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter;
> + link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source;
> + }
> +
> + return (link->hpo_dp_link_enc != NULL);
> +}
> +
> +static void remove_dp_hpo_link_encoder_from_link(struct dc_link *link)
> +{
> + if (link->hpo_dp_link_enc) {
> + link->hpo_dp_link_enc->hpd_source = HPD_SOURCEID_UNKNOWN;
> + link->hpo_dp_link_enc->transmitter = TRANSMITTER_UNKNOWN;
> + link->hpo_dp_link_enc = NULL;
> + }
> +}
> +#endif
> +
> static void dc_link_destruct(struct dc_link *link)
> {
> int i;
> @@ -91,6 +116,12 @@ static void dc_link_destruct(struct dc_link *link)
> link->link_enc->funcs->destroy(&link->link_enc);
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (link->hpo_dp_link_enc) {
> + remove_dp_hpo_link_encoder_from_link(link);
> + }
> +#endif
> +
> if (link->local_sink)
> dc_sink_release(link->local_sink);
>
> @@ -928,6 +959,11 @@ static bool dc_link_detect_helper(struct dc_link *link,
> return false;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING)
> + add_dp_hpo_link_encoder_to_link(link);
> +#endif
> +
> if (link->type == dc_connection_mst_branch) {
> LINK_INFO("link=%d, mst branch is now Connected\n",
> link->link_index);
> @@ -1173,6 +1209,11 @@ static bool dc_link_detect_helper(struct dc_link *link,
> sizeof(link->mst_stream_alloc_table.stream_allocations));
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
> + reset_dp_hpo_stream_encoders_for_link(link);
> +#endif
> +
> link->type = dc_connection_none;
> sink_caps.signal = SIGNAL_TYPE_NONE;
> /* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk
> @@ -1549,6 +1590,9 @@ static bool dc_link_construct(struct dc_link *link,
> }
>
> DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
> +#endif
>
> /* Update link encoder tracking variables. These are used for the dynamic
> * assignment of link encoders to streams.
> @@ -1741,17 +1785,36 @@ static enum dc_status enable_link_dp(struct dc_state *state,
> /* get link settings for video mode timing */
> decide_link_settings(stream, &link_settings);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING &&
> + pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
> + dp_enable_mst_on_sink(link, true);
> + }
> +#endif
> +
> if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
> /*in case it is not on*/
> link->dc->hwss.edp_power_control(link, true);
> link->dc->hwss.edp_wait_for_hpd_ready(link, true);
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
> + /* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */
> + } else {
> + pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
> + link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
> + if (state->clk_mgr && !apply_seamless_boot_optimization)
> + state->clk_mgr->funcs->update_clocks(state->clk_mgr,
> + state, false);
> + }
> +#else
> pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
> - link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
> + link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
> if (state->clk_mgr && !apply_seamless_boot_optimization)
> state->clk_mgr->funcs->update_clocks(state->clk_mgr,
> - state, false);
> + state, false);
> +#endif
>
> // during mode switch we do DP_SET_POWER off then on, and OUI is lost
> dpcd_set_source_specific_data(link);
> @@ -1780,7 +1843,12 @@ static enum dc_status enable_link_dp(struct dc_state *state,
> else
> fec_enable = true;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
> + dp_set_fec_enable(link, fec_enable);
> +#else
> dp_set_fec_enable(link, fec_enable);
> +#endif
>
> // during mode set we do DP_SET_POWER off then on, aux writes are lost
> if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
> @@ -2284,6 +2352,9 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
>
> if (dc_is_dp_signal(signal)) {
> /* SST DP, eDP */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct dc_link_settings link_settings = link->cur_link_settings;
> +#endif
> if (dc_is_dp_sst_signal(signal))
> dp_disable_link_phy(link, signal);
> else
> @@ -2291,8 +2362,15 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
>
> if (dc_is_dp_sst_signal(signal) ||
> link->mst_stream_alloc_table.stream_count == 0) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) {
> + dp_set_fec_enable(link, false);
> + dp_set_fec_ready(link, false);
> + }
> +#else
> dp_set_fec_enable(link, false);
> dp_set_fec_ready(link, false);
> +#endif
> }
> } else {
> if (signal != SIGNAL_TYPE_VIRTUAL)
> @@ -2475,9 +2553,14 @@ static bool dp_active_dongle_validate_timing(
> break;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER &&
> + dongle_caps->extendedCapValid == true) {
> +#else
> if (dpcd_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
> dongle_caps->extendedCapValid == false)
> return true;
> +#endif
>
> /* Check Pixel Encoding */
> switch (timing->pixel_encoding) {
> @@ -2520,6 +2603,87 @@ static bool dp_active_dongle_validate_timing(
> if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
> return false;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + }
> +
> + if (dongle_caps->dfp_cap_ext.supported) {
> +
> + if (dongle_caps->dfp_cap_ext.max_pixel_rate_in_mps < (timing->pix_clk_100hz / 10000))
> + return false;
> +
> + if (dongle_caps->dfp_cap_ext.max_video_h_active_width < timing->h_addressable)
> + return false;
> +
> + if (dongle_caps->dfp_cap_ext.max_video_v_active_height < timing->v_addressable)
> + return false;
> +
> + if (timing->pixel_encoding == PIXEL_ENCODING_RGB) {
> + if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
> + return false;
> + if (timing->display_color_depth == COLOR_DEPTH_666 &&
> + !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_6bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_888 &&
> + !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_8bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
> + !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_10bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
> + !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_12bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
> + !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_16bpc)
> + return false;
> + } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
> + if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
> + return false;
> + if (timing->display_color_depth == COLOR_DEPTH_888 &&
> + !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_8bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
> + !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_10bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
> + !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_12bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
> + !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_16bpc)
> + return false;
> + } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
> + if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
> + return false;
> + if (timing->display_color_depth == COLOR_DEPTH_888 &&
> + !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_8bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
> + !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_10bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
> + !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_12bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
> + !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_16bpc)
> + return false;
> + } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
> + if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
> + return false;
> + if (timing->display_color_depth == COLOR_DEPTH_888 &&
> + !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_8bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
> + !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_10bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
> + !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_12bpc)
> + return false;
> + else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
> + !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_16bpc)
> + return false;
> + }
> + }
> +#endif
> +
> return true;
> }
>
> @@ -3016,6 +3180,159 @@ static void update_mst_stream_alloc_table(
> link->mst_stream_alloc_table.stream_allocations[i] =
> work_table[i];
> }
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +/* TODO: Temp function for Diags FPGA */
> +static void dp2_update_mst_stream_alloc_table(
> + struct dc_link *link,
> + struct stream_encoder *dio_stream_enc,
> + struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
> + const struct dp_mst_stream_allocation_table *proposed_table)
> +{
> + struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = {
> + { 0 } };
> + struct link_mst_stream_allocation *dc_alloc;
> +
> + int i;
> + int j;
> +
> + /* if DRM proposed_table has more than one new payload */
> + ASSERT(proposed_table->stream_count -
> + link->mst_stream_alloc_table.stream_count < 2);
> +
> + /* copy proposed_table to link, add stream encoder */
> + for (i = 0; i < proposed_table->stream_count; i++) {
> +
> + for (j = 0; j < link->mst_stream_alloc_table.stream_count; j++) {
> + dc_alloc =
> + &link->mst_stream_alloc_table.stream_allocations[j];
> +
> + if (dc_alloc->vcp_id ==
> + proposed_table->stream_allocations[i].vcp_id) {
> +
> + work_table[i] = *dc_alloc;
> + break; /* exit j loop */
> + }
> + }
> +
> + /* new vcp_id */
> + if (j == link->mst_stream_alloc_table.stream_count) {
> + work_table[i].vcp_id =
> + proposed_table->stream_allocations[i].vcp_id;
> + work_table[i].slot_count =
> + proposed_table->stream_allocations[i].slot_count;
> + work_table[i].stream_enc = dio_stream_enc;
> + work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc;
> + }
> + }
> +
> + /* update link->mst_stream_alloc_table with work_table */
> + link->mst_stream_alloc_table.stream_count =
> + proposed_table->stream_count;
> + for (i = 0; i < MAX_CONTROLLER_NUM; i++)
> + link->mst_stream_alloc_table.stream_allocations[i] =
> + work_table[i];
> +}
> +
> +/*
> + * Payload allocation/deallocation for SST introduced in DP2.0
> + */
> +enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx, bool allocate)
> +{
> + struct dc_stream_state *stream = pipe_ctx->stream;
> + struct dc_link *link = stream->link;
> + struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc;
> + struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
> + struct link_mst_stream_allocation_table proposed_table = {0};
> + struct fixed31_32 avg_time_slots_per_mtp;
> + DC_LOGGER_INIT(link->ctx->logger);
> +
> + /* slot X.Y for SST payload deallocate */
> + if (!allocate) {
> + avg_time_slots_per_mtp = dc_fixpt_from_int(0);
> +
> + DC_LOG_DP2("SST Update Payload: set_throttled_vcp_size slot X.Y for SST stream"
> + "X: %d "
> + "Y: %d",
> + dc_fixpt_floor(
> + avg_time_slots_per_mtp),
> + dc_fixpt_ceil(
> + dc_fixpt_shl(
> + dc_fixpt_sub_int(
> + avg_time_slots_per_mtp,
> + dc_fixpt_floor(
> + avg_time_slots_per_mtp)),
> + 26)));
> +
> + hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
> + hpo_dp_link_encoder,
> + hpo_dp_stream_encoder->inst,
> + avg_time_slots_per_mtp);
> + }
> +
> + /* calculate VC payload and update branch with new payload allocation table*/
> + if (!dpcd_write_128b_132b_sst_payload_allocation_table(
> + stream,
> + link,
> + &proposed_table,
> + allocate)) {
> + DC_LOG_ERROR("SST Update Payload: Failed to update "
> + "allocation table for "
> + "pipe idx: %d\n",
> + pipe_ctx->pipe_idx);
> + }
> +
> + proposed_table.stream_allocations[0].hpo_dp_stream_enc = hpo_dp_stream_encoder;
> +
> + ASSERT(proposed_table.stream_count == 1);
> +
> + //TODO - DP2.0 Logging: Instead of hpo_dp_stream_enc pointer, log instance id
> + DC_LOG_DP2("SST Update Payload: hpo_dp_stream_enc: %p "
> + "vcp_id: %d "
> + "slot_count: %d\n",
> + (void *) proposed_table.stream_allocations[0].hpo_dp_stream_enc,
> + proposed_table.stream_allocations[0].vcp_id,
> + proposed_table.stream_allocations[0].slot_count);
> +
> + /* program DP source TX for payload */
> + hpo_dp_link_encoder->funcs->update_stream_allocation_table(
> + hpo_dp_link_encoder,
> + &proposed_table);
> +
> + /* poll for ACT handled */
> + if (!dpcd_poll_for_allocation_change_trigger(link)) {
> + // Failures will result in blackscreen and errors logged
> + BREAK_TO_DEBUGGER();
> + }
> +
> + /* slot X.Y for SST payload allocate */
> + if (allocate) {
> + avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
> +
> + DC_LOG_DP2("SST Update Payload: "
> + "slot.X: %d "
> + "slot.Y: %d",
> + dc_fixpt_floor(
> + avg_time_slots_per_mtp),
> + dc_fixpt_ceil(
> + dc_fixpt_shl(
> + dc_fixpt_sub_int(
> + avg_time_slots_per_mtp,
> + dc_fixpt_floor(
> + avg_time_slots_per_mtp)),
> + 26)));
> +
> + hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
> + hpo_dp_link_encoder,
> + hpo_dp_stream_encoder->inst,
> + avg_time_slots_per_mtp);
> + }
> +
> + /* Always return DC_OK.
> + * If part of sequence fails, log failure(s) and show blackscreen
> + */
> + return DC_OK;
> +}
> +#endif
>
> /* convert link_mst_stream_alloc_table to dm dp_mst_stream_alloc_table
> * because stream_encoder is not exposed to dm
> @@ -3203,6 +3520,11 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
> config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
> config.link_enc_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A;
> config.phy_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A;
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
> + config.link_enc_idx = pipe_ctx->stream->link->hpo_dp_link_enc->inst;
> + config.dp2_enabled = 1;
> + }
> #endif
> config.dpms_off = dpms_off;
> config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context;
> @@ -3214,6 +3536,88 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
> }
> #endif
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pipe_ctx *pipe_ctx)
> +{
> + struct dc *dc = pipe_ctx->stream->ctx->dc;
> + struct dc_stream_state *stream = pipe_ctx->stream;
> + struct link_mst_stream_allocation_table proposed_table = {0};
> + struct fixed31_32 avg_time_slots_per_mtp;
> + uint8_t req_slot_count = 0;
> + uint8_t vc_id = 1; /// VC ID always 1 for SST
> +
> + struct dc_link_settings link_settings = {0};
> + DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
> +
> + decide_link_settings(stream, &link_settings);
> + stream->link->cur_link_settings = link_settings;
> +
> + /* Enable clock, Configure lane count, and Enable Link Encoder*/
> + enable_dp_hpo_output(stream->link, &stream->link->cur_link_settings);
> +
> +#ifdef DIAGS_BUILD
> + /* Workaround for FPGA HPO capture DP link data:
> + * HPO capture will set link to active mode
> + * This workaround is required to get a capture from start of frame
> + */
> + if (!dc->debug.fpga_hpo_capture_en) {
> + struct encoder_set_dp_phy_pattern_param params = {0};
> + params.dp_phy_pattern = DP_TEST_PATTERN_VIDEO_MODE;
> +
> + /* Set link active */
> + stream->link->hpo_dp_link_enc->funcs->set_link_test_pattern(
> + stream->link->hpo_dp_link_enc,
> + ¶ms);
> + }
> +#endif
> +
> + /* Enable DP_STREAM_ENC */
> + dc->hwss.enable_stream(pipe_ctx);
> +
> + /* Set DPS PPS SDP (AKA "info frames") */
> + if (pipe_ctx->stream->timing.flags.DSC) {
> + dp_set_dsc_pps_sdp(pipe_ctx, true);
> + }
> +
> + /* Allocate Payload */
> + if ((stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) && (state->stream_count > 1)) {
> + // MST case
> + uint8_t i;
> +
> + proposed_table.stream_count = state->stream_count;
> + for (i = 0; i < state->stream_count; i++) {
> + avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(state->streams[i], state->streams[i]->link);
> + req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
> + proposed_table.stream_allocations[i].slot_count = req_slot_count;
> + proposed_table.stream_allocations[i].vcp_id = i+1;
> + /* NOTE: This makes assumption that pipe_ctx index is same as stream index */
> + proposed_table.stream_allocations[i].hpo_dp_stream_enc = state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc;
> + }
> + } else {
> + // SST case
> + avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, stream->link);
> + req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
> + proposed_table.stream_count = 1; /// Always 1 stream for SST
> + proposed_table.stream_allocations[0].slot_count = req_slot_count;
> + proposed_table.stream_allocations[0].vcp_id = vc_id;
> + proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
> + }
> +
> + stream->link->hpo_dp_link_enc->funcs->update_stream_allocation_table(
> + stream->link->hpo_dp_link_enc,
> + &proposed_table);
> +
> + stream->link->hpo_dp_link_enc->funcs->set_throttled_vcp_size(
> + stream->link->hpo_dp_link_enc,
> + pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
> + avg_time_slots_per_mtp);
> +
> +
> +
> + dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
> +}
> +#endif
> +
> void core_link_enable_stream(
> struct dc_state *state,
> struct pipe_ctx *pipe_ctx)
> @@ -3230,7 +3634,12 @@ void core_link_enable_stream(
> dc_is_virtual_signal(pipe_ctx->stream->signal))
> return;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
> + && !is_dp_128b_132b_signal(pipe_ctx)) {
> +#else
> if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) {
> +#endif
> stream->link->link_enc->funcs->setup(
> stream->link->link_enc,
> pipe_ctx->stream->signal);
> @@ -3240,13 +3649,32 @@ void core_link_enable_stream(
> stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
> }
>
> - if (dc_is_dp_signal(pipe_ctx->stream->signal))
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->set_stream_attribute(
> + pipe_ctx->stream_res.hpo_dp_stream_enc,
> + &stream->timing,
> + stream->output_color_space,
> + stream->use_vsc_sdp_for_colorimetry,
> + stream->timing.flags.DSC,
> + false);
> + otg_out_dest = OUT_MUX_HPO_DP;
> + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
> pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(
> + pipe_ctx->stream_res.stream_enc,
> + &stream->timing,
> + stream->output_color_space,
> + stream->use_vsc_sdp_for_colorimetry,
> + stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
> + }
> +#else
> + pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(
> pipe_ctx->stream_res.stream_enc,
> &stream->timing,
> stream->output_color_space,
> stream->use_vsc_sdp_for_colorimetry,
> stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
> +#endif
>
> if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
> pipe_ctx->stream_res.stream_enc->funcs->hdmi_set_stream_attribute(
> @@ -3357,7 +3785,12 @@ void core_link_enable_stream(
> * as a workaround for the incorrect value being applied
> * from transmitter control.
> */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
> + is_dp_128b_132b_signal(pipe_ctx)))
> +#else
> if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
> +#endif
> stream->link->link_enc->funcs->setup(
> stream->link->link_enc,
> pipe_ctx->stream->signal);
> @@ -3375,6 +3808,11 @@ void core_link_enable_stream(
>
> if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
> dc_link_allocate_mst_payload(pipe_ctx);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
> + is_dp_128b_132b_signal(pipe_ctx))
> + dc_link_update_sst_payload(pipe_ctx, true);
> +#endif
>
> dc->hwss.unblank_stream(pipe_ctx,
> &pipe_ctx->stream->link->cur_link_settings);
> @@ -3391,6 +3829,11 @@ void core_link_enable_stream(
> dc->hwss.enable_audio_stream(pipe_ctx);
>
> } else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + fpga_dp_hpo_enable_link_and_stream(state, pipe_ctx);
> + }
> +#endif
> if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
> dc_is_virtual_signal(pipe_ctx->stream->signal))
> dp_set_dsc_enable(pipe_ctx, true);
> @@ -3426,6 +3869,11 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
>
> if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
> deallocate_mst_payload(pipe_ctx);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
> + is_dp_128b_132b_signal(pipe_ctx))
> + dc_link_update_sst_payload(pipe_ctx, false);
> +#endif
>
> if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
> struct ext_hdmi_settings settings = {0};
> @@ -3452,14 +3900,39 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
> }
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
> + !is_dp_128b_132b_signal(pipe_ctx)) {
> +
> + /* In DP1.x SST mode, our encoder will go to TPS1
> + * when link is on but stream is off.
> + * Disabling link before stream will avoid exposing TPS1 pattern
> + * during the disable sequence as it will confuse some receivers
> + * state machine.
> + * In DP2 or MST mode, our encoder will stay video active
> + */
> + disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
> + dc->hwss.disable_stream(pipe_ctx);
> + } else {
> + dc->hwss.disable_stream(pipe_ctx);
> + disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
> + }
> +#else
> disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal);
>
> dc->hwss.disable_stream(pipe_ctx);
> +#endif
>
> if (pipe_ctx->stream->timing.flags.DSC) {
> if (dc_is_dp_signal(pipe_ctx->stream->signal))
> dp_set_dsc_enable(pipe_ctx, false);
> }
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
> + pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO);
> + }
> +#endif
> }
>
> void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
> @@ -3592,6 +4065,13 @@ void dc_link_set_preferred_training_settings(struct dc *dc,
>
> if (link_setting != NULL) {
> link->preferred_link_setting = *link_setting;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(link_setting) ==
> + DP_128b_132b_ENCODING && !link->hpo_dp_link_enc) {
> + if (!add_dp_hpo_link_encoder_to_link(link))
> + memset(&link->preferred_link_setting, 0, sizeof(link->preferred_link_setting));
> + }
> +#endif
> } else {
> link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
> link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
> @@ -3633,6 +4113,38 @@ uint32_t dc_link_bandwidth_kbps(
> const struct dc_link *link,
> const struct dc_link_settings *link_setting)
> {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint32_t total_data_bw_efficiency_x10000 = 0;
> + uint32_t link_rate_per_lane_kbps = 0;
> +
> + switch (dp_get_link_encoding_format(link_setting)) {
> + case DP_8b_10b_ENCODING:
> + /* For 8b/10b encoding:
> + * link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane.
> + * data bandwidth efficiency is 80% with additional 3% overhead if FEC is supported.
> + */
> + link_rate_per_lane_kbps = link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE;
> + total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000;
> + if (dc_link_should_enable_fec(link)) {
> + total_data_bw_efficiency_x10000 /= 100;
> + total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100;
> + }
> + break;
> + case DP_128b_132b_ENCODING:
> + /* For 128b/132b encoding:
> + * link rate is defined in the unit of 10mbps per lane.
> + * total data bandwidth efficiency is always 96.71%.
> + */
> + link_rate_per_lane_kbps = link_setting->link_rate * 10000;
> + total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_128b_132b_x10000;
> + break;
> + default:
> + break;
> + }
> +
> + /* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */
> + return link_rate_per_lane_kbps * link_setting->lane_count / 10000 * total_data_bw_efficiency_x10000;
> +#else
> uint32_t link_bw_kbps =
> link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ; /* bytes per sec */
>
> @@ -3663,9 +4175,9 @@ uint32_t dc_link_bandwidth_kbps(
> long long fec_link_bw_kbps = link_bw_kbps * 970LL;
> link_bw_kbps = (uint32_t)(div64_s64(fec_link_bw_kbps, 1000LL));
> }
> -
> return link_bw_kbps;
>
> +#endif
> }
>
> const struct dc_link_settings *dc_link_get_link_cap(
> 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
> index cd025c12f17b..fc122c8c2318 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
> @@ -39,6 +39,43 @@ enum {
> POST_LT_ADJ_REQ_TIMEOUT = 200
> };
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +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},
> +};
> +#endif
> +
> static bool decide_fallback_link_setting(
> struct dc_link_settings initial_link_settings,
> struct dc_link_settings *current_link_setting,
> @@ -52,15 +89,27 @@ static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link,
> {
> union training_aux_rd_interval training_rd_interval;
> uint32_t wait_in_micro_secs = 100;
> -
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> memset(&training_rd_interval, 0, sizeof(training_rd_interval));
> + if (dp_get_link_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;
> + }
> +#else
> 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;
> + wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
> +#endif
> return wait_in_micro_secs;
> }
>
> @@ -68,6 +117,36 @@ static uint32_t get_eq_training_aux_rd_interval(
> struct dc_link *link,
> const struct dc_link_settings *link_settings)
> {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + union training_aux_rd_interval training_rd_interval;
> +
> + memset(&training_rd_interval, 0, sizeof(training_rd_interval));
> + if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
> + core_link_read_dpcd(
> + link,
> + DP_128b_132b_TRAINING_AUX_RD_INTERVAL,
> + (uint8_t *)&training_rd_interval,
> + sizeof(training_rd_interval));
> + } else if (dp_get_link_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;
> + }
> +#else
> union training_aux_rd_interval training_rd_interval;
> uint32_t wait_in_micro_secs = 400;
>
> @@ -87,13 +166,21 @@ static uint32_t get_eq_training_aux_rd_interval(
> }
>
> return wait_in_micro_secs;
> +#endif
> }
>
> void dp_wait_for_training_aux_rd_interval(
> struct dc_link *link,
> uint32_t wait_in_micro_secs)
> {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (wait_in_micro_secs > 16000)
> + msleep(wait_in_micro_secs/1000);
> + else
> + udelay(wait_in_micro_secs);
> +#else
> udelay(wait_in_micro_secs);
> +#endif
>
> DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
> __func__,
> @@ -121,6 +208,17 @@ enum dpcd_training_patterns
> case DP_TRAINING_PATTERN_SEQUENCE_4:
> dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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;
> +#endif
> case DP_TRAINING_PATTERN_VIDEOIDLE:
> dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
> break;
> @@ -159,13 +257,62 @@ static void dpcd_set_training_pattern(
> static enum dc_dp_training_pattern decide_cr_training_pattern(
> const struct dc_link_settings *link_settings)
> {
> - return DP_TRAINING_PATTERN_SEQUENCE_1;
> + enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
> +
> + switch (dp_get_link_encoding_format(link_settings)) {
> + case DP_8b_10b_ENCODING:
> + pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
> + break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + case DP_128b_132b_ENCODING:
> + pattern = DP_128b_132b_TPS1;
> + break;
> +#endif
> + }
> +
> + return pattern;
> }
>
> static 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;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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;
> +
> + /* Access link encoder capability based on whether it is statically
> + * or dynamically assigned to a link.
> + */
> + if (link->is_dig_mapping_flexible &&
> + link->dc->res_pool->funcs->link_encs_assign)
> + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
> + else
> + link_enc = link->link_enc;
> + ASSERT(link_enc);
> + enc_caps = &link_enc->features;
> +
> + switch (dp_get_link_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;
> +#else
> enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
> struct encoder_feature_support *features;
> struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
> @@ -196,7 +343,38 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li
> return DP_TRAINING_PATTERN_SEQUENCE_3;
>
> return DP_TRAINING_PATTERN_SEQUENCE_2;
> +#endif
> +}
> +
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
> +{
> + uint8_t link_rate = 0;
> + enum dp_link_encoding encoding = dp_get_link_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;
> }
> +#endif
>
> enum dc_status dpcd_set_link_settings(
> struct dc_link *link,
> @@ -247,7 +425,11 @@ enum dc_status dpcd_set_link_settings(
> status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
> <_settings->link_settings.link_rate_set, 1);
> } else {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + rate = get_dpcd_link_rate(<_settings->link_settings);
> +#else
> rate = (uint8_t) (lt_settings->link_settings.link_rate);
> +#endif
> status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
> }
>
> @@ -289,6 +471,10 @@ uint8_t dc_dp_initialize_scrambling_data_symbols(
> disable_scrabled_data_symbols = 1;
> break;
> case DP_TRAINING_PATTERN_SEQUENCE_4:
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + case DP_128b_132b_TPS1:
> + case DP_128b_132b_TPS2:
> +#endif
> disable_scrabled_data_symbols = 0;
> break;
> default:
> @@ -356,6 +542,26 @@ static void dpcd_set_lt_pattern_and_lane_settings(
> for (lane = 0; lane <
> (uint32_t)(lt_settings->link_settings.lane_count); lane++) {
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(<_settings->link_settings) ==
> + DP_128b_132b_ENCODING) {
> + dpcd_lane[lane].tx_ffe.PRESET_VALUE =
> + lt_settings->lane_settings[lane].FFE_PRESET.settings.level;
> + } else if (dp_get_link_encoding_format(<_settings->link_settings) ==
> + DP_8b_10b_ENCODING) {
> + dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
> + (uint8_t)(lt_settings->lane_settings[lane].VOLTAGE_SWING);
> + dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
> + (uint8_t)(lt_settings->lane_settings[lane].PRE_EMPHASIS);
> +
> + dpcd_lane[lane].bits.MAX_SWING_REACHED =
> + (lt_settings->lane_settings[lane].VOLTAGE_SWING ==
> + VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
> + dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
> + (lt_settings->lane_settings[lane].PRE_EMPHASIS ==
> + PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
> + }
> +#else
> dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
> (uint8_t)(lt_settings->lane_settings[lane].VOLTAGE_SWING);
> dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
> @@ -367,6 +573,7 @@ static void dpcd_set_lt_pattern_and_lane_settings(
> dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
> (lt_settings->lane_settings[lane].PRE_EMPHASIS ==
> PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
> +#endif
> }
>
> /* concatenate everything into one buffer*/
> @@ -380,6 +587,18 @@ static void dpcd_set_lt_pattern_and_lane_settings(
> size_in_bytes);
>
> if (is_repeater(link, offset)) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(<_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,
> + dpcd_lane[0].tx_ffe.PRESET_VALUE);
> + else if (dp_get_link_encoding_format(<_settings->link_settings) ==
> + DP_8b_10b_ENCODING)
> +#endif
> 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__,
> @@ -390,6 +609,16 @@ static void dpcd_set_lt_pattern_and_lane_settings(
> dpcd_lane[0].bits.MAX_SWING_REACHED,
> dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
> } else {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(<_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,
> + dpcd_lane[0].tx_ffe.PRESET_VALUE);
> + else if (dp_get_link_encoding_format(<_settings->link_settings) ==
> + DP_8b_10b_ENCODING)
> +#endif
> 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,
> @@ -414,6 +643,15 @@ static void dpcd_set_lt_pattern_and_lane_settings(
> (uint8_t *)(dpcd_lane),
> size_in_bytes);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + } else if (dp_get_link_encoding_format(<_settings->link_settings) ==
> + DP_128b_132b_ENCODING) {
> + core_link_write_dpcd(
> + link,
> + dpcd_base_lt_offset,
> + dpcd_lt_buffer,
> + sizeof(dpcd_lt_buffer));
> +#endif
> } else
> /* write it all in (1 + number-of-lanes)-byte burst*/
> core_link_write_dpcd(
> @@ -484,6 +722,13 @@ void dp_update_drive_settings(
> dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2;
> else
> dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2;
> +
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dest->ffe_preset == NULL)
> + dest->lane_settings[lane].FFE_PRESET = src.lane_settings[lane].FFE_PRESET;
> + else
> + dest->lane_settings[lane].FFE_PRESET = *dest->ffe_preset;
> +#endif
> }
> }
>
> @@ -529,6 +774,10 @@ static void find_max_drive_settings(
> lane_settings[0].PRE_EMPHASIS;
> /*max_requested.postCursor2 =
> * link_training_setting->laneSettings[0].postCursor2;*/
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + max_requested.FFE_PRESET =
> + link_training_setting->lane_settings[0].FFE_PRESET;
> +#endif
>
> /* Determine what the maximum of the requested settings are*/
> for (lane = 1; lane < link_training_setting->link_settings.lane_count;
> @@ -554,6 +803,13 @@ static void find_max_drive_settings(
> link_training_setting->laneSettings[lane].postCursor2;
> }
> */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (link_training_setting->lane_settings[lane].FFE_PRESET.settings.level >
> + max_requested.FFE_PRESET.settings.level)
> + max_requested.FFE_PRESET.settings.level =
> + link_training_setting->
> + lane_settings[lane].FFE_PRESET.settings.level;
> +#endif
> }
>
> /* make sure the requested settings are
> @@ -567,6 +823,10 @@ static void find_max_drive_settings(
> if (max_requested.postCursor2 > PostCursor2_MaxLevel)
> max_requested.postCursor2 = PostCursor2_MaxLevel;
> */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
> + max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
> +#endif
>
> /* make sure the pre-emphasis matches the voltage swing*/
> if (max_requested.PRE_EMPHASIS >
> @@ -604,6 +864,10 @@ static void find_max_drive_settings(
> /*max_lt_setting->laneSettings[lane].postCursor2 =
> * max_requested.postCursor2;
> */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + max_lt_setting->lane_settings[lane].FFE_PRESET =
> + max_requested.FFE_PRESET;
> +#endif
> }
>
> }
> @@ -701,12 +965,28 @@ enum dc_status dp_get_lane_status_and_drive_settings(
> (uint32_t)(link_training_setting->link_settings.lane_count);
> lane++) {
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_128b_132b_ENCODING) {
> + request_settings.lane_settings[lane].FFE_PRESET.raw =
> + dpcd_lane_adjust[lane].tx_ffe.PRESET_VALUE;
> + } else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_8b_10b_ENCODING) {
> + request_settings.lane_settings[lane].VOLTAGE_SWING =
> + (enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits.
> + VOLTAGE_SWING_LANE);
> + request_settings.lane_settings[lane].PRE_EMPHASIS =
> + (enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits.
> + PRE_EMPHASIS_LANE);
> + }
> +#else
> request_settings.lane_settings[lane].VOLTAGE_SWING =
> (enum dc_voltage_swing)(dpcd_lane_adjust[lane].bits.
> VOLTAGE_SWING_LANE);
> request_settings.lane_settings[lane].PRE_EMPHASIS =
> (enum dc_pre_emphasis)(dpcd_lane_adjust[lane].bits.
> PRE_EMPHASIS_LANE);
> +#endif
> }
>
> /*Note: for postcursor2, read adjusted
> @@ -745,6 +1025,26 @@ enum dc_status dpcd_set_lane_settings(
> (uint32_t)(link_training_setting->
> link_settings.lane_count);
> lane++) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_128b_132b_ENCODING) {
> + dpcd_lane[lane].tx_ffe.PRESET_VALUE =
> + link_training_setting->lane_settings[lane].FFE_PRESET.settings.level;
> + } else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_8b_10b_ENCODING) {
> + dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
> + (uint8_t)(link_training_setting->lane_settings[lane].VOLTAGE_SWING);
> + dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
> + (uint8_t)(link_training_setting->lane_settings[lane].PRE_EMPHASIS);
> +
> + dpcd_lane[lane].bits.MAX_SWING_REACHED =
> + (link_training_setting->lane_settings[lane].VOLTAGE_SWING ==
> + VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
> + dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
> + (link_training_setting->lane_settings[lane].PRE_EMPHASIS ==
> + PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
> + }
> +#else
> dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
> (uint8_t)(link_training_setting->
> lane_settings[lane].VOLTAGE_SWING);
> @@ -759,6 +1059,7 @@ enum dc_status dpcd_set_lane_settings(
> (link_training_setting->
> lane_settings[lane].PRE_EMPHASIS ==
> PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
> +#endif
> }
>
> status = core_link_write_dpcd(link,
> @@ -786,6 +1087,18 @@ enum dc_status dpcd_set_lane_settings(
> */
>
> if (is_repeater(link, offset)) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_training_setting->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,
> + lane0_set_address,
> + dpcd_lane[0].tx_ffe.PRESET_VALUE);
> + else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_8b_10b_ENCODING)
> +#endif
> 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__,
> @@ -797,6 +1110,16 @@ enum dc_status dpcd_set_lane_settings(
> dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
>
> } else {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_128b_132b_ENCODING)
> + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
> + __func__,
> + lane0_set_address,
> + dpcd_lane[0].tx_ffe.PRESET_VALUE);
> + else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
> + DP_8b_10b_ENCODING)
> +#endif
> 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,
> @@ -932,6 +1255,14 @@ uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval
> case 0x04:
> aux_rd_interval_us = 16000;
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + case 0x05:
> + aux_rd_interval_us = 32000;
> + break;
> + case 0x06:
> + aux_rd_interval_us = 64000;
> + break;
> +#endif
> default:
> break;
> }
> @@ -972,8 +1303,13 @@ static enum link_training_result perform_channel_equalization_sequence(
>
> tr_pattern = lt_settings->pattern_for_eq;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_repeater(link, offset) && dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING)
> + tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
> +#else
> if (is_repeater(link, offset))
> tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
> +#endif
>
> dp_set_hw_training_pattern(link, tr_pattern, offset);
>
> @@ -1125,9 +1461,28 @@ static enum link_training_result perform_clock_recovery_sequence(
> return LINK_TRAINING_SUCCESS;
>
> /* 6. max VS reached*/
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if ((dp_get_link_encoding_format(<_settings->link_settings) ==
> + DP_8b_10b_ENCODING) &&
> + dp_is_max_vs_reached(lt_settings))
> + break;
> +#else
> if (dp_is_max_vs_reached(lt_settings))
> break;
> +#endif
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_128b_132b_ENCODING) &&
> + lt_settings->lane_settings[0].FFE_PRESET.settings.level ==
> + req_settings.lane_settings[0].FFE_PRESET.settings.level)
> + retries_cr++;
> + else if ((dp_get_link_encoding_format(<_settings->link_settings) == DP_8b_10b_ENCODING) &&
> + lt_settings->lane_settings[0].VOLTAGE_SWING ==
> + req_settings.lane_settings[0].VOLTAGE_SWING)
> + retries_cr++;
> + else
> + retries_cr = 0;
> +#else
> /* 7. same lane settings*/
> /* Note: settings are the same for all lanes,
> * so comparing first lane is sufficient*/
> @@ -1138,6 +1493,7 @@ static enum link_training_result perform_clock_recovery_sequence(
> retries_cr++;
> else
> retries_cr = 0;
> +#endif
>
> /* 8. update VS/PE/PC2 in lt_settings*/
> dp_update_drive_settings(lt_settings, req_settings);
> @@ -1172,7 +1528,11 @@ static inline enum link_training_result dp_transition_to_video_idle(
> * TPS4 must be used instead of POST_LT_ADJ_REQ.
> */
> if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
> +#else
> lt_settings->pattern_for_eq == DP_TRAINING_PATTERN_SEQUENCE_4) {
> +#endif
> /* delay 5ms after Main Link output idle pattern and then check
> * DPCD 0202h.
> */
> @@ -1268,6 +1628,32 @@ static inline void decide_8b_10b_training_settings(
> lt_settings->should_set_fec_ready = true;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static inline 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_convert_to_count(
> + link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
> + lt_settings->lttpr_mode = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ?
> + LTTPR_MODE_NON_TRANSPARENT : LTTPR_MODE_TRANSPARENT;
> +}
> +#endif
> +
> void dp_decide_training_settings(
> struct dc_link *link,
> const struct dc_link_settings *link_settings,
> @@ -1275,6 +1661,10 @@ void dp_decide_training_settings(
> {
> if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING)
> decide_8b_10b_training_settings(link, link_settings, lt_settings);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + else if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING)
> + decide_128b_132b_training_settings(link, link_settings, lt_settings);
> +#endif
> }
>
> static void override_training_settings(
> @@ -1303,6 +1693,11 @@ static void override_training_settings(
> lt_settings->pre_emphasis = overrides->pre_emphasis;
> if (overrides->post_cursor2 != NULL)
> lt_settings->post_cursor2 = overrides->post_cursor2;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (overrides->ffe_preset != NULL)
> + lt_settings->ffe_preset = overrides->ffe_preset;
> +#endif
> +
> for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
> lt_settings->lane_settings[lane].VOLTAGE_SWING =
> lt_settings->voltage_swing != NULL ?
> @@ -1489,6 +1884,17 @@ static void print_status_message(
> case LINK_RATE_HIGH3:
> link_rate = "HBR3";
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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;
> +#endif
> default:
> break;
> }
> @@ -1518,6 +1924,20 @@ static void print_status_message(
> case LINK_TRAINING_LINK_LOSS:
> lt_result = "Link loss";
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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;
> +#endif
> default:
> break;
> }
> @@ -1537,6 +1957,9 @@ static void print_status_message(
> }
>
> /* Connectivity log: link training */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
> +#endif
> CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
> link_rate,
> lt_settings->link_settings.lane_count,
> @@ -1619,9 +2042,23 @@ enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_train
>
> static void dpcd_exit_training_mode(struct dc_link *link)
> {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint8_t sink_status = 0;
> + uint8_t i;
> +#endif
>
> /* clear training pattern set */
> dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
> +
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* 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);
> + }
> +#endif
> }
>
> enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
> @@ -1645,6 +2082,131 @@ enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
> return status;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +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_128b_132b_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,
> + struct link_training_settings *lt_settings)
> +{
> + uint8_t loop_count = 0;
> + uint32_t aux_rd_interval = 0;
> + uint32_t wait_time = 0;
> + struct link_training_settings req_settings;
> + union lane_align_status_updated dpcd_lane_status_updated = { {0} };
> + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } };
> + enum link_training_result status = LINK_TRAINING_SUCCESS;
> +
> + /* Transmit 128b/132b_TPS1 over Main-Link and Set TRAINING_PATTERN_SET to 01h */
> + dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, DPRX);
> + dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
> +
> + /* Adjust TX_FFE_PRESET_VALUE as requested */
> + dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
> + &dpcd_lane_status_updated, &req_settings, DPRX);
> + dp_update_drive_settings(lt_settings, req_settings);
> + dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
> + dp_set_hw_lane_settings(link, lt_settings, DPRX);
> + dpcd_set_lane_settings(link, lt_settings, DPRX);
> +
> + /* Transmit 128b/132b_TPS2 over Main-Link and Set TRAINING_PATTERN_SET to 02h */
> + dp_set_hw_training_pattern(link, lt_settings->pattern_for_eq, DPRX);
> + dpcd_set_training_pattern(link, lt_settings->pattern_for_eq);
> +
> + /* poll for channel EQ done */
> + while (status == LINK_TRAINING_SUCCESS) {
> + loop_count++;
> + dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
> + wait_time += aux_rd_interval;
> + dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
> + &dpcd_lane_status_updated, &req_settings, DPRX);
> + dp_update_drive_settings(lt_settings, req_settings);
> + dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
> + 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) {
> + status = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
> + } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
> + status = DP_128b_132b_LT_FAILED;
> + } else {
> + dp_set_hw_lane_settings(link, lt_settings, DPRX);
> + dpcd_set_lane_settings(link, lt_settings, DPRX);
> + }
> + }
> +
> + /* poll for EQ interlane align done */
> + while (status == LINK_TRAINING_SUCCESS) {
> + if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
> + /* pass */
> + break;
> + } else if (wait_time >= lt_settings->eq_wait_time_limit) {
> + status = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
> + } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
> + status = 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;
> + dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
> + &dpcd_lane_status_updated, &req_settings, DPRX);
> + }
> + }
> +
> + return status;
> +}
> +
> +static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
> + struct dc_link *link,
> + struct link_training_settings *lt_settings)
> +{
> + /* Assumption: assume hardware has transmitted eq pattern */
> + enum link_training_result status = LINK_TRAINING_SUCCESS;
> + struct link_training_settings req_settings;
> + union lane_align_status_updated dpcd_lane_status_updated = { {0} };
> + union lane_status dpcd_lane_status[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 (status == LINK_TRAINING_SUCCESS) {
> + dp_wait_for_training_aux_rd_interval(link,
> + lt_settings->cds_pattern_time);
> + wait_time += lt_settings->cds_pattern_time;
> + dp_get_lane_status_and_drive_settings(link, lt_settings, dpcd_lane_status,
> + &dpcd_lane_status_updated, &req_settings, DPRX);
> + 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) {
> + status = DP_128b_132b_LT_FAILED;
> + } else if (wait_time >= lt_settings->cds_wait_time_limit) {
> + status = DP_128b_132b_CDS_DONE_TIMEOUT;
> + }
> + }
> +
> + return status;
> +}
> +#endif
> +
> static enum link_training_result dp_perform_8b_10b_link_training(
> struct dc_link *link,
> struct link_training_settings *lt_settings)
> @@ -1701,6 +2263,35 @@ static enum link_training_result dp_perform_8b_10b_link_training(
> return status;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static enum link_training_result dp_perform_128b_132b_link_training(
> + struct dc_link *link,
> + 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,
> + <_settings->link_settings,
> + &legacy_settings);
> + return dp_perform_8b_10b_link_training(link, &legacy_settings);
> + }
> +
> + dpcd_set_link_settings(link, lt_settings);
> +
> + if (result == LINK_TRAINING_SUCCESS)
> + result = dp_perform_128b_132b_channel_eq_done_sequence(link, lt_settings);
> +
> + if (result == LINK_TRAINING_SUCCESS)
> + result = dp_perform_128b_132b_cds_done_sequence(link, lt_settings);
> +
> + return result;
> +}
> +#endif
> +
> enum link_training_result dc_link_dp_perform_link_training(
> struct dc_link *link,
> const struct dc_link_settings *link_settings,
> @@ -1735,6 +2326,10 @@ enum link_training_result dc_link_dp_perform_link_training(
> */
> if (encoding == DP_8b_10b_ENCODING)
> status = dp_perform_8b_10b_link_training(link, <_settings);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + else if (encoding == DP_128b_132b_ENCODING)
> + status = dp_perform_128b_132b_link_training(link, <_settings);
> +#endif
> else
> ASSERT(0);
>
> @@ -1780,7 +2375,10 @@ bool perform_link_training_with_retries(
> /* 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_enc->funcs->connect_dig_be_to_fe(link_enc,
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(¤t_setting) == DP_8b_10b_ENCODING)
> +#endif
> + link_enc->funcs->connect_dig_be_to_fe(link_enc,
> pipe_ctx->stream_res.stream_enc->id, true);
>
> for (j = 0; j < attempts; ++j) {
> @@ -1950,8 +2548,14 @@ enum link_training_result dc_link_dp_sync_lt_attempt(
> dp_cs_id, link_settings);
>
> /* Set FEC enable */
> - fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
> - dp_set_fec_ready(link, fec_enable);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
> +#endif
> + fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
> + dp_set_fec_ready(link, fec_enable);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + }
> +#endif
>
> if (lt_overrides->alternate_scrambler_reset) {
> if (*lt_overrides->alternate_scrambler_reset)
> @@ -1993,14 +2597,36 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
> * Still shouldn't turn off dp_receiver (DPCD:600h)
> */
> if (link_down == true) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct dc_link_settings link_settings = link->cur_link_settings;
> +#endif
> dp_disable_link_phy(link, link->connector_signal);
> - dp_set_fec_ready(link, false);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
> +#endif
> + dp_set_fec_ready(link, false);
> }
>
> link->sync_lt_in_progress = false;
> return true;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +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;
> +}
> +#endif
> +
> bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
> {
> if (!max_link_enc_cap) {
> @@ -2025,6 +2651,11 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link)
>
> /* get max link encoder capability */
> link->link_enc->funcs->get_max_link_cap(link->link_enc, &max_link_cap);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (max_link_cap.link_rate >= LINK_RATE_UHBR10 &&
> + !link->hpo_dp_link_enc)
> + max_link_cap.link_rate = LINK_RATE_HIGH3;
> +#endif
>
> /* Lower link settings based on sink's link cap */
> if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
> @@ -2045,8 +2676,15 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *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;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + enum dc_link_rate 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;
> +#else
> if (link->dpcd_caps.lttpr_caps.max_link_rate < max_link_cap.link_rate)
> max_link_cap.link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
> +#endif
>
> DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",
> __func__,
> @@ -2205,6 +2843,10 @@ bool dp_verify_link_cap(
> core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
> + reset_dp_hpo_stream_encoders_for_link(link);
> +#endif
> /* TODO implement override and monitor patch later */
>
> /* try to train the link from high to low to
> @@ -2360,7 +3002,17 @@ static struct dc_link_settings get_common_supported_link_settings(
> * We map it to the maximum supported link rate that
> * is smaller than MAX_LINK_BW in this case.
> */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (link_settings.link_rate > LINK_RATE_UHBR20) {
> + link_settings.link_rate = LINK_RATE_UHBR20;
> + } else if (link_settings.link_rate < LINK_RATE_UHBR20 &&
> + link_settings.link_rate > LINK_RATE_UHBR13_5) {
> + link_settings.link_rate = LINK_RATE_UHBR13_5;
> + } else if (link_settings.link_rate < LINK_RATE_UHBR10 &&
> + link_settings.link_rate > LINK_RATE_HIGH3) {
> +#else
> if (link_settings.link_rate > LINK_RATE_HIGH3) {
> +#endif
> link_settings.link_rate = LINK_RATE_HIGH3;
> } else if (link_settings.link_rate < LINK_RATE_HIGH3
> && link_settings.link_rate > LINK_RATE_HIGH2) {
> @@ -2405,6 +3057,14 @@ static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
> static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
> {
> switch (link_rate) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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;
> +#endif
> case LINK_RATE_HIGH3:
> return LINK_RATE_HIGH2;
> case LINK_RATE_HIGH2:
> @@ -2439,11 +3099,55 @@ static enum dc_link_rate increase_link_rate(enum dc_link_rate link_rate)
> return LINK_RATE_HIGH2;
> case LINK_RATE_HIGH2:
> return LINK_RATE_HIGH3;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + case LINK_RATE_HIGH3:
> + return LINK_RATE_UHBR10;
> + case LINK_RATE_UHBR10:
> + return LINK_RATE_UHBR13_5;
> + case LINK_RATE_UHBR13_5:
> + return LINK_RATE_UHBR20;
> +#endif
> default:
> return LINK_RATE_UNKNOWN;
> }
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static bool decide_fallback_link_setting_max_bw_policy(
> + const struct dc_link_settings *max,
> + struct dc_link_settings *cur)
> +{
> + uint8_t cur_idx = 0, next_idx;
> + bool found = 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)
> + break;
> + else
> + next_idx++;
> +
> + 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;
> +}
> +#endif
> +
> /*
> * function: set link rate and lane count fallback based
> * on current link setting and last link training result
> @@ -2459,6 +3163,11 @@ static bool decide_fallback_link_setting(
> {
> if (!current_link_setting)
> return false;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&initial_link_settings) == DP_128b_132b_ENCODING)
> + return decide_fallback_link_setting_max_bw_policy(&initial_link_settings,
> + current_link_setting);
> +#endif
>
> switch (training_result) {
> case LINK_TRAINING_CR_FAIL_LANE0:
> @@ -2831,9 +3540,15 @@ 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;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + unsigned char test_pattern_buffer[
> + (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
> + DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
> +#else
> unsigned char test_pattern_buffer[
> (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
> DP_TEST_80BIT_CUSTOM_PATTERN_7_0)+1] = {0};
> +#endif
> unsigned int test_pattern_size = 0;
> enum dp_test_pattern test_pattern;
> struct dc_link_training_settings link_settings;
> @@ -2899,6 +3614,35 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
> case PHY_TEST_PATTERN_CP2520_3:
> test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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_PULSE:
> + test_pattern = DP_TEST_PATTERN_SQUARE_PULSE;
> + break;
> +#endif
> default:
> test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
> break;
> @@ -2914,6 +3658,27 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
> test_pattern_size);
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) {
> + 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);
> + }
> +#endif
> +
> /* prepare link training settings */
> link_settings.link = link->cur_link_settings;
>
> @@ -2922,6 +3687,24 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
> lane++) {
> dpcd_lane_adjust.raw =
> get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link->cur_link_settings) ==
> + DP_128b_132b_ENCODING) {
> + link_settings.lane_settings[lane].FFE_PRESET.raw =
> + dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
> + } else if (dp_get_link_encoding_format(&link->cur_link_settings) ==
> + DP_8b_10b_ENCODING) {
> + link_settings.lane_settings[lane].VOLTAGE_SWING =
> + (enum dc_voltage_swing)
> + (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
> + link_settings.lane_settings[lane].PRE_EMPHASIS =
> + (enum dc_pre_emphasis)
> + (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
> + link_settings.lane_settings[lane].POST_CURSOR2 =
> + (enum dc_post_cursor2)
> + ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
> + }
> +#else
> link_settings.lane_settings[lane].VOLTAGE_SWING =
> (enum dc_voltage_swing)
> (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
> @@ -2931,6 +3714,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
> link_settings.lane_settings[lane].POST_CURSOR2 =
> (enum dc_post_cursor2)
> ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
> +#endif
> }
>
> for (i = 0; i < 4; i++)
> @@ -3535,6 +4319,43 @@ static void get_active_converter_info(
> dp_hw_fw_revision.ieee_fw_rev,
> sizeof(dp_hw_fw_revision.ieee_fw_rev));
> }
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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);
> + }
> +#endif
> }
>
> static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
> @@ -3594,7 +4415,11 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
>
> bool dp_retrieve_lttpr_cap(struct dc_link *link)
> {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint8_t lttpr_dpcd_data[8];
> +#else
> uint8_t lttpr_dpcd_data[6];
> +#endif
> bool vbios_lttpr_enable = link->dc->caps.vbios_lttpr_enable;
> bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
> enum dc_status status = DC_ERROR_UNEXPECTED;
> @@ -3602,6 +4427,18 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
>
> memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data));
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + bool allow_lttpr_non_transparent_mode = 0;
> +
> + if ((link->dc->config.allow_lttpr_non_transparent_mode.bits.DP2_0 &&
> + link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED)) {
> + allow_lttpr_non_transparent_mode = 1;
> + } else if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
> + !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
> + allow_lttpr_non_transparent_mode = 1;
> + }
> +#endif
> +
> /*
> * Logic to determine LTTPR mode
> */
> @@ -3609,13 +4446,21 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
> if (vbios_lttpr_enable && vbios_lttpr_interop)
> link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
> else if (!vbios_lttpr_enable && vbios_lttpr_interop) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (allow_lttpr_non_transparent_mode)
> +#else
> if (link->dc->config.allow_lttpr_non_transparent_mode)
> +#endif
> link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
> else
> link->lttpr_mode = LTTPR_MODE_TRANSPARENT;
> } else if (!vbios_lttpr_enable && !vbios_lttpr_interop) {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (!allow_lttpr_non_transparent_mode || !link->dc->caps.extended_aux_timeout_support)
> +#else
> if (!link->dc->config.allow_lttpr_non_transparent_mode
> || !link->dc->caps.extended_aux_timeout_support)
> +#endif
> link->lttpr_mode = LTTPR_MODE_NON_LTTPR;
> else
> link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
> @@ -3659,6 +4504,16 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
> lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
> DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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_128b_132b_RATES -
> + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
> +#endif
> +
> /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
> is_lttpr_present = (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
> link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
> @@ -3909,16 +4764,82 @@ static bool retrieve_link_cap(struct dc_link *link)
> DP_DSC_SUPPORT,
> link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
> sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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);
> + }
> +#else
> 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));
> +#endif
> }
>
> if (!dpcd_read_sink_ext_caps(link))
> link->dpcd_sink_ext_caps.raw = 0;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + link->dpcd_caps.channel_coding_cap.raw = dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_CAP - DP_DPCD_REV];
> +
> + 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_128b_132b_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");
> + }
> +#endif
> +
> /* Connectivity log: detection */
> CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
>
> @@ -4389,6 +5310,35 @@ bool dc_link_dp_set_test_pattern(
> case DP_TEST_PATTERN_CP2520_3:
> pattern = PHY_TEST_PATTERN_CP2520_3;
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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_PULSE:
> + pattern = PHY_TEST_PATTERN_SQUARE_PULSE;
> + break;
> +#endif
> default:
> return false;
> }
> @@ -4964,6 +5914,210 @@ enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings
> if ((link_settings->link_rate >= LINK_RATE_LOW) &&
> (link_settings->link_rate <= LINK_RATE_HIGH3))
> return DP_8b_10b_ENCODING;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
> + (link_settings->link_rate <= LINK_RATE_UHBR20))
> + return DP_128b_132b_ENCODING;
> +#endif
> return DP_UNKNOWN_ENCODING;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +// 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;
> +
> + if (status == NULL || status_updated == NULL) {
> + return;
> + }
> +
> + uint8_t dpcd_buf[3] = {0};
> +
> + 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 };
> +
> + 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);
> + } else {
> + /// Leave req_slot_count = 0 if allocate is false.
> + }
> +
> + union payload_table_update_status update_status = { 0 };
> +
> + /// 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);
> +
> + ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT); /// Validation should filter out modes that exceed link BW
> + 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)
> + const uint32_t max_retries = 30;
> + uint32_t retries = 0;
> +
> + 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++;
> + udelay(5000);
> + }
> +
> + 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
> + }
> +
> + 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;
> +
> + 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;
> +
> + 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;
> + }
> +
> + udelay(5000);
> + }
> +
> + 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;
> +}
> +
> +bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
> +{
> + return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
> + pipe_ctx->stream->link->hpo_dp_link_enc &&
> + dc_is_dp_signal(pipe_ctx->stream->signal));
> +}
> +#endif
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
> index 9c51cd09dcf1..0d3800896333 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
> @@ -17,6 +17,7 @@
> #include "link_enc_cfg.h"
> #include "clk_mgr.h"
> #include "inc/link_dpcd.h"
> +#include "dccg.h"
>
> static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
> {
> @@ -111,12 +112,37 @@ void dp_enable_link_phy(
>
> link->cur_link_settings = *link_settings;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
> + /* TODO - DP2.0 HW: notify link rate change here */
> + } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
> + if (dc->clk_mgr->funcs->notify_link_rate_change)
> + dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
> + }
> +#else
> if (dc->clk_mgr->funcs->notify_link_rate_change)
> dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
> -
> +#endif
> if (dmcu != NULL && dmcu->funcs->lock_phy)
> dmcu->funcs->lock_phy(dmcu);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
> + enable_dp_hpo_output(link, link_settings);
> + } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
> + 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);
> + }
> + }
> +#else
> if (dc_is_dp_sst_signal(signal)) {
> link_enc->funcs->enable_dp_output(
> link_enc,
> @@ -128,7 +154,7 @@ void dp_enable_link_phy(
> link_settings,
> clock_source);
> }
> -
> +#endif
> if (dmcu != NULL && dmcu->funcs->unlock_phy)
> dmcu->funcs->unlock_phy(dmcu);
>
> @@ -206,6 +232,9 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
> {
> struct dc *dc = link->ctx->dc;
> struct dmcu *dmcu = dc->res_pool->dmcu;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct hpo_dp_link_encoder *hpo_link_enc = link->hpo_dp_link_enc;
> +#endif
> struct link_encoder *link_enc;
>
> /* Link should always be assigned encoder when en-/disabling. */
> @@ -221,14 +250,28 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
> if (signal == SIGNAL_TYPE_EDP) {
> if (link->dc->hwss.edp_backlight_control)
> link->dc->hwss.edp_backlight_control(link, false);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
> + disable_dp_hpo_output(link, signal);
> + else
> + link_enc->funcs->disable_output(link_enc, signal);
> +#else
> link_enc->funcs->disable_output(link_enc, signal);
> +#endif
> link->dc->hwss.edp_power_control(link, false);
> } else {
> if (dmcu != NULL && dmcu->funcs->lock_phy)
> dmcu->funcs->lock_phy(dmcu);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING &&
> + hpo_link_enc)
> + disable_dp_hpo_output(link, signal);
> + else
> + link_enc->funcs->disable_output(link_enc, signal);
> +#else
> link_enc->funcs->disable_output(link_enc, signal);
> -
> +#endif
> if (dmcu != NULL && dmcu->funcs->unlock_phy)
> dmcu->funcs->unlock_phy(dmcu);
> }
> @@ -273,6 +316,14 @@ bool dp_set_hw_training_pattern(
> case DP_TRAINING_PATTERN_SEQUENCE_4:
> test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
> break;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + 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;
> +#endif
> default:
> break;
> }
> @@ -282,6 +333,10 @@ bool dp_set_hw_training_pattern(
> return true;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +#define DC_LOGGER \
> + link->ctx->logger
> +#endif
> void dp_set_hw_lane_settings(
> struct dc_link *link,
> const struct link_training_settings *link_settings,
> @@ -293,7 +348,20 @@ void dp_set_hw_lane_settings(
> return;
>
> /* call Encoder to set lane settings */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dp_get_link_encoding_format(&link_settings->link_settings) ==
> + DP_128b_132b_ENCODING) {
> + link->hpo_dp_link_enc->funcs->set_ffe(
> + link->hpo_dp_link_enc,
> + &link_settings->link_settings,
> + link_settings->lane_settings[0].FFE_PRESET.raw);
> + } else if (dp_get_link_encoding_format(&link_settings->link_settings)
> + == DP_8b_10b_ENCODING) {
> + encoder->funcs->dp_set_lane_settings(encoder, link_settings);
> + }
> +#else
> encoder->funcs->dp_set_lane_settings(encoder, link_settings);
> +#endif
> }
>
> void dp_set_hw_test_pattern(
> @@ -319,8 +387,28 @@ void dp_set_hw_test_pattern(
> pattern_param.custom_pattern_size = custom_pattern_size;
> pattern_param.dp_panel_mode = dp_get_panel_mode(link);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + enum dp_link_encoding link_encoding_format = dp_get_link_encoding_format(&link->cur_link_settings);
> + switch (link_encoding_format) {
> + case DP_128b_132b_ENCODING:
> + link->hpo_dp_link_enc->funcs->set_link_test_pattern(
> + link->hpo_dp_link_enc, &pattern_param);
> + break;
> + case DP_8b_10b_ENCODING:
> + ASSERT(encoder);
> + encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
> + break;
> + default:
> + DC_LOG_ERROR("%s: Unknown link encoding format.", __func__);
> + break;
> + }
> +#else
> encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
> +#endif
> }
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +#undef DC_LOGGER
> +#endif
>
> void dp_retrain_link_dp_test(struct dc_link *link,
> struct dc_link_settings *link_setting,
> @@ -468,7 +556,12 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
> optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
>
> /* Enable DSC in encoder */
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
> + && !is_dp_128b_132b_signal(pipe_ctx)) {
> +#else
> if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
> +#endif
> 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,
> @@ -495,13 +588,21 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
> /* disable DSC in stream encoder */
> if (dc_is_dp_signal(stream->signal)) {
>
> - 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);
> - }
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (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);
> + else
> +#endif
> + 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);
> + }
> }
>
> /* disable DSC block */
> @@ -562,16 +663,32 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable)
> dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
> 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);
> - pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
> - pipe_ctx->stream_res.stream_enc,
> - true,
> - &dsc_packed_pps[0]);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (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]);
> + else
> +#endif
> + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
> + pipe_ctx->stream_res.stream_enc,
> + true,
> + &dsc_packed_pps[0]);
> }
> } else {
> /* disable DSC PPS in stream encoder */
> if (dc_is_dp_signal(stream->signal)) {
> - pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
> - pipe_ctx->stream_res.stream_enc, false, NULL);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (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);
> + else
> +#endif
> + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
> + pipe_ctx->stream_res.stream_enc, false, NULL);
> }
> }
>
> @@ -593,3 +710,168 @@ bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
> return true;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +#undef DC_LOGGER
> +#define DC_LOGGER \
> + link->ctx->logger
> +
> +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;
> + }
> +
> + //BREAK_TO_DEBUGGER();
> + return TRANSMITTER_UNIPHY_A;
> +}
> +
> +void enable_dp_hpo_output(struct dc_link *link, const struct dc_link_settings *link_settings)
> +{
> + const struct dc *dc = link->dc;
> + enum phyd32clk_clock_source phyd32clk;
> +
> + /* Enable PHY PLL at target bit rate
> + * UHBR10 = 10Gbps (SYMCLK32 = 312.5MHz)
> + * UBR13.5 = 13.5Gbps (SYMCLK32 = 421.875MHz)
> + * UHBR20 = 20Gbps (SYMCLK32 = 625MHz)
> + */
> + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
> + switch (link_settings->link_rate) {
> + case LINK_RATE_UHBR10:
> + dm_set_phyd32clk(dc->ctx, 312500);
> + break;
> + case LINK_RATE_UHBR13_5:
> + dm_set_phyd32clk(dc->ctx, 412875);
> + break;
> + case LINK_RATE_UHBR20:
> + dm_set_phyd32clk(dc->ctx, 625000);
> + break;
> + default:
> + return;
> + }
> + } else {
> + /* DP2.0 HW: call transmitter control to enable PHY */
> + link->hpo_dp_link_enc->funcs->enable_link_phy(
> + link->hpo_dp_link_enc,
> + link_settings,
> + link->link_enc->transmitter);
> + }
> +
> + /* DCCG muxing and DTBCLK DTO */
> + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
> + dc->res_pool->dccg->funcs->set_physymclk(
> + dc->res_pool->dccg,
> + link->link_enc_hw_inst,
> + PHYSYMCLK_FORCE_SRC_PHYD32CLK,
> + true);
> +
> + phyd32clk = get_phyd32clk_src(link);
> + dc->res_pool->dccg->funcs->enable_symclk32_le(
> + dc->res_pool->dccg,
> + link->hpo_dp_link_enc->inst,
> + phyd32clk);
> + link->hpo_dp_link_enc->funcs->link_enable(
> + link->hpo_dp_link_enc,
> + link_settings->lane_count);
> + }
> +}
> +
> +void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal)
> +{
> + const struct dc *dc = link->dc;
> +
> + link->hpo_dp_link_enc->funcs->link_disable(link->hpo_dp_link_enc);
> +
> + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
> + dc->res_pool->dccg->funcs->disable_symclk32_le(
> + dc->res_pool->dccg,
> + link->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);
> + } else {
> + /* DP2.0 HW: call transmitter control to disable PHY */
> + link->hpo_dp_link_enc->funcs->disable_link_phy(
> + link->hpo_dp_link_enc,
> + signal);
> + }
> +}
> +
> +void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable)
> +{
> + struct dc_stream_state *stream = pipe_ctx->stream;
> + struct dc *dc = pipe_ctx->stream->ctx->dc;
> + struct pipe_ctx *odm_pipe;
> + int odm_combine_num_segments = 1;
> + enum phyd32clk_clock_source phyd32clk;
> +
> + if (enable) {
> + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
> + odm_combine_num_segments++;
> +
> + dc->res_pool->dccg->funcs->set_dpstreamclk(
> + dc->res_pool->dccg,
> + DTBCLK0,
> + pipe_ctx->stream_res.tg->inst);
> +
> + phyd32clk = get_phyd32clk_src(stream->link);
> + dc->res_pool->dccg->funcs->enable_symclk32_se(
> + dc->res_pool->dccg,
> + pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
> + phyd32clk);
> +
> + dc->res_pool->dccg->funcs->set_dtbclk_dto(
> + dc->res_pool->dccg,
> + pipe_ctx->stream_res.tg->inst,
> + stream->phy_pix_clk,
> + odm_combine_num_segments,
> + &stream->timing);
> + } else {
> + dc->res_pool->dccg->funcs->set_dtbclk_dto(
> + dc->res_pool->dccg,
> + pipe_ctx->stream_res.tg->inst,
> + 0,
> + 0,
> + &stream->timing);
> + dc->res_pool->dccg->funcs->disable_symclk32_se(
> + dc->res_pool->dccg,
> + pipe_ctx->stream_res.hpo_dp_stream_enc->inst);
> + dc->res_pool->dccg->funcs->set_dpstreamclk(
> + dc->res_pool->dccg,
> + REFCLK,
> + pipe_ctx->stream_res.tg->inst);
> + }
> +}
> +
> +void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link)
> +{
> + const struct dc *dc = link->dc;
> + struct dc_state *state = dc->current_state;
> + uint8_t i;
> +
> + for (i = 0; i < MAX_PIPES; i++) {
> + if (state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc &&
> + state->res_ctx.pipe_ctx[i].stream &&
> + state->res_ctx.pipe_ctx[i].stream->link == link &&
> + !state->res_ctx.pipe_ctx[i].stream->dpms_off) {
> + setup_dp_hpo_stream(&state->res_ctx.pipe_ctx[i], false);
> + }
> + }
> +}
> +
> +#undef DC_LOGGER
> +#endif
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> index a60396d5be44..57420bf10786 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
> @@ -41,6 +41,7 @@
> #include "set_mode_types.h"
> #include "virtual/virtual_stream_encoder.h"
> #include "dpcd_defs.h"
> +#include "dc_link_dp.h"
>
> #if defined(CONFIG_DRM_AMD_DC_SI)
> #include "dce60/dce60_resource.h"
> @@ -346,6 +347,29 @@ bool resource_construct(
> }
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + pool->hpo_dp_stream_enc_count = 0;
> + if (create_funcs->create_hpo_dp_stream_encoder) {
> + for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
> + pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
> + if (pool->hpo_dp_stream_enc[i] == NULL)
> + DC_ERR("DC: failed to create HPO DP stream encoder!\n");
> + pool->hpo_dp_stream_enc_count++;
> +
> + }
> + }
> +
> + pool->hpo_dp_link_enc_count = 0;
> + if (create_funcs->create_hpo_dp_link_encoder) {
> + for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
> + pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
> + if (pool->hpo_dp_link_enc[i] == NULL)
> + DC_ERR("DC: failed to create HPO DP link encoder!\n");
> + pool->hpo_dp_link_enc_count++;
> + }
> + }
> +#endif
> +
> #if defined(CONFIG_DRM_AMD_DC_DCN)
> for (i = 0; i < caps->num_mpc_3dlut; i++) {
> pool->mpc_lut[i] = dc_create_3dlut_func();
> @@ -1665,6 +1689,22 @@ static void update_stream_engine_usage(
> }
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static void update_hpo_dp_stream_engine_usage(
> + struct resource_context *res_ctx,
> + const struct resource_pool *pool,
> + struct hpo_dp_stream_encoder *hpo_dp_stream_enc,
> + bool acquired)
> +{
> + int i;
> +
> + for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
> + if (pool->hpo_dp_stream_enc[i] == hpo_dp_stream_enc)
> + res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
> + }
> +}
> +#endif
> +
> /* TODO: release audio object */
> void update_audio_usage(
> struct resource_context *res_ctx,
> @@ -1709,6 +1749,26 @@ static int acquire_first_free_pipe(
> return -1;
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
> + struct resource_context *res_ctx,
> + const struct resource_pool *pool,
> + struct dc_stream_state *stream)
> +{
> + int i;
> +
> + for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
> + if (!res_ctx->is_hpo_dp_stream_enc_acquired[i] &&
> + pool->hpo_dp_stream_enc[i]) {
> +
> + return pool->hpo_dp_stream_enc[i];
> + }
> + }
> +
> + return NULL;
> +}
> +#endif
> +
> static struct audio *find_first_free_audio(
> struct resource_context *res_ctx,
> const struct resource_pool *pool,
> @@ -1799,6 +1859,15 @@ enum dc_status dc_remove_stream_from_ctx(
> if (dc->res_pool->funcs->link_enc_unassign)
> dc->res_pool->funcs->link_enc_unassign(new_ctx, del_pipe->stream);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(del_pipe)) {
> + update_hpo_dp_stream_engine_usage(
> + &new_ctx->res_ctx, dc->res_pool,
> + del_pipe->stream_res.hpo_dp_stream_enc,
> + false);
> + }
> +#endif
> +
> if (del_pipe->stream_res.audio)
> update_audio_usage(
> &new_ctx->res_ctx,
> @@ -2051,6 +2120,31 @@ enum dc_status resource_map_pool_resources(
> pipe_ctx->stream_res.stream_enc,
> true);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* Allocate DP HPO Stream Encoder based on signal, hw capabilities
> + * and link settings
> + */
> + if (dc_is_dp_signal(stream->signal) &&
> + dc->caps.dp_hpo) {
> + struct dc_link_settings link_settings = {0};
> +
> + decide_link_settings(stream, &link_settings);
> + if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
> + pipe_ctx->stream_res.hpo_dp_stream_enc =
> + find_first_free_match_hpo_dp_stream_enc_for_link(
> + &context->res_ctx, pool, stream);
> +
> + if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
> + return DC_NO_STREAM_ENC_RESOURCE;
> +
> + update_hpo_dp_stream_engine_usage(
> + &context->res_ctx, pool,
> + pipe_ctx->stream_res.hpo_dp_stream_enc,
> + true);
> + }
> + }
> +#endif
> +
> /* TODO: Add check if ASIC support and EDID audio */
> if (!stream->converter_disable_audio &&
> dc_is_audio_capable_signal(pipe_ctx->stream->signal) &&
> @@ -2726,6 +2820,11 @@ bool pipe_need_reprogram(
> if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
> return true;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
> + return true;
> +#endif
> +
> /* DIG link encoder resource assignment for stream changed. */
> if (pipe_ctx_old->stream->link_enc != pipe_ctx->stream->link_enc)
> return true;
> @@ -2975,3 +3074,22 @@ void get_audio_check(struct audio_info *aud_modes,
> }
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
> + const struct resource_pool *pool)
> +{
> + uint8_t i;
> + struct hpo_dp_link_encoder *enc = NULL;
> +
> + ASSERT(pool->hpo_dp_link_enc_count <= MAX_HPO_DP2_LINK_ENCODERS);
> +
> + for (i = 0; i < pool->hpo_dp_link_enc_count; i++) {
> + if (pool->hpo_dp_link_enc[i]->transmitter == TRANSMITTER_UNKNOWN) {
> + enc = pool->hpo_dp_link_enc[i];
> + break;
> + }
> + }
> +
> + return enc;
> +}
> +#endif
> diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
> index 03b81e5c5d67..19114cd3abf6 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc.h
> @@ -183,6 +183,9 @@ struct dc_caps {
> unsigned int cursor_cache_size;
> struct dc_plane_cap planes[MAX_PLANES];
> struct dc_color_caps color;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + bool dp_hpo;
> +#endif
> bool vbios_lttpr_aware;
> bool vbios_lttpr_enable;
> };
> @@ -289,7 +292,15 @@ struct dc_cap_funcs {
>
> struct link_training_settings;
>
> -
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +union allow_lttpr_non_transparent_mode {
> + struct {
> + bool DP1_4A : 1;
> + bool DP2_0 : 1;
> + } bits;
> + unsigned char raw;
> +};
> +#endif
> /* Structure to hold configuration flags set by dm at dc creation. */
> struct dc_config {
> bool gpu_vm_support;
> @@ -302,7 +313,11 @@ struct dc_config {
> bool edp_no_power_sequencing;
> bool force_enum_edp;
> bool forced_clocks;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + union allow_lttpr_non_transparent_mode allow_lttpr_non_transparent_mode;
> +#else
> bool allow_lttpr_non_transparent_mode;
> +#endif
> bool multi_mon_pp_mclk_switch;
> bool disable_dmcu;
> bool enable_4to1MPC;
> @@ -614,6 +629,10 @@ struct dc_debug_options {
> bool enable_dmcub_surface_flip;
> bool usbc_combo_phy_reset_wa;
> bool enable_dram_clock_change_one_display_vactive;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* TODO - remove once tested */
> + bool legacy_dp2_lt;
> +#endif
> union mem_low_power_enable_options enable_mem_low_power;
> bool force_vblank_alignment;
>
> @@ -1146,6 +1165,12 @@ struct dpcd_caps {
> struct dc_lttpr_caps lttpr_caps;
> struct psr_caps psr_caps;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + union dp_128b_132b_supported_link_rates dp_128b_132b_supported_link_rates;
> + union dp_main_line_channel_coding_cap channel_coding_cap;
> + union dp_sink_video_fallback_formats fallback_formats;
> + union dp_fec_capability1 fec_cap1;
> +#endif
> };
>
> union dpcd_sink_ext_caps {
> diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
> index 4f54bde1bb1c..a5e798b5da79 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
> @@ -53,7 +53,17 @@ enum dc_link_rate {
> LINK_RATE_RBR2 = 0x0C, // Rate_5 (RBR2)- 3.24 Gbps/Lane
> LINK_RATE_RATE_6 = 0x10, // Rate_6 - 4.32 Gbps/Lane
> LINK_RATE_HIGH2 = 0x14, // Rate_7 (HBR2)- 5.40 Gbps/Lane
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + LINK_RATE_HIGH3 = 0x1E, // Rate_8 (HBR3)- 8.10 Gbps/Lane
> + /* Starting from DP2.0 link rate enum directly represents actual
> + * link rate value in unit of 10 mbps
> + */
> + LINK_RATE_UHBR10 = 1000, // UHBR10 - 10.0 Gbps/Lane
> + LINK_RATE_UHBR13_5 = 1350, // UHBR13.5 - 13.5 Gbps/Lane
> + LINK_RATE_UHBR20 = 2000, // UHBR10 - 20.0 Gbps/Lane
> +#else
> LINK_RATE_HIGH3 = 0x1E // Rate_8 (HBR3)- 8.10 Gbps/Lane
> +#endif
> };
A simplification you can do here is to move out the following line out
of the guard:
LINK_RATE_HIGH3 = 0x1E, // Rate_8 (HBR3)- 8.10 Gbps/Lane
It's okay to end an enum list with a comma.
>
> enum dc_link_spread {
> @@ -90,17 +100,47 @@ enum dc_post_cursor2 {
> POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3,
> };
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +enum dc_dp_ffe_preset_level {
> + DP_FFE_PRESET_LEVEL0 = 0,
> + DP_FFE_PRESET_LEVEL1,
> + DP_FFE_PRESET_LEVEL2,
> + DP_FFE_PRESET_LEVEL3,
> + DP_FFE_PRESET_LEVEL4,
> + DP_FFE_PRESET_LEVEL5,
> + DP_FFE_PRESET_LEVEL6,
> + DP_FFE_PRESET_LEVEL7,
> + DP_FFE_PRESET_LEVEL8,
> + DP_FFE_PRESET_LEVEL9,
> + DP_FFE_PRESET_LEVEL10,
> + DP_FFE_PRESET_LEVEL11,
> + DP_FFE_PRESET_LEVEL12,
> + DP_FFE_PRESET_LEVEL13,
> + DP_FFE_PRESET_LEVEL14,
> + DP_FFE_PRESET_LEVEL15,
> + DP_FFE_PRESET_MAX_LEVEL = DP_FFE_PRESET_LEVEL15,
> +};
> +#endif
> +
> enum dc_dp_training_pattern {
> DP_TRAINING_PATTERN_SEQUENCE_1 = 0,
> DP_TRAINING_PATTERN_SEQUENCE_2,
> DP_TRAINING_PATTERN_SEQUENCE_3,
> DP_TRAINING_PATTERN_SEQUENCE_4,
> DP_TRAINING_PATTERN_VIDEOIDLE,
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + DP_128b_132b_TPS1,
> + DP_128b_132b_TPS2,
> + DP_128b_132b_TPS2_CDS,
> +#endif
> };
>
> enum dp_link_encoding {
> DP_UNKNOWN_ENCODING = 0,
> DP_8b_10b_ENCODING = 1,
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + DP_128b_132b_ENCODING = 2,
> +#endif
> };
>
> struct dc_link_settings {
> @@ -112,10 +152,26 @@ struct dc_link_settings {
> bool dpcd_source_device_specific_field_support;
> };
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +union dc_dp_ffe_preset {
> + struct {
> + uint8_t level : 4;
> + uint8_t reserved : 1;
> + uint8_t no_preshoot : 1;
> + uint8_t no_deemphasis : 1;
> + uint8_t method2 : 1;
> + } settings;
> + uint8_t raw;
> +};
> +#endif
> +
> struct dc_lane_settings {
> enum dc_voltage_swing VOLTAGE_SWING;
> enum dc_pre_emphasis PRE_EMPHASIS;
> enum dc_post_cursor2 POST_CURSOR2;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + union dc_dp_ffe_preset FFE_PRESET;
> +#endif
> };
>
> struct dc_link_training_settings {
> @@ -127,6 +183,9 @@ struct dc_link_training_overrides {
> enum dc_voltage_swing *voltage_swing;
> enum dc_pre_emphasis *pre_emphasis;
> enum dc_post_cursor2 *post_cursor2;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + union dc_dp_ffe_preset *ffe_preset;
> +#endif
>
> uint16_t *cr_pattern_time;
> uint16_t *eq_pattern_time;
> @@ -140,6 +199,16 @@ struct dc_link_training_overrides {
> bool *fec_enable;
> };
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +union payload_table_update_status {
> + struct {
> + uint8_t VC_PAYLOAD_TABLE_UPDATED:1;
> + uint8_t ACT_HANDLED:1;
> + } bits;
> + uint8_t raw;
> +};
> +#endif
> +
> union dpcd_rev {
> struct {
> uint8_t MINOR:4;
> @@ -227,7 +296,14 @@ union lane_align_status_updated {
> struct {
> uint8_t INTERLANE_ALIGN_DONE:1;
> uint8_t POST_LT_ADJ_REQ_IN_PROGRESS:1;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint8_t EQ_INTERLANE_ALIGN_DONE_128b_132b:1;
> + uint8_t CDS_INTERLANE_ALIGN_DONE_128b_132b:1;
> + uint8_t LT_FAILED_128b_132b:1;
> + uint8_t RESERVED:1;
> +#else
> uint8_t RESERVED:4;
> +#endif
> uint8_t DOWNSTREAM_PORT_STATUS_CHANGED:1;
> uint8_t LINK_STATUS_UPDATED:1;
> } bits;
> @@ -240,6 +316,12 @@ union lane_adjust {
> uint8_t PRE_EMPHASIS_LANE:2;
> uint8_t RESERVED:4;
> } bits;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct {
> + uint8_t PRESET_VALUE :4;
> + uint8_t RESERVED :4;
> + } tx_ffe;
> +#endif
> uint8_t raw;
> };
>
> @@ -269,6 +351,12 @@ union dpcd_training_lane {
> uint8_t MAX_PRE_EMPHASIS_REACHED:1;
> uint8_t RESERVED:2;
> } bits;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct {
> + uint8_t PRESET_VALUE :4;
> + uint8_t RESERVED :4;
> + } tx_ffe;
> +#endif
> uint8_t raw;
> };
>
> @@ -551,12 +639,18 @@ union test_response {
>
> union phy_test_pattern {
> struct {
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* This field is 7 bits for DP2.0 */
> + uint8_t PATTERN :7;
> + uint8_t RESERVED :1;
> +#else
> /* DpcdPhyTestPatterns. This field is 2 bits for DP1.1
> * and 3 bits for DP1.2.
> */
> uint8_t PATTERN :3;
> /* BY speci, bit7:2 is 0 for DP1.1. */
> uint8_t RESERVED :5;
> +#endif
> } bits;
> uint8_t raw;
> };
> @@ -634,7 +728,14 @@ union dpcd_fec_capability {
> uint8_t UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
> uint8_t CORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
> uint8_t BIT_ERROR_COUNT_CAPABLE:1;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + uint8_t PARITY_BLOCK_ERROR_COUNT_CAPABLE:1;
> + uint8_t ARITY_BIT_ERROR_COUNT_CAPABLE:1;
> + uint8_t FEC_RUNNING_INDICATOR_SUPPORTED:1;
> + uint8_t FEC_ERROR_REPORTING_POLICY_SUPPORTED:1;
> +#else
> uint8_t RESERVED:4;
> +#endif
> } bits;
> uint8_t raw;
> };
> @@ -758,4 +859,125 @@ struct psr_caps {
> bool psr_exit_link_training_required;
> };
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +#define DP_MAIN_LINK_CHANNEL_CODING_CAP 0x006
> +#define DP_SINK_VIDEO_FALLBACK_FORMATS 0x020
> +#define DP_FEC_CAPABILITY_1 0x091
> +#define DP_DFP_CAPABILITY_EXTENSION_SUPPORT 0x0A3
> +#define DP_DSC_CONFIGURATION 0x161
> +#define DP_PHY_SQUARE_PATTERN 0x249
> +#define DP_128b_132b_SUPPORTED_LINK_RATES 0x2215
> +#define DP_128b_132b_TRAINING_AUX_RD_INTERVAL 0x2216
> +#define DP_TEST_264BIT_CUSTOM_PATTERN_7_0 0X2230
> +#define DP_TEST_264BIT_CUSTOM_PATTERN_263_256 0X2250
> +#define DP_DSC_SUPPORT_AND_DECODER_COUNT 0x2260
> +#define DP_DSC_MAX_SLICE_COUNT_AND_AGGREGATION_0 0x2270
> +# define DP_DSC_DECODER_0_MAXIMUM_SLICE_COUNT_MASK (1 << 0)
> +# define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_MASK (0b111 << 1)
> +# define DP_DSC_DECODER_0_AGGREGATION_SUPPORT_SHIFT 1
> +# define DP_DSC_DECODER_COUNT_MASK (0b111 << 5)
> +# define DP_DSC_DECODER_COUNT_SHIFT 5
> +#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108
> +#define DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER 0xF0006
> +#define DP_PHY_REPEATER_128b_132b_RATES 0xF0007
> +#define DP_128b_132b_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xF0022
> +#define DP_INTRA_HOP_AUX_REPLY_INDICATION (1 << 3)
> +/* TODO - Use DRM header to replace above once available */
> +
> +union dp_main_line_channel_coding_cap {
> + struct {
> + uint8_t DP_8b_10b_SUPPORTED :1;
> + uint8_t DP_128b_132b_SUPPORTED :1;
> + uint8_t RESERVED :6;
> + } bits;
> + uint8_t raw;
> +};
> +
> +union dp_main_link_channel_coding_lttpr_cap {
> + struct {
> + uint8_t DP_128b_132b_SUPPORTED :1;
> + uint8_t RESERVED :7;
> + } bits;
> + uint8_t raw;
> +};
> +
> +union dp_128b_132b_supported_link_rates {
> + struct {
> + uint8_t UHBR10 :1;
> + uint8_t UHBR20 :1;
> + uint8_t UHBR13_5:1;
> + uint8_t RESERVED:5;
> + } bits;
> + uint8_t raw;
> +};
> +
> +union dp_128b_132b_supported_lttpr_link_rates {
> + struct {
> + uint8_t UHBR10 :1;
> + uint8_t UHBR13_5:1;
> + uint8_t UHBR20 :1;
> + uint8_t RESERVED:5;
> + } bits;
> + uint8_t raw;
> +};
> +
> +union dp_sink_video_fallback_formats {
> + struct {
> + uint8_t dp_1024x768_60Hz_24bpp_support :1;
> + uint8_t dp_1280x720_60Hz_24bpp_support :1;
> + uint8_t dp_1920x1080_60Hz_24bpp_support :1;
> + uint8_t RESERVED :5;
> + } bits;
> + uint8_t raw;
> +};
> +
> +union dp_fec_capability1 {
> + struct {
> + uint8_t AGGREGATED_ERROR_COUNTERS_CAPABLE :1;
> + uint8_t RESERVED :7;
> + } bits;
> + uint8_t raw;
> +};
> +
> +struct dp_color_depth_caps {
> + uint8_t support_6bpc :1;
> + uint8_t support_8bpc :1;
> + uint8_t support_10bpc :1;
> + uint8_t support_12bpc :1;
> + uint8_t support_16bpc :1;
> + uint8_t RESERVED :3;
> +};
> +
> +struct dp_encoding_format_caps {
> + uint8_t support_rgb :1;
> + uint8_t support_ycbcr444:1;
> + uint8_t support_ycbcr422:1;
> + uint8_t support_ycbcr420:1;
> + uint8_t RESERVED :4;
> +};
> +
> +union dp_dfp_cap_ext {
> + struct {
> + uint8_t supported;
> + uint8_t max_pixel_rate_in_mps[2];
> + uint8_t max_video_h_active_width[2];
> + uint8_t max_video_v_active_height[2];
> + struct dp_encoding_format_caps encoding_format_caps;
> + struct dp_color_depth_caps rgb_color_depth_caps;
> + struct dp_color_depth_caps ycbcr444_color_depth_caps;
> + struct dp_color_depth_caps ycbcr422_color_depth_caps;
> + struct dp_color_depth_caps ycbcr420_color_depth_caps;
> + } fields;
> + uint8_t raw[12];
> +};
> +
> +union dp_128b_132b_training_aux_rd_interval {
> + struct {
> + uint8_t VALUE :7;
> + uint8_t UNIT :1;
> + } bits;
> + uint8_t raw;
> +};
> +#endif
> +
> #endif /* DC_DP_TYPES_H */
> diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
> index 4450078213a2..4fdb24ba24af 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc_link.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
> @@ -154,6 +154,9 @@ struct dc_link {
>
> struct panel_cntl *panel_cntl;
> struct link_encoder *link_enc;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct hpo_dp_link_encoder *hpo_dp_link_enc;
> +#endif
> struct graphics_object_id link_id;
> /* Endpoint type distinguishes display endpoints which do not have entries
> * in the BIOS connector table from those that do. Helps when tracking link
> diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
> index c1532930169b..3c109c805447 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc_types.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
> @@ -395,9 +395,27 @@ struct dc_lttpr_caps {
> uint8_t max_link_rate;
> uint8_t phy_repeater_cnt;
> uint8_t max_ext_timeout;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
> + union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
> +#endif
> uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
> };
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +struct dc_dongle_dfp_cap_ext {
> + bool supported;
> + uint16_t max_pixel_rate_in_mps;
> + uint16_t max_video_h_active_width;
> + uint16_t max_video_v_active_height;
> + struct dp_encoding_format_caps encoding_format_caps;
> + struct dp_color_depth_caps rgb_color_depth_caps;
> + struct dp_color_depth_caps ycbcr444_color_depth_caps;
> + struct dp_color_depth_caps ycbcr422_color_depth_caps;
> + struct dp_color_depth_caps ycbcr420_color_depth_caps;
> +};
> +#endif
> +
> struct dc_dongle_caps {
> /* dongle type (DP converter, CV smart dongle) */
> enum display_dongle_type dongle_type;
> @@ -411,6 +429,9 @@ struct dc_dongle_caps {
> bool is_dp_hdmi_ycbcr420_converter;
> uint32_t dp_hdmi_max_bpc;
> uint32_t dp_hdmi_max_pixel_clk_in_khz;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + struct dc_dongle_dfp_cap_ext dfp_cap_ext;
> +#endif
> };
> /* Scaling format */
> enum scaling_transformation {
> diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
> index 62d595ded866..33743dc2631c 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
> @@ -1108,8 +1108,17 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
> clk_mgr->funcs->enable_pme_wa(clk_mgr);
> /* un-mute audio */
> /* TODO: audio should be per stream rather than per link */
> - pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx))
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
> + pipe_ctx->stream_res.hpo_dp_stream_enc, false);
> + else
> + pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
> pipe_ctx->stream_res.stream_enc, false);
> +#else
> + pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
> + pipe_ctx->stream_res.stream_enc, false);
> +#endif
> if (pipe_ctx->stream_res.audio)
> pipe_ctx->stream_res.audio->enabled = true;
> }
> @@ -1129,14 +1138,32 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
> if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false)
> return;
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx))
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
> + pipe_ctx->stream_res.hpo_dp_stream_enc, true);
> + else
> + pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
> + pipe_ctx->stream_res.stream_enc, true);
> +#else
> pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
> pipe_ctx->stream_res.stream_enc, true);
> +#endif
> if (pipe_ctx->stream_res.audio) {
> pipe_ctx->stream_res.audio->enabled = false;
>
> if (dc_is_dp_signal(pipe_ctx->stream->signal))
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx))
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
> + pipe_ctx->stream_res.hpo_dp_stream_enc);
> + else
> + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
> + pipe_ctx->stream_res.stream_enc);
> +#else
> pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
> pipe_ctx->stream_res.stream_enc);
> +#endif
> else
> pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
> pipe_ctx->stream_res.stream_enc);
> @@ -1166,16 +1193,37 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
> pipe_ctx->stream_res.stream_enc);
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
> + pipe_ctx->stream_res.hpo_dp_stream_enc);
> + } else if (dc_is_dp_signal(pipe_ctx->stream->signal))
> +#else
> if (dc_is_dp_signal(pipe_ctx->stream->signal))
> +#endif
> pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets(
> pipe_ctx->stream_res.stream_enc);
>
> dc->hwss.disable_audio_stream(pipe_ctx);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->disable(
> + pipe_ctx->stream_res.hpo_dp_stream_enc);
> + setup_dp_hpo_stream(pipe_ctx, false);
> + /* TODO - DP2.0 HW: unmap stream from link encoder here */
> + } else {
> + link->link_enc->funcs->connect_dig_be_to_fe(
> + link->link_enc,
> + pipe_ctx->stream_res.stream_enc->id,
> + false);
> + }
> +#else
> link->link_enc->funcs->connect_dig_be_to_fe(
> link->link_enc,
> pipe_ctx->stream_res.stream_enc->id,
> false);
> +#endif
>
> }
>
> @@ -1210,7 +1258,15 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
> link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
> }
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
> + pipe_ctx->stream_res.hpo_dp_stream_enc);
> + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
> +#else
> if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
> +#endif
> pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
>
> if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) {
> @@ -1451,10 +1507,23 @@ static enum dc_status apply_single_controller_ctx_to_hw(
> build_audio_output(context, pipe_ctx, &audio_output);
>
> if (dc_is_dp_signal(pipe_ctx->stream->signal))
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + if (is_dp_128b_132b_signal(pipe_ctx))
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
> + pipe_ctx->stream_res.hpo_dp_stream_enc,
> + pipe_ctx->stream_res.audio->inst,
> + &pipe_ctx->stream->audio_info);
> + else
> + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
> + pipe_ctx->stream_res.stream_enc,
> + pipe_ctx->stream_res.audio->inst,
> + &pipe_ctx->stream->audio_info);
> +#else
> pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
> pipe_ctx->stream_res.stream_enc,
> pipe_ctx->stream_res.audio->inst,
> &pipe_ctx->stream->audio_info);
> +#endif
> else
> pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
> pipe_ctx->stream_res.stream_enc,
> @@ -1469,10 +1538,17 @@ static enum dc_status apply_single_controller_ctx_to_hw(
> &pipe_ctx->stream->audio_info);
> }
>
> - /* */
> - /* Do not touch stream timing on seamless boot optimization. */
> - if (!pipe_ctx->stream->apply_seamless_boot_optimization)
> - hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* DCN3.1 FPGA Workaround
> + * Need to enable HPO DP Stream Encoder before setting OTG master enable.
> + * To do so, move calling function enable_stream_timing to only be done AFTER calling
> + * function core_link_enable_stream
> + */
> + if (!(hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)))
> + /* */
> + /* Do not touch stream timing on seamless boot optimization. */
> + if (!pipe_ctx->stream->apply_seamless_boot_optimization)
> + hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
>
> if (hws->funcs.setup_vupdate_interrupt)
> hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
> @@ -1482,6 +1558,12 @@ static enum dc_status apply_single_controller_ctx_to_hw(
> if (pipe_ctx->stream_res.tg->funcs->set_drr)
> pipe_ctx->stream_res.tg->funcs->set_drr(
> pipe_ctx->stream_res.tg, ¶ms);
> +#else
> + /* */
> + /* Do not touch stream timing on seamless boot optimization. */
> + if (!pipe_ctx->stream->apply_seamless_boot_optimization)
> + hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
> +#endif
>
> // DRR should set trigger event to monitor surface update event
> if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
> @@ -1526,6 +1608,18 @@ static enum dc_status apply_single_controller_ctx_to_hw(
> if (!stream->dpms_off)
> core_link_enable_stream(context, pipe_ctx);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* DCN3.1 FPGA Workaround
> + * Need to enable HPO DP Stream Encoder before setting OTG master enable.
> + * To do so, move calling function enable_stream_timing to only be done AFTER calling
> + * function core_link_enable_stream
> + */
> + if (hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)) {
> + if (!pipe_ctx->stream->apply_seamless_boot_optimization)
> + hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
> + }
> +#endif
> +
> pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
>
> pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
> index e4701825b5a0..2dc4b4e4ba02 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
> @@ -1460,5 +1460,14 @@ void dcn10_link_encoder_get_max_link_cap(struct link_encoder *enc,
> if (enc->features.flags.bits.IS_HBR3_CAPABLE)
> max_link_cap.link_rate = LINK_RATE_HIGH3;
>
> + if (enc->features.flags.bits.IS_UHBR10_CAPABLE)
> + max_link_cap.link_rate = LINK_RATE_UHBR10;
> +
> + if (enc->features.flags.bits.IS_UHBR13_5_CAPABLE)
> + max_link_cap.link_rate = LINK_RATE_UHBR13_5;
> +
> + if (enc->features.flags.bits.IS_UHBR20_CAPABLE)
> + max_link_cap.link_rate = LINK_RATE_UHBR20;
> +
> *link_settings = max_link_cap;
> }
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
> index a47ba1d45be9..b9276da87872 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
> @@ -2135,7 +2135,12 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
>
> params.link_settings.link_rate = link_settings->link_rate;
>
> - if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
> + pipe_ctx->stream_res.hpo_dp_stream_enc,
> + pipe_ctx->stream_res.tg->inst);
> + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
> if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1)
> params.timing.pix_clk_100hz /= 2;
> pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
> @@ -2380,8 +2385,19 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
> * disconnect them during disable_stream
> * BY this, it is logic clean to separate stream and link
> */
> - link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
> - pipe_ctx->stream_res.stream_enc->id, true);
> + if (is_dp_128b_132b_signal(pipe_ctx)) {
> + setup_dp_hpo_stream(pipe_ctx, true);
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->enable_stream(
> + pipe_ctx->stream_res.hpo_dp_stream_enc);
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->map_stream_to_link(
> + pipe_ctx->stream_res.hpo_dp_stream_enc,
> + pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
> + link->hpo_dp_link_enc->inst);
> + }
> +
> + if (!is_dp_128b_132b_signal(pipe_ctx))
> + link->link_enc->funcs->connect_dig_be_to_fe(
> + link->link_enc, pipe_ctx->stream_res.stream_enc->id, true);
>
> if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
> if (link->dc->hwss.program_dmdata_engine)
> @@ -2406,7 +2422,9 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
>
> /* enable audio only within mode set */
> if (pipe_ctx->stream_res.audio != NULL) {
> - if (dc_is_dp_signal(pipe_ctx->stream->signal))
> + if (is_dp_128b_132b_signal(pipe_ctx))
> + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.hpo_dp_stream_enc);
> + else 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);
> }
> }
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
> index e3e01b17c164..0159700c148a 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
> @@ -63,6 +63,7 @@
> #include "dcn20_dccg.h"
> #include "dcn20_vmid.h"
> #include "dc_link_ddc.h"
> +#include "dc_link_dp.h"
> #include "dce/dce_panel_cntl.h"
>
> #include "navi10_ip_offset.h"
> @@ -1604,6 +1605,7 @@ static void get_pixel_clock_parameters(
> pixel_clk_params->signal_type = pipe_ctx->stream->signal;
> pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1;
> /* TODO: un-hardcode*/
> + /* TODO - DP2.0 HW: calculate requested_sym_clk for UHBR rates */
> pixel_clk_params->requested_sym_clk = LINK_RATE_LOW *
> LINK_RATE_REF_FREQ_IN_KHZ;
> pixel_clk_params->flags.ENABLE_SS = 0;
> @@ -3044,6 +3046,8 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
> for (i = 0; i < dc->res_pool->pipe_count; i++) {
> if (!context->res_ctx.pipe_ctx[i].stream)
> continue;
> + if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
> + return true;
> }
> return false;
> }
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
> index f264a32ebade..463e96f8f14c 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
> @@ -561,11 +561,6 @@ static const struct dcn10_link_enc_mask le_mask = {
> DPCS_DCN31_MASK_SH_LIST(_MASK)
> };
>
> -#define dpp_regs(id)\
> -[id] = {\
> - DPP_REG_LIST_DCN30(id),\
> -}
> -
> #define hpo_dp_stream_encoder_reg_list(id)\
> [id] = {\
> DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\
> @@ -609,6 +604,11 @@ static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {
> DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)
> };
>
> +#define dpp_regs(id)\
> +[id] = {\
> + DPP_REG_LIST_DCN30(id),\
> +}
> +
> static const struct dcn3_dpp_registers dpp_regs[] = {
> dpp_regs(0),
> dpp_regs(1),
> @@ -1449,6 +1449,13 @@ static struct dce_hwseq *dcn31_hwseq_create(
> hws->regs = &hwseq_reg;
> hws->shifts = &hwseq_shift;
> hws->masks = &hwseq_mask;
> + /* DCN3.1 FPGA Workaround
> + * Need to enable HPO DP Stream Encoder before setting OTG master enable.
> + * To do so, move calling function enable_stream_timing to only be done AFTER calling
> + * function core_link_enable_stream
> + */
> + if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
> + hws->wa.dp_hpo_and_otg_sequence = true;
> }
> return hws;
> }
> @@ -2102,6 +2109,7 @@ static bool dcn31_resource_construct(
> dc->caps.max_slave_rgb_planes = 1;
> dc->caps.post_blend_color_processing = true;
> dc->caps.force_dp_tps4_for_cp2520 = true;
> + dc->caps.dp_hpo = true;
> dc->caps.extended_aux_timeout_support = true;
> dc->caps.dmcub_support = true;
> dc->caps.is_apu = true;
> diff --git a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h
> index a9170b9f84d3..43f33e186088 100644
> --- a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h
> +++ b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h
> @@ -37,6 +37,7 @@ struct cp_psp_stream_config {
> uint8_t phy_idx;
> uint8_t assr_enabled;
> uint8_t mst_enabled;
> + uint8_t dp2_enabled;
> void *dm_stream_ctx;
> bool dpms_off;
> };
> diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
> index 9ab854293ace..8de554fb98b9 100644
> --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
> +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
> @@ -160,6 +160,8 @@ void dm_set_dcn_clocks(
> struct dc_context *ctx,
> struct dc_clocks *clks);
>
> +void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz);
> +
> bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable);
>
> void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us);
> 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
> index 01c3a31be191..3cc110e13213 100644
> --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
> +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
> @@ -30,6 +30,7 @@
> #define LINK_TRAINING_RETRY_DELAY 50 /* ms */
> #define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
> #define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
> +#define MAX_MTP_SLOT_COUNT 64
> #define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
> #define TRAINING_AUX_RD_INTERVAL 100 //us
>
> @@ -189,5 +190,26 @@ enum dc_status dpcd_configure_lttpr_mode(
> struct link_training_settings *lt_settings);
>
> enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_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);
> +
> +enum dc_status dpcd_configure_channel_coding(
> + struct dc_link *link,
> + struct link_training_settings *lt_settings);
> +
> +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 dc_link_settings *link_settings);
> +void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal);
> +void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
> +bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx);
> +void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link);
> +
> bool dp_retrieve_lttpr_cap(struct dc_link *link);
> #endif /* __DC_LINK_DP_H__ */
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
> index f7f7e4fff0c2..d09eed7bcc4a 100644
> --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
> +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
> @@ -41,6 +41,9 @@ struct dce_hwseq_wa {
> bool DEGVIDCN10_254;
> bool DEGVIDCN21;
> bool disallow_self_refresh_during_multi_plane_transition;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + bool dp_hpo_and_otg_sequence;
> +#endif
> };
>
> struct hwseq_wa_state {
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
> index 713f6d5cf3e0..3fbda9d7e257 100644
> --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
> +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
> @@ -200,4 +200,9 @@ int get_num_mpc_splits(struct pipe_ctx *pipe);
>
> int get_num_odm_splits(struct pipe_ctx *pipe);
>
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
> + const struct resource_pool *pool);
> +#endif
> +
> #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
> diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
> index aec7389aff37..6fb7c0145cb6 100644
> --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
> +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
> @@ -80,6 +80,15 @@ enum dpcd_phy_test_patterns {
> PHY_TEST_PATTERN_CP2520_1,
> PHY_TEST_PATTERN_CP2520_2,
> PHY_TEST_PATTERN_CP2520_3, /* same as TPS4 */
> + PHY_TEST_PATTERN_128b_132b_TPS1 = 0x8,
> + PHY_TEST_PATTERN_128b_132b_TPS2 = 0x10,
> + PHY_TEST_PATTERN_PRBS9 = 0x18,
> + PHY_TEST_PATTERN_PRBS11 = 0x20,
> + PHY_TEST_PATTERN_PRBS15 = 0x28,
> + PHY_TEST_PATTERN_PRBS23 = 0x30,
> + PHY_TEST_PATTERN_PRBS31 = 0x38,
> + PHY_TEST_PATTERN_264BIT_CUSTOM = 0x40,
> + PHY_TEST_PATTERN_SQUARE_PULSE = 0x48,
> };
>
> enum dpcd_test_dyn_range {
> @@ -135,7 +144,14 @@ enum dpcd_training_patterns {
> DPCD_TRAINING_PATTERN_1,
> DPCD_TRAINING_PATTERN_2,
> DPCD_TRAINING_PATTERN_3,
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + DPCD_TRAINING_PATTERN_4 = 7,
> + DPCD_128b_132b_TPS1 = 1,
> + DPCD_128b_132b_TPS2 = 2,
> + DPCD_128b_132b_TPS2_CDS = 3,
> +#else
> DPCD_TRAINING_PATTERN_4 = 7
> +#endif
> };
>
> /* This enum is for use with PsrSinkPsrStatus.bits.sinkSelfRefreshStatus
> diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
> index efd9812c13ec..c729b50c4f20 100644
> --- a/drivers/gpu/drm/amd/display/include/link_service_types.h
> +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
> @@ -53,7 +53,11 @@ enum edp_revision {
> };
>
> enum {
> - LINK_RATE_REF_FREQ_IN_KHZ = 27000 /*27MHz*/
> + LINK_RATE_REF_FREQ_IN_KHZ = 27000, /*27MHz*/
> + BITS_PER_DP_BYTE = 10,
> + DATA_EFFICIENCY_8b_10b_x10000 = 8000, /* 80% data efficiency */
> + DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100 = 97, /* 97% data efficiency when FEC is enabled */
> + DATA_EFFICIENCY_128b_132b_x10000 = 9646, /* 96.71% data efficiency x 99.75% downspread factor */
> };
>
> enum link_training_result {
> @@ -70,6 +74,12 @@ enum link_training_result {
> LINK_TRAINING_LINK_LOSS,
> /* Abort link training (because sink unplugged) */
> LINK_TRAINING_ABORT,
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + DP_128b_132b_LT_FAILED,
> + DP_128b_132b_MAX_LOOP_COUNT_REACHED,
> + DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT,
> + DP_128b_132b_CDS_DONE_TIMEOUT,
> +#endif
> };
>
> enum lttpr_mode {
> @@ -86,11 +96,23 @@ struct link_training_settings {
> enum dc_pre_emphasis *pre_emphasis;
> enum dc_post_cursor2 *post_cursor2;
> bool should_set_fec_ready;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + /* TODO - factor lane_settings out because it changes during LT */
> + union dc_dp_ffe_preset *ffe_preset;
> +#endif
>
> uint16_t cr_pattern_time;
> uint16_t eq_pattern_time;
> + uint16_t cds_pattern_time;
> enum dc_dp_training_pattern pattern_for_cr;
> enum dc_dp_training_pattern pattern_for_eq;
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + enum dc_dp_training_pattern pattern_for_cds;
> +
> + uint32_t eq_wait_time_limit;
> + uint8_t eq_loop_count_limit;
> + uint32_t cds_wait_time_limit;
> +#endif
>
> bool enhanced_framing;
> bool allow_invalid_msa_timing_param;
> diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h
> index 571fcf23cea9..370fad883e33 100644
> --- a/drivers/gpu/drm/amd/display/include/logger_types.h
> +++ b/drivers/gpu/drm/amd/display/include/logger_types.h
> @@ -72,6 +72,9 @@
> #define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__)
> #define DC_LOG_SMU(...) pr_debug("[SMU_MSG]:"__VA_ARGS__)
> #define DC_LOG_DWB(...) DRM_DEBUG_KMS(__VA_ARGS__)
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> +#define DC_LOG_DP2(...) DRM_DEBUG_KMS(__VA_ARGS__)
> +#endif
>
> struct dal_logger;
>
> @@ -123,6 +126,9 @@ enum dc_log_type {
> LOG_MAX_HW_POINTS,
> LOG_ALL_TF_CHANNELS,
> LOG_SAMPLE_1DLUT,
> +#if defined(CONFIG_DRM_AMD_DC_DCN)
> + LOG_DP2,
> +#endif
> LOG_SECTION_TOTAL_COUNT
> };
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread