Add all the bits to enable DSC over FRL.
Signed-off-by: Harry Wentland <[email protected]>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 74 +-
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 91 ++-
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 12 +
drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 13 +
.../gpu/drm/amd/display/dc/core/dc_resource.c | 54 ++
.../gpu/drm/amd/display/dc/core/dc_stream.c | 2 +-
drivers/gpu/drm/amd/display/dc/dc.h | 7 +
drivers/gpu/drm/amd/display/dc/dc_dsc.h | 8 +
.../gpu/drm/amd/display/dc/dc_hdmi_types.h | 2 +
.../drm/amd/display/dc/dml/dcn30/dcn30_fpu.c | 40 +-
.../dc/dml/dcn30/display_mode_vba_30.c | 3 +
.../dc/dml/dcn31/display_mode_vba_31.c | 3 +
.../dc/dml/dcn314/display_mode_vba_314.c | 3 +
.../dc/dml/dcn32/display_mode_vba_util_32.c | 3 +
.../drm/amd/display/dc/dml/dml1_frl_cap_chk.c | 197 +++++
.../drm/amd/display/dc/dml/dml1_frl_cap_chk.h | 9 +
drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c | 704 ++++++++++++++++++
.../hpo/dcn30/dcn30_hpo_frl_stream_encoder.c | 105 +++
.../dcn401/dcn401_hpo_frl_stream_encoder.c | 1 +
.../hpo/dcn42/dcn42_hpo_frl_stream_encoder.c | 1 +
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +
.../amd/display/dc/hwss/dcn30/dcn30_init.c | 1 +
.../amd/display/dc/hwss/dcn31/dcn31_init.c | 1 +
.../amd/display/dc/hwss/dcn314/dcn314_init.c | 1 +
.../amd/display/dc/hwss/dcn32/dcn32_init.c | 1 +
.../amd/display/dc/hwss/dcn35/dcn35_init.c | 1 +
.../amd/display/dc/hwss/dcn351/dcn351_init.c | 1 +
.../amd/display/dc/hwss/dcn401/dcn401_init.c | 1 +
.../amd/display/dc/hwss/dcn42/dcn42_init.c | 1 +
.../drm/amd/display/dc/hwss/hw_sequencer.h | 5 +
.../amd/display/dc/inc/hw/stream_encoder.h | 4 +
.../gpu/drm/amd/display/dc/link/link_dpms.c | 38 +
.../display/dc/link/protocols/link_hdmi_frl.c | 38 +
.../amd/display/dc/optc/dcn30/dcn30_optc.c | 30 +-
.../amd/display/dc/optc/dcn30/dcn30_optc.h | 1 +
.../amd/display/dc/optc/dcn31/dcn31_optc.c | 1 +
.../amd/display/dc/optc/dcn314/dcn314_optc.c | 1 +
.../amd/display/dc/optc/dcn32/dcn32_optc.c | 1 +
.../amd/display/dc/optc/dcn35/dcn35_optc.c | 1 +
.../amd/display/dc/optc/dcn401/dcn401_optc.c | 1 +
.../amd/display/dc/optc/dcn42/dcn42_optc.c | 1 +
42 files changed, 1460 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index be4b66b00be9..007f099ffbb5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -7323,12 +7323,30 @@ static void update_dsc_caps(struct amdgpu_dm_connector
*aconnector,
if (aconnector->dc_link && (sink->sink_signal ==
SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP)) {
- if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE ||
- sink->link->dpcd_caps.dongle_type ==
DISPLAY_DONGLE_DP_HDMI_CONVERTER)
+ if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE)
dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
dsc_caps);
+ else if (sink->link->dpcd_caps.dongle_type ==
DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
+ if
(aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT
&&
+
!aconnector->dsc_settings.dsc_force_disable_passthrough &&
+
aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0
&&
+ sink->edid_caps.frl_dsc_support &&
+ sink->edid_caps.max_frl_rate > 0 &&
+ sink->edid_caps.frl_dsc_max_frl_rate >
0)
+
dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
+ else
+
dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
+
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
+
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
+ dsc_caps);
+ }
+ } else if (aconnector->dc_link && sink->sink_signal ==
SIGNAL_TYPE_HDMI_FRL) {
+ if (sink->edid_caps.frl_dsc_support &&
+ sink->edid_caps.max_frl_rate > 0 &&
+ sink->edid_caps.frl_dsc_max_frl_rate > 0)
+ dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc,
&sink->edid_caps, dsc_caps);
}
}
@@ -7402,6 +7420,10 @@ static void apply_dsc_policy_for_stream(struct
amdgpu_dm_connector *aconnector,
struct drm_connector *drm_connector = &aconnector->base;
u32 link_bandwidth_kbps;
struct dc *dc = sink->ctx->dc;
+ const struct dc_hdmi_frl_link_settings *frl_verified_link_cap = NULL;
+ u32 converter_bw_in_kbps;
+ u32 sink_bw_in_kbps;
+ u32 dsc_sink_bw_in_kbps;
u32 max_supported_bw_in_kbps, timing_bw_in_kbps;
u32 dsc_max_supported_bw_in_kbps;
u32 max_dsc_target_bpp_limit_override =
@@ -7440,8 +7462,18 @@ static void apply_dsc_policy_for_stream(struct
amdgpu_dm_connector *aconnector,
} else if (sink->link->dpcd_caps.dongle_type ==
DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
timing_bw_in_kbps =
dc_bandwidth_in_kbps_from_timing(&stream->timing,
dc_link_get_highest_encoding_format(aconnector->dc_link));
- max_supported_bw_in_kbps = link_bandwidth_kbps;
- dsc_max_supported_bw_in_kbps = link_bandwidth_kbps;
+ converter_bw_in_kbps =
aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps;
+ sink_bw_in_kbps =
dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.max_frl_rate);
+ dsc_sink_bw_in_kbps =
dc_link_bw_kbps_from_raw_frl_link_rate_data(dc,
sink->edid_caps.frl_dsc_max_frl_rate);
+
+ if (dsc_caps->is_frl) {
+ max_supported_bw_in_kbps =
min(link_bandwidth_kbps, converter_bw_in_kbps);
+ max_supported_bw_in_kbps =
min(max_supported_bw_in_kbps, sink_bw_in_kbps);
+ dsc_max_supported_bw_in_kbps =
min(max_supported_bw_in_kbps, dsc_sink_bw_in_kbps);
+ } else {
+ max_supported_bw_in_kbps = link_bandwidth_kbps;
+ dsc_max_supported_bw_in_kbps =
link_bandwidth_kbps;
+ }
if (timing_bw_in_kbps > max_supported_bw_in_kbps &&
max_supported_bw_in_kbps > 0 &&
@@ -7454,11 +7486,41 @@ static void apply_dsc_policy_for_stream(struct
amdgpu_dm_connector *aconnector,
dc_link_get_highest_encoding_format(aconnector->dc_link),
&stream->timing.dsc_cfg)) {
stream->timing.flags.DSC = 1;
- drm_dbg_driver(drm_connector->dev, "%s:
SST_DSC [%s] DSC is selected from DP-HDMI PCON\n",
-
__func__, drm_connector->name);
+ drm_dbg_driver(drm_connector->dev, "%s:
SST_DSC [%s] DSC is selected from %s\n",
+ __func__,
drm_connector->name,
+ (dsc_caps->is_frl == 1)
? "HDMI FRL RX" : "DP-HDMI PCON");
}
}
}
+ else if (aconnector->dc_link && sink->sink_signal ==
SIGNAL_TYPE_HDMI_FRL) {
+ struct dc_dsc_policy dsc_policy = {0};
+
+ frl_verified_link_cap = dc_link_get_frl_link_cap(stream->link);
+ if (frl_verified_link_cap->frl_link_rate !=
HDMI_FRL_LINK_RATE_DISABLE &&
+ aconnector->dc_link->frl_flags.force_frl_dsc) {
+ dc_dsc_policy_set_enable_dsc_when_not_needed(true);
+ dc_dsc_get_policy_for_timing(&stream->timing, 0,
&dsc_policy, dc_link_get_highest_encoding_format(stream->link));
+ }
+
+ timing_bw_in_kbps =
dc_bandwidth_in_kbps_from_timing(&stream->timing, DC_LINK_ENCODING_HDMI_FRL);
+ link_bandwidth_kbps = dc_link_frl_bandwidth_kbps(stream->link,
frl_verified_link_cap->frl_link_rate);
+ dsc_sink_bw_in_kbps =
dc_link_bw_kbps_from_raw_frl_link_rate_data(dc,
sink->edid_caps.frl_dsc_max_frl_rate);
+
+ if ((timing_bw_in_kbps > link_bandwidth_kbps &&
dsc_sink_bw_in_kbps > 0) ||
+ (dsc_policy.enable_dsc_when_not_needed ||
dsc_options.force_dsc_when_not_needed)) {
+ if
(dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
+ dsc_caps,
+ &dsc_options,
+ dsc_sink_bw_in_kbps,
+ &stream->timing,
+
dc_link_get_highest_encoding_format(aconnector->dc_link),
+ &stream->timing.dsc_cfg)) {
+ stream->timing.flags.DSC = 1;
+ drm_dbg_driver(drm_connector->dev, "%s:
HDMI_FRL_DSC [%s] DSC is selected from HDMI FRL RX\n",
+ __func__, drm_connector->name);
+ }
+ }
+ }
/* Overwrite the stream flag if DSC is enabled through debugfs */
if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE)
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 05f9a01f223c..e14980271c96 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
@@ -178,8 +178,15 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
- if (edid_caps->edid_hdmi)
+ if (edid_caps->edid_hdmi) {
populate_hdmi_info_from_connector(&connector->display_info.hdmi, edid_caps);
+ drm_dbg_driver(connector->dev, "%s: HDMI_FRL [%s] max_frl_rate
%d\n", __func__, connector->name, edid_caps->max_frl_rate);
+ if (edid_caps->frl_dsc_support)
+ drm_dbg_driver(connector->dev, "%s: HDMI_FRL_DSC [%s]
frl_dsc_10bpc %d, frl_dsc_12bpc %d, frl_dsc_all_bpp %d, frl_dsc_native_420 %d,
frl_dsc_max_slices %d, frl_dsc_max_frl_rate %d, frl_dsc_total_chunk_kbytes
%d\n",
+ __func__, connector->name,
edid_caps->frl_dsc_10bpc, edid_caps->frl_dsc_12bpc, \
+ edid_caps->frl_dsc_all_bpp,
edid_caps->frl_dsc_native_420, edid_caps->frl_dsc_max_slices, \
+ edid_caps->frl_dsc_max_frl_rate,
edid_caps->frl_dsc_total_chunk_kbytes);
+ }
apply_edid_quirks(dev, edid_buf, edid_caps);
@@ -896,8 +903,23 @@ bool dm_helpers_dp_write_dsc_enable(
port = aconnector->mst_output_port;
if (enable) {
- if (port->passthrough_aux) {
- ret = drm_dp_dpcd_write(port->passthrough_aux,
+ if (port->passthrough_aux
+ || (stream->timing.dsc_cfg.is_frl &&
+ (!stream->sink->dsc_caps.dsc_dec_caps.is_frl ||
+ (stream->sink->dsc_caps.dsc_dec_caps.is_frl &&
+
aconnector->mst_downstream_port_present.fields.PORT_PRESENT &&
+
aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE ==
+ DOWN_STREAM_DETAILED_HDMI)))
+ ) {
+ if (!stream->sink->dsc_caps.dsc_dec_caps.is_frl)
+ /* DSC passthrough to DP receiver */
+ enable_passthrough = DSC_DECODING;
+ else if
(aconnector->mst_downstream_port_present.fields.PORT_PRESENT &&
+
aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE ==
+ DOWN_STREAM_DETAILED_HDMI)
+ /* DSC passthrough to FRL sink */
+ enable_passthrough = DSC_PASSTHROUGH;
+ ret =
drm_dp_dpcd_write(&aconnector->mst_output_port->aux,
DP_DSC_ENABLE,
&enable_passthrough, 1);
drm_dbg_dp(dev,
@@ -921,8 +943,13 @@ bool dm_helpers_dp_write_dsc_enable(
"virtual dpcd",
ret);
- if (port->passthrough_aux) {
- ret = drm_dp_dpcd_write(port->passthrough_aux,
+ if (port->passthrough_aux
+ || (stream->timing.dsc_cfg.is_frl &&
+ (!stream->sink->dsc_caps.dsc_dec_caps.is_frl ||
+
(aconnector->mst_downstream_port_present.fields.PORT_PRESENT &&
+
aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE ==
+ DOWN_STREAM_DETAILED_HDMI)))) {
+ ret =
drm_dp_dpcd_write(&aconnector->mst_output_port->aux,
DP_DSC_ENABLE,
&enable_passthrough, 1);
drm_dbg_dp(dev,
@@ -939,10 +966,22 @@ bool dm_helpers_dp_write_dsc_enable(
"SST_DSC Send DSC %s to SST RX\n",
enable_dsc ? "enable" : "disable");
} else if (stream->sink->link->dpcd_caps.dongle_type ==
DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
+ if (enable) {
+ if (stream->timing.dsc_cfg.is_frl) {
+ enable_dsc = DSC_PASSTHROUGH;
+ } else {
+ enable_dsc = DSC_DECODING;
+ }
+ drm_dbg_dp(dev,
+ "SST_DSC Sent DSC decoding enable to
%s port, ret = %u\n",
+ (port->passthrough_aux) ?
+ "remote HDMI FRL RX" :
+ "DP-HDMI PCON", ret);
+ } else {
+ enable_dsc = DSC_DISABLE;
+ drm_dbg_dp(dev, "SST_DSC Send DSC disable to
DP-HDMI PCON\n");
+ }
ret = dm_helpers_dp_write_dpcd(ctx, stream->link,
DP_DSC_ENABLE, &enable_dsc, 1);
- drm_dbg_dp(dev,
- "SST_DSC Send DSC %s to DP-HDMI PCON\n",
- enable_dsc ? "enable" : "disable");
}
}
@@ -1054,10 +1093,46 @@ static uint8_t get_max_frl_rate(uint8_t max_lanes,
uint8_t max_rate_per_lane)
return max_frl_rate;
}
+static uint8_t get_dsc_max_slices(uint8_t max_slices, int clk_per_slice)
+{
+ uint8_t dsc_max_slices;
+
+ if ((max_slices == 1) && (clk_per_slice == 340))
+ dsc_max_slices = 1;
+ else if ((max_slices == 2) && (clk_per_slice == 340))
+ dsc_max_slices = 2;
+ else if ((max_slices == 4) && (clk_per_slice == 340))
+ dsc_max_slices = 3;
+ else if ((max_slices == 8) && (clk_per_slice == 340))
+ dsc_max_slices = 4;
+ else if ((max_slices == 8) && (clk_per_slice == 400))
+ dsc_max_slices = 5;
+ else if ((max_slices == 12) && (clk_per_slice == 400))
+ dsc_max_slices = 6;
+ else if ((max_slices == 16) && (clk_per_slice == 400))
+ dsc_max_slices = 7;
+ else
+ dsc_max_slices = 0;
+
+ return dsc_max_slices;
+}
+
void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct
dc_edid_caps *edid_caps)
{
edid_caps->scdc_present = hdmi->scdc.supported;
edid_caps->max_frl_rate = get_max_frl_rate(hdmi->max_lanes,
hdmi->max_frl_rate_per_lane);
+ edid_caps->frl_dsc_support = hdmi->dsc_cap.v_1p2;
+ if (edid_caps->frl_dsc_support) {
+ if (hdmi->dsc_cap.bpc_supported == 10)
+ edid_caps->frl_dsc_10bpc = true;
+ else if (hdmi->dsc_cap.bpc_supported == 12)
+ edid_caps->frl_dsc_12bpc = true;
+ edid_caps->frl_dsc_all_bpp = hdmi->dsc_cap.all_bpp;
+ edid_caps->frl_dsc_native_420 = hdmi->dsc_cap.native_420;
+ edid_caps->frl_dsc_max_slices =
get_dsc_max_slices(hdmi->dsc_cap.max_slices, hdmi->dsc_cap.clk_per_slice);
+ edid_caps->frl_dsc_max_frl_rate =
get_max_frl_rate(hdmi->dsc_cap.max_lanes, hdmi->dsc_cap.max_frl_rate_per_lane);
+ edid_caps->frl_dsc_total_chunk_kbytes =
hdmi->dsc_cap.total_chunk_kbytes;
+ }
}
enum dc_edid_status dm_helpers_read_local_edid(
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 8e2a8c2c1d84..bc5a9e1663ba 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -295,6 +295,17 @@ static bool validate_dsc_caps_on_connector(struct
amdgpu_dm_connector *aconnecto
if (!aconnector->dsc_aux)
return false;
+ if (port->passthrough_aux &&
+ aconnector->dc_link->dc->caps.dp_hdmi21_pcon_support &&
+ dc_sink->edid_caps.frl_dsc_support &&
+ dc_sink->edid_caps.max_frl_rate > 0 &&
+ dc_sink->edid_caps.frl_dsc_max_frl_rate > 0) {
+ dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc,
+ &dc_sink->edid_caps,
&dc_sink->dsc_caps.dsc_dec_caps);
+ DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from FRL RX\n",
__func__, aconnector->base.name);
+ return true;
+ } else {
+ DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from DP-HDMI
PCON\n", __func__, aconnector->base.name);
if (drm_dp_dpcd_read(aconnector->dsc_aux, DP_DSC_SUPPORT, dsc_caps, 16)
< 0)
return false;
@@ -307,6 +318,7 @@ static bool validate_dsc_caps_on_connector(struct
amdgpu_dm_connector *aconnecto
&dc_sink->dsc_caps.dsc_dec_caps))
return false;
+ }
return true;
}
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index b4ad3ec0f029..517844a99451 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -4050,6 +4050,12 @@ static void add_link_update_dsc_config_sequence(
pipe_ctx->stream_res.stream_enc,
true, dsc_packed_pps, false);
}
+ else if (dc_is_hdmi_frl_signal(stream->signal)) {
+ hwss_add_hpo_frl_stream_enc_set_dsc_config(seq_state,
+ pipe_ctx->stream_res.hpo_frl_stream_enc,
+ &stream->timing,
+ dsc_packed_pps);
+ }
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index c0c35d6653a5..ad01ffdc73c3 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -1642,6 +1642,9 @@ void hwss_execute_sequence(struct dc *dc,
case STREAM_ENC_DP_SET_DSC_PPS_INFO_PACKET:
hwss_stream_enc_dp_set_dsc_pps_info_packet(params);
break;
+ case HPO_FRL_STREAM_ENC_SET_DSC_CONFIG:
+ hwss_hpo_frl_stream_enc_set_dsc_config(params);
+ break;
case DP_TRACE_SOURCE_SEQUENCE:
hwss_dp_trace_source_sequence(params);
break;
@@ -3734,6 +3737,16 @@ void hwss_stream_enc_dp_set_dsc_pps_info_packet(union
block_sequence_params *par
params->stream_enc_dp_set_dsc_pps_info_packet_params.pps_sdp_stream);
}
+void hwss_hpo_frl_stream_enc_set_dsc_config(union block_sequence_params
*params)
+{
+ if (params->hpo_frl_stream_enc_set_dsc_config_params.hpo_frl_stream_enc
&&
+
params->hpo_frl_stream_enc_set_dsc_config_params.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config)
+
params->hpo_frl_stream_enc_set_dsc_config_params.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+
params->hpo_frl_stream_enc_set_dsc_config_params.hpo_frl_stream_enc,
+ (struct dc_crtc_timing
*)params->hpo_frl_stream_enc_set_dsc_config_params.timing,
+
params->hpo_frl_stream_enc_set_dsc_config_params.dsc_packed_pps);
+}
+
void hwss_set_dmdata_attributes(union block_sequence_params *params)
{
struct hubp *hubp = params->set_dmdata_attributes_params.hubp;
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 2457b563e6c8..0815400468ed 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4592,6 +4592,38 @@ enum dc_status dc_validate_with_context(struct dc *dc,
}
#if defined(CONFIG_DRM_AMD_DC_FP)
+/**
+ * dc_update_modified_pix_clock_for_dsc_with_padding() - update pix_clk for
dsc with padding
+ *
+ * @dc_stream_state: Pointer to the stream structure.
+ * @dc_crtc_timing: Pointer to the stream dc_crtc_timing structure.
+ * @dsc_padding_params: Pointer to the DSC padding parameters structure.
+ *
+ * This function updated the pix_clk for dsc with padding stored in pipe_ctx
+ * such that the OTG h_active time fits withing the expected compressed active
+ * time calculated according to HDMI spec. H_total is then increased to
+ * maintain the same OTG line time as before the increased pix_clk.
+ */
+static void dc_update_modified_pix_clock_for_dsc_with_padding(const struct
dc_stream_state *stream,
+ const struct dc_crtc_timing *timing, struct dsc_padding_params
*dsc_padding_params)
+{
+ DC_FP_START();
+
frl_modified_pix_clock_for_dsc_padding(stream->link->frl_verified_link_cap.borrow_params.hc_active_target,
+ stream->link->frl_verified_link_cap.borrow_params.hc_blank_target,
+ stream->link->frl_verified_link_cap.frl_num_lanes,
+ timing->pix_clk_100hz,
+ stream->link->frl_verified_link_cap.frl_link_rate,
+ timing->h_addressable,
+ timing->h_border_left,
+ timing->h_border_right,
+ timing->h_total,
+ (timing->h_addressable + dsc_padding_params->dsc_hactive_padding),
+ &dsc_padding_params->dsc_pix_clk_100hz,
+ &dsc_padding_params->dsc_htotal_padding);
+ DC_FP_END();
+
+ dsc_padding_params->dsc_htotal_padding =
dsc_padding_params->dsc_htotal_padding - timing->h_total;
+}
#endif /* CONFIG_DRM_AMD_DC_FP */
/**
@@ -4618,6 +4650,28 @@ static void
calculate_timing_params_for_dsc_with_padding(struct pipe_ctx *pipe_c
if (stream)
pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz =
stream->timing.pix_clk_100hz;
+ uint32_t hactive;
+ uint32_t ceil_slice_width;
+ if (stream && stream->timing.flags.DSC) {
+ hactive = stream->timing.h_addressable +
stream->timing.h_border_left + stream->timing.h_border_right;
+
+ /* Assume if determined slices does not divide Hactive evenly,
Hborrow is needed for padding*/
+ if (hactive % stream->timing.dsc_cfg.num_slices_h != 0) {
+ ceil_slice_width = (hactive /
stream->timing.dsc_cfg.num_slices_h) + 1;
+
+ /* If YCBCR420 slice width must be even */
+ if (stream->timing.pixel_encoding ==
PIXEL_ENCODING_YCBCR420 && ceil_slice_width % 2 != 0)
+ ceil_slice_width++;
+
+ pipe_ctx->dsc_padding_params.dsc_hactive_padding =
+ (uint8_t)(ceil_slice_width *
stream->timing.dsc_cfg.num_slices_h - hactive);
+
+ if (stream->timing.h_total - hactive -
pipe_ctx->dsc_padding_params.dsc_hactive_padding < 32)
+
pipe_ctx->dsc_padding_params.dsc_hactive_padding = 0;
+
+
dc_update_modified_pix_clock_for_dsc_with_padding(stream, &stream->timing,
&pipe_ctx->dsc_padding_params);
+ }
+ }
}
/**
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index f694c6ad6e98..c1984ebe0ef1 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -99,7 +99,7 @@ void update_stream_signal(struct dc_stream_state *stream,
struct dc_sink *sink)
if (stream->link->frl_flags.force_frl_always ||
stream->link->frl_flags.force_frl_max
- )
+ || stream->link->frl_flags.force_frl_dsc)
stream->signal = SIGNAL_TYPE_HDMI_FRL;
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h
b/drivers/gpu/drm/amd/display/dc/dc.h
index 965fa9830355..4c75595a5742 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -121,6 +121,12 @@ struct frl_cap_chk_params_fixed31_32 {
bool compressed; /* set to true if DSC is enabled */
bool bypass_hc_target_calc; /* debug only */
+ bool allow_all_bpp; /* dsc_all_bpp */
+
+ /* DSC parameters */
+ int slices;
+ int slice_width;
+ struct fixed31_32 bpp_target;
int layout;
int acat; /* not supported */
@@ -1151,6 +1157,7 @@ struct dc_debug_options {
int select_ffe;
int limit_ffe;
bool force_frl_always;
+ bool force_frl_dsc;
bool force_frl_max;
bool apply_vsdb_rcc_wa;
bool enable_hdmi_idcc;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h
b/drivers/gpu/drm/amd/display/dc/dc_dsc.h
index 101bce6b8de6..c0564167c587 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dsc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h
@@ -63,11 +63,19 @@ struct dc_dsc_config_options {
bool force_dsc_when_not_needed;
};
+struct dc_dsc_primary_bpp {
+ uint32_t vic;
+ uint32_t target_bpp;
+};
bool dc_dsc_parse_dsc_dpcd(const struct dc *dc,
const uint8_t *dpcd_dsc_basic_data,
const uint8_t *dpcd_dsc_ext_data,
struct dsc_dec_dpcd_caps *dsc_sink_caps);
+bool dc_dsc_parse_dsc_edid(const struct dc *dc,
+ const struct dc_edid_caps *edid_caps,
+ struct dsc_dec_dpcd_caps *dsc_sink_caps);
+
bool dc_dsc_compute_bandwidth_range(
const struct display_stream_compressor *dsc,
uint32_t dsc_min_slice_height_override,
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
index afd21eb6bbcd..5923a5f112a9 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
@@ -138,6 +138,7 @@ union hdmi_scdc_status_flags_data {
uint8_t LANE3_LOCKED:1;
uint8_t RESERVED:1;
uint8_t FLT_READY:1;
+ uint8_t DSC_DECODEFAIL:1;
} fields;
};
@@ -270,6 +271,7 @@ struct dc_hdmi_frl_flags {
int select_ffe;
int limit_ffe;
bool force_frl_always;
+ bool force_frl_dsc;
bool force_frl_max;
bool apply_vsdb_rcc_wa;
};
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
index 58479bea9976..523d8261be94 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
@@ -780,6 +780,38 @@ void hpo_fpu_enc3_validate_hdmi_frl_output_link(struct
hpo_frl_stream_encoder *e
break;
}
+ if (timing->flags.DSC &&
+ (unsigned int)frl_link_settings->frl_link_rate >
dsc_max_rate) {
+ if (dsc_max_rate < HDMI_FRL_LINK_RATE_6GBPS_4LANE) {
+ frl_params->lanes = 3;
+ } else {
+ frl_params->lanes = 4;
+ }
+
+ switch (dsc_max_rate) {
+ case HDMI_FRL_LINK_RATE_3GBPS:
+ frl_params->r_bit_nominal = 3.0e9;
+ break;
+ case HDMI_FRL_LINK_RATE_6GBPS:
+ case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+ frl_params->r_bit_nominal = 6.0e9;
+ break;
+ case HDMI_FRL_LINK_RATE_8GBPS:
+ frl_params->r_bit_nominal = 8.0e9;
+ break;
+ case HDMI_FRL_LINK_RATE_10GBPS:
+ default:
+ frl_params->r_bit_nominal = 10.0e9;
+ break;
+ case HDMI_FRL_LINK_RATE_12GBPS:
+ frl_params->r_bit_nominal = 12.0e9;
+ break;
+ }
+ }
+
+ if (timing->flags.DSC && timing->rid > 0)
+ frl_params->is_ovt = true;
+
frl_params->f_pixel_clock_nominal = (double)timing->pix_clk_100hz * 100;
frl_params->h_active = timing->h_addressable + timing->h_border_left +
timing->h_border_right;
frl_params->h_blank = timing->h_total - frl_params->h_active;
@@ -795,6 +827,12 @@ void hpo_fpu_enc3_validate_hdmi_frl_output_timing(
if (timing->flags.DSC) {
frl_params->compressed = true;
+ frl_params->slices = timing->dsc_cfg.num_slices_h;
+ frl_params->slice_width = (frl_params->h_active +
frl_params->slices - 1) / frl_params->slices;
+ // If YCBCR420 slice width must be even
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 &&
frl_params->slice_width % 2 != 0)
+ frl_params->slice_width++;
+ frl_params->bpp_target = timing->dsc_cfg.bits_per_pixel / 16.0;
} else {
frl_params->compressed = false;
}
@@ -826,5 +864,5 @@ enum frl_cap_chk_result frl_fpu_cap_chk_compressed(struct
hpo_frl_stream_encoder
struct
frl_cap_chk_intermediates *inter)
{
(void)enc;
- return -5;
+ return dml1_frl_cap_chk_compressed(params, inter);
}
\ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
index b54d24cdfbe2..55db25437952 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
@@ -3358,6 +3358,9 @@ static double TruncToValidBPP(
hdmifrlparams.h_active = HActive;
hdmifrlparams.h_blank = HTotal - HActive;
hdmifrlparams.compressed = DSCEnable;
+ hdmifrlparams.slices = DSCSlices;
+ hdmifrlparams.slice_width = (int)dml_ceil((double) HActive / DSCSlices,
1.0);
+ hdmifrlparams.bpp_target = DesiredBPP;
if (Format == dm_420) {
NonDSCBPP0 = 12;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
index 96fdb3f6fa37..3216fd10ad04 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
@@ -3665,6 +3665,9 @@ static double TruncToValidBPP(
hdmifrlparams.h_active = HActive;
hdmifrlparams.h_blank = HTotal - HActive;
hdmifrlparams.compressed = DSCEnable;
+ hdmifrlparams.slices = DSCSlices;
+ hdmifrlparams.slice_width = (int)dml_ceil((double) HActive / DSCSlices,
1.0);
+ hdmifrlparams.bpp_target = DesiredBPP;
if (Format == dm_420) {
NonDSCBPP0 = 12;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
index 50c217413abf..2f412cee57c7 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
@@ -3771,6 +3771,9 @@ static double TruncToValidBPP(
hdmifrlparams.h_active = HActive;
hdmifrlparams.h_blank = HTotal - HActive;
hdmifrlparams.compressed = DSCEnable;
+ hdmifrlparams.slices = DSCSlices;
+ hdmifrlparams.slice_width = (int)dml_ceil((double) HActive / DSCSlices,
1.0);
+ hdmifrlparams.bpp_target = DesiredBPP;
if (Format == dm_420) {
NonDSCBPP0 = 12;
diff --git
a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
index 530f6fdc8df3..2ddc30d08b73 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
@@ -1702,6 +1702,9 @@ double dml32_TruncToValidBPP(
hdmifrlparams.h_blank = HTotal - HActive;
hdmifrlparams.bpc = (int)(DesiredBPP / 3);
hdmifrlparams.compressed = DSCEnable;
+ hdmifrlparams.slices = DSCSlices;
+ hdmifrlparams.slice_width = (int)dml_ceil((double) HActive / DSCSlices,
1.0);
+ hdmifrlparams.bpp_target = DesiredBPP;
if (Format == dm_420) {
NonDSCBPP0 = 12;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
index 9dde4e56f237..327d89b66613 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c
@@ -430,10 +430,207 @@ enum frl_cap_chk_result
dml1_frl_cap_chk_uncompressed(struct frl_cap_chk_params
return FRL_CAP_CHK_OK;
}
+enum frl_cap_chk_result dml1_frl_cap_chk_compressed(struct frl_cap_chk_params
*params,
+ struct
frl_cap_chk_intermediates *inter)
+{
+ enum frl_cap_chk_result res;
+ int c_frl_available;
+#if defined(DEBUG_FRL_CAP_CHK)
+ int c_frl_active_available;
+ int c_frl_blank_available;
+#endif
+ int bytes_target = 0;
+ int hc_active_target;
+ int hc_blank_target_est1;
+ int hc_blank_target_est2;
+ int hc_blank_target = 0;
+ int c_frl_actual_target_payload;
+ double utilization_targeted;
+ double margin_target;
+ double f_tb_average;
+ double t_active_ref;
+ double t_blank_ref;
+ double t_active_target;
+ double t_blank_target;
+ double tb_borrowed;
+#ifdef DEBUG_FRL_CAP_CHK
+ double tb_delta;
+ double tb_delta_limit;
+ int tb_worst;
+#endif
+ int table_size_444 = ARRAY_SIZE(prim_format_444);
+ int table_size_422 = ARRAY_SIZE(prim_format_422);
+ int table_size_420 = ARRAY_SIZE(prim_format_420);
+ int i;
+ bool hc_active_blank_predefined = false;
+
+ dc_assert_fp_enabled();
+
+ res = dml1_frl_cap_chk_common(inter, params);
+
+ if (res != FRL_CAP_CHK_OK)
+ return res;
+
+ c_frl_available = (int)dml_floor((1 - inter->overhead_max) *
inter->c_frl_line, 1);
+#if defined(DEBUG_FRL_CAP_CHK)
+ c_frl_active_available = dml_floor(c_frl_available *
((double)params->h_active / (params->h_active + params->h_blank)), 1);
+ c_frl_blank_available = dml_floor(c_frl_available *
((double)params->h_blank / (params->h_active + params->h_blank)), 1);
+#endif
+ bytes_target = (int)(params->slices *
dml_ceil(params->bpp_target * params->slice_width / 8.0, 1));
+
+ if (!params->bypass_hc_target_calc)
+ hc_active_target = (int)dml_ceil(bytes_target / 3.0, 1);
+ else
+ hc_active_target = params->borrow_params.hc_active_target;
+
+ if (!params->allow_all_bpp && params->vic != 0) {
+ if (params->pixel_encoding == HDMI_FRL_PIXEL_ENCODING_444) {
+ for (i = 0; i < table_size_444 ; i++) {
+ if (prim_format_444[i].vic == params->vic) {
+ params->borrow_params.hc_active_target
= prim_format_444[i].hc_active;
+ params->borrow_params.hc_blank_target
= prim_format_444[i].hc_blank;
+ hc_active_blank_predefined = true;
+ break;
+ }
+ }
+ } else if (params->pixel_encoding ==
HDMI_FRL_PIXEL_ENCODING_422) {
+ for (i = 0; i < table_size_422 ; i++) {
+ if (prim_format_422[i].vic == params->vic) {
+ params->borrow_params.hc_active_target
= prim_format_422[i].hc_active;
+ params->borrow_params.hc_blank_target
= prim_format_422[i].hc_blank;
+ hc_active_blank_predefined = true;
+ break;
+ }
+ }
+ } else if (params->pixel_encoding ==
HDMI_FRL_PIXEL_ENCODING_420) {
+ for (i = 0; i < table_size_420 ; i++) {
+ if (prim_format_420[i].vic == params->vic) {
+ params->borrow_params.hc_active_target
= prim_format_420[i].hc_active;
+ params->borrow_params.hc_blank_target
= prim_format_420[i].hc_blank;
+ hc_active_blank_predefined = true;
+ break;
+ }
+ }
+ }
+
+ if (hc_active_blank_predefined) {
+ hc_active_target =
params->borrow_params.hc_active_target;
+ hc_blank_target = params->borrow_params.hc_blank_target;
+ }
+ }
+
+ hc_blank_target_est1 = (int)dml_ceil(hc_active_target *
((double)params->h_blank / params->h_active), 1);
+ hc_blank_target_est2 = (int)dml_max(hc_blank_target_est1,
inter->blank_audio_min);
+
+ if (!hc_active_blank_predefined) {
+ if (!params->bypass_hc_target_calc) {
+ hc_blank_target = (int)(4 *
dml_floor(dml_min(hc_blank_target_est2, c_frl_available - 3.0 / 2.0 *
hc_active_target) / 4.0, 1));
+
+ params->borrow_params.hc_active_target =
hc_active_target;
+ params->borrow_params.hc_blank_target =
hc_blank_target;
+ } else {
+ hc_blank_target =
params->borrow_params.hc_blank_target;
+ }
+ }
+
+#ifdef DEBUG_FRL_CAP_CHK
+ {
+ frl_dump_var("%i", c_frl_available);
+ frl_dump_var("%i", c_frl_active_available);
+ frl_dump_var("%i", c_frl_blank_available);
+ frl_dump_var("%i", bytes_target);
+ frl_dump_var("%i", hc_active_target);
+ frl_dump_var("%i", hc_blank_target_est1);
+ frl_dump_var("%i", hc_blank_target_est2);
+ frl_dump_var("%i", hc_blank_target);
+ }
+#endif
+
+ if (!(inter->blank_audio_min <= hc_blank_target)) {
+ frl_dump_var("%i", inter->blank_audio_min);
+ frl_dump_var("%i", hc_blank_target);
+ return FRL_CAP_CHK_ERROR_AUDIO_BW;
+ }
+
+ f_tb_average = inter->f_pixel_clock_max / (params->h_active +
params->h_blank) * (hc_active_target + hc_blank_target);
+ t_active_ref = inter->t_line * ((double)params->h_active /
(params->h_active + params->h_blank));
+ t_blank_ref = inter->t_line - t_active_ref; // * ((double)
params->h_blank / (params->h_active + params->h_blank));
+ t_active_target = dml_max((hc_active_target / f_tb_average),
+ (3.0 / 2.0 * hc_active_target) /
+ (params->lanes * inter->r_frl_char_min * (1.0
- inter->overhead_max)));
+ t_blank_target = inter->t_line - t_active_target;
+
+ tb_borrowed = t_active_target * f_tb_average - hc_active_target;
+#ifdef DEBUG_FRL_CAP_CHK
+ tb_delta = dcn_bw_fabs(t_active_target - t_active_ref) *
(hc_active_target + hc_blank_target_est1) / inter->t_line;
+
+ {
+ frl_dump_var("%le", f_tb_average);
+ frl_dump_var("%le", t_active_ref);
+ frl_dump_var("%le", t_blank_ref);
+ frl_dump_var("%le", t_active_target);
+ frl_dump_var("%le", t_blank_target);
+ frl_dump_var("%le", tb_delta);
+ }
+#endif
+
+ if (t_blank_target - t_blank_ref > DBL_EPSILON) {
+#ifdef DEBUG_FRL_CAP_CHK
+ tb_delta_limit = (t_active_ref - hc_active_target /
f_tb_average) * (hc_active_target + hc_blank_target_est1) / inter->t_line;
+#endif
+ params->borrow_params.borrow_mode = FRL_BORROW_MODE_FROM_ACTIVE;
+ } else if (t_active_target - t_active_ref > DBL_EPSILON) {
+#ifdef DEBUG_FRL_CAP_CHK
+ tb_delta_limit = tb_delta;
+#endif
+ params->borrow_params.borrow_mode = FRL_BORROW_MODE_FROM_BLANK;
+ } else {
+#ifdef DEBUG_FRL_CAP_CHK
+ tb_delta_limit = 0;
+#endif
+ params->borrow_params.borrow_mode = FRL_BORROW_MODE_NONE;
+ }
+
+#ifdef DEBUG_FRL_CAP_CHK
+ tb_worst = dml_ceil(dml_max(tb_borrowed, tb_delta_limit), 1);
+
+ {
+ frl_dump_var("%le", tb_delta_limit);
+ frl_dump_var("%le", tb_borrowed);
+ frl_dump_var("%i", params->borrow_params.borrow_mode);
+ frl_dump_var("%i", tb_worst);
+ }
+#endif
+
+ if (!(tb_borrowed <= TB_BORROWED_MAX))
+ return FRL_CAP_CHK_ERROR_MAX_BORROW;
+
+ c_frl_actual_target_payload = (int)(dml_ceil(3.0 / 2.0 *
hc_active_target, 1) + hc_blank_target);
+ utilization_targeted = c_frl_actual_target_payload /
inter->c_frl_line;
+ margin_target = 1.0 - (utilization_targeted +
inter->overhead_max);
+
+#ifdef DEBUG_FRL_CAP_CHK
+ {
+ frl_dump_var("%i", c_frl_actual_target_payload);
+ frl_dump_var("%le", utilization_targeted);
+ frl_dump_var("%le", margin_target);
+ }
+#endif
+
+ // oversubscribed bandwidth relative to margin
+ if (margin_target < 0 && dcn_bw_fabs(margin_target) > EPSILON)
+ return FRL_CAP_CHK_ERROR_MARGIN;
+
+ return FRL_CAP_CHK_OK;
+}
+
enum frl_cap_chk_result dml1_frl_cap_chk(struct frl_cap_chk_params *params)
{
struct frl_cap_chk_intermediates inter;
+ if (params->compressed)
+ return dml1_frl_cap_chk_compressed(params, &inter);
+
return dml1_frl_cap_chk_inter(params, &inter);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.h
b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.h
index 545f498ea396..debe4c1dc0f7 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.h
@@ -119,6 +119,13 @@ struct frl_cap_chk_params {
bool compressed; /* set to true if DSC is enabled */
bool bypass_hc_target_calc; /* debug only */
+ bool allow_all_bpp; /* dsc_all_bpp */
+
+ /* DSC parameters */
+ int slices;
+ int slice_width;
+ double bpp_target;
+ bool is_ovt;
int layout;
int acat; /* not supported */
@@ -138,6 +145,8 @@ enum frl_cap_chk_result dml1_frl_cap_chk_common(struct
frl_cap_chk_intermediates
enum frl_cap_chk_result dml1_frl_cap_chk_uncompressed(struct
frl_cap_chk_params *params,
struct
frl_cap_chk_intermediates *inter);
+enum frl_cap_chk_result dml1_frl_cap_chk_compressed(struct frl_cap_chk_params
*params,
+ struct
frl_cap_chk_intermediates *inter);
#endif
void frl_modified_pix_clock_for_dsc_padding(const int hc_active_target,
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
index 8dfb6dd14eb2..c0f489ccf5e1 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
@@ -151,6 +151,166 @@ uint32_t dc_bandwidth_in_kbps_from_timing(
return kbps;
}
+const struct dc_dsc_primary_bpp prim_bpp_444[] = {
+ /* VIC/BPP */
+ {64, 192}, /* 1920x1080 @ 100 */
+ {77, 192}, /* 1920x1080 @ 100 */
+ {63, 192}, /* 1920x1080 @ 120 */
+ {78, 192}, /* 1920x1080 @ 120 */
+ {93, 192}, /* 3840x2160 @ 24 */
+ {103, 192}, /* 3840x2160 @ 24 */
+ {94, 192}, /* 3840x2160 @ 25 */
+ {104, 192}, /* 3840x2160 @ 25 */
+ {95, 192}, /* 3840x2160 @ 30 */
+ {105, 192}, /* 3840x2160 @ 30 */
+ {114, 192}, /* 3840x2160 @ 48 */
+ {116, 192}, /* 3840x2160 @ 48 */
+ {96, 192}, /* 3840x2160 @ 50 */
+ {106, 192}, /* 3840x2160 @ 50 */
+ {97, 192}, /* 3840x2160 @ 60 */
+ {107, 192}, /* 3840x2160 @ 60 */
+ {117, 192}, /* 3840x2160 @ 100 */
+ {119, 192}, /* 3840x2160 @ 100 */
+ {118, 192}, /* 3840x2160 @ 120 */
+ {120, 192}, /* 3840x2160 @ 120 */
+ {98, 192}, /* 4096x2160 @ 24 */
+ {99, 192}, /* 4096x2160 @ 25 */
+ {100, 192}, /* 4096x2160 @ 30 */
+ {115, 192}, /* 4096x2160 @ 48 */
+ {101, 192}, /* 4096x2160 @ 50 */
+ {102, 192}, /* 4096x2160 @ 60 */
+ {218, 192}, /* 4096x2160 @ 100 */
+ {219, 192}, /* 4096x2160 @ 120 */
+ {121, 192}, /* 5120x2160 @ 24 */
+ {122, 192}, /* 5120x2160 @ 25 */
+ {123, 192}, /* 5120x2160 @ 30 */
+ {124, 192}, /* 5120x2160 @ 48 */
+ {125, 192}, /* 5120x2160 @ 50 */
+ {126, 173}, /* 5120x2160 @ 60 */
+ {127, 192}, /* 5120x2160 @ 100 */
+ {193, 175}, /* 5120x2160 @ 120 */
+ {194, 192}, /* 7680x2160 @ 24 */
+ {202, 192}, /* 7680x2160 @ 24 */
+ {195, 192}, /* 7680x2160 @ 25 */
+ {203, 192}, /* 7680x2160 @ 25 */
+ {196, 192}, /* 7680x2160 @ 30 */
+ {204, 192}, /* 7680x2160 @ 30 */
+ {197, 157}, /* 7680x2160 @ 48 */
+ {205, 157}, /* 7680x2160 @ 48 */
+ {198, 157}, /* 7680x2160 @ 50 */
+ {206, 157}, /* 7680x2160 @ 50 */
+ {199, 159}, /* 7680x2160 @ 60 */
+ {207, 159}, /* 7680x2160 @ 60 */
+ {200, 134}, /* 7680x2160 @ 100 */
+ {208, 134}, /* 7680x2160 @ 100 */
+ {201, 130}, /* 7680x2160 @ 120 */
+ {209, 130}, /* 7680x2160 @ 120 */
+ {210, 182}, /* 10240x4320 @ 24 */
+ {211, 181}, /* 10240x4320 @ 25 */
+ {212, 177}, /* 10240x4320 @ 30 */
+ {213, 163}, /* 10240x4320 @ 48 */
+ {214, 162}, /* 10240x4320 @ 50 */
+ {215, 157}, /* 10240x4320 @ 60 */
+};
+const struct dc_dsc_primary_bpp prim_bpp_422[] = {
+ /* VIC/BPP */
+ {114, 192}, /* 3840x2160 @ 48 */
+ {116, 192}, /* 3840x2160 @ 48 */
+ {96, 192}, /* 3840x2160 @ 50 */
+ {106, 192}, /* 3840x2160 @ 50 */
+ {97, 192}, /* 3840x2160 @ 60 */
+ {107, 192}, /* 3840x2160 @ 60 */
+ {117, 137}, /* 3840x2160 @ 100 */
+ {119, 137}, /* 3840x2160 @ 100 */
+ {118, 113}, /* 3840x2160 @ 120 */
+ {120, 113}, /* 3840x2160 @ 120 */
+ {115, 192}, /* 4096x2160 @ 48 */
+ {101, 192}, /* 4096x2160 @ 50 */
+ {102, 192}, /* 4096x2160 @ 60 */
+ {218, 192}, /* 4096x2160 @ 100 */
+ {219, 192}, /* 4096x2160 @ 120 */
+ {121, 192}, /* 5120x2160 @ 24 */
+ {122, 192}, /* 5120x2160 @ 25 */
+ {123, 192}, /* 5120x2160 @ 30 */
+ {124, 192}, /* 5120x2160 @ 48 */
+ {125, 192}, /* 5120x2160 @ 50 */
+ {126, 173}, /* 5120x2160 @ 60 */
+ {127, 192}, /* 5120x2160 @ 100 */
+ {193, 175}, /* 5120x2160 @ 120 */
+ {194, 123}, /* 7680x2160 @ 24 */
+ {202, 123}, /* 7680x2160 @ 24 */
+ {195, 123}, /* 7680x2160 @ 25 */
+ {203, 123}, /* 7680x2160 @ 25 */
+ {196, 118}, /* 7680x2160 @ 30 */
+ {204, 118}, /* 7680x2160 @ 30 */
+ {197, 123}, /* 7680x2160 @ 48 */
+ {205, 123}, /* 7680x2160 @ 48 */
+ {198, 123}, /* 7680x2160 @ 50 */
+ {206, 123}, /* 7680x2160 @ 50 */
+ {199, 119}, /* 7680x2160 @ 60 */
+ {207, 119}, /* 7680x2160 @ 60 */
+ {200, 134}, /* 7680x2160 @ 100 */
+ {208, 134}, /* 7680x2160 @ 100 */
+ {201, 130}, /* 7680x2160 @ 120 */
+ {209, 130}, /* 7680x2160 @ 120 */
+ {210, 182}, /* 10240x4320 @ 24 */
+ {211, 181}, /* 10240x4320 @ 25 */
+ {212, 177}, /* 10240x4320 @ 30 */
+ {213, 126}, /* 10240x4320 @ 48 */
+ {214, 125}, /* 10240x4320 @ 50 */
+ {215, 117}, /* 10240x4320 @ 60 */
+ {216, 125}, /* 10240x4320 @ 100 */
+ {217, 117}, /* 10240x4320 @ 120 */
+};
+
+const struct dc_dsc_primary_bpp prim_bpp_420[] = {
+ /* VIC/BPP */
+ {114, 192}, /* 3840x2160 @ 48 */
+ {116, 192}, /* 3840x2160 @ 48 */
+ {96, 192}, /* 3840x2160 @ 50 */
+ {106, 192}, /* 3840x2160 @ 50 */
+ {97, 192}, /* 3840x2160 @ 60 */
+ {107, 192}, /* 3840x2160 @ 60 */
+ {117, 137}, /* 3840x2160 @ 100 */
+ {119, 137}, /* 3840x2160 @ 100 */
+ {118, 113}, /* 3840x2160 @ 120 */
+ {120, 113}, /* 3840x2160 @ 120 */
+ {115, 192}, /* 4096x2160 @ 48 */
+ {101, 192}, /* 4096x2160 @ 50 */
+ {102, 192}, /* 4096x2160 @ 60 */
+ {218, 129}, /* 4096x2160 @ 100 */
+ {219, 106}, /* 4096x2160 @ 120 */
+ {124, 192}, /* 5120x2160 @ 48 */
+ {125, 192}, /* 5120x2160 @ 50 */
+ {126, 173}, /* 5120x2160 @ 60 */
+ {127, 192}, /* 5120x2160 @ 100 */
+ {193, 175}, /* 5120x2160 @ 120 */
+ {194, 123}, /* 7680x4320 @ 24 */
+ {202, 123}, /* 7680x4320 @ 24 */
+ {195, 123}, /* 7680x4320 @ 25 */
+ {203, 123}, /* 7680x4320 @ 25 */
+ {196, 118}, /* 7680x4320 @ 30 */
+ {204, 118}, /* 7680x4320 @ 30 */
+ {197, 123}, /* 7680x4320 @ 48 */
+ {205, 123}, /* 7680x4320 @ 48 */
+ {198, 123}, /* 7680x4320 @ 50 */
+ {206, 123}, /* 7680x4320 @ 50 */
+ {199, 119}, /* 7680x4320 @ 60 */
+ {207, 119}, /* 7680x4320 @ 60 */
+ {200, 112}, /* 7680x4320 @ 100 */
+ {208, 112}, /* 7680x4320 @ 100 */
+ {201, 103}, /* 7680x4320 @ 120 */
+ {209, 103}, /* 7680x4320 @ 120 */
+ {210, 98}, /* 10240x4320 @ 24 */
+ {211, 98}, /* 10240x4320 @ 25 */
+ {212, 177}, /* 10240x4320 @ 30 */
+ {213, 98}, /* 10240x4320 @ 48 */
+ {214, 125}, /* 10240x4320 @ 50 */
+ {215, 117}, /* 10240x4320 @ 60 */
+ {216, 107}, /* 10240x4320 @ 100 */
+ {217, 97}, /* 10240x4320 @ 120 */
+};
+
/* Forward Declerations */
static unsigned int get_min_dsc_slice_count_for_odm(
const struct display_stream_compressor *dsc,
@@ -194,6 +354,15 @@ static bool setup_dsc_config(
int min_slice_count,
struct dc_dsc_config *dsc_cfg);
+static bool convert_bandwidth_to_frl_params(
+ int bandwidth_kbps,
+ int *num_lanes,
+ int *frl_rate);
+
+static uint32_t compute_bpp_x16_from_frl_params(
+ const struct dc_crtc_timing *timing,
+ const uint32_t num_slices_h,
+ const struct dsc_enc_caps *dsc_caps);
static bool dsc_buff_block_size_from_dpcd(int dpcd_buff_block_size, int
*buff_block_size)
{
@@ -328,6 +497,207 @@ static bool dsc_bpp_increment_div_from_dpcd(uint8_t
bpp_increment_dpcd, uint32_t
+static bool get_vic_preset_bpp(
+ const struct dc_crtc_timing *timing,
+ int *preset_bpp)
+{
+ bool preset_found = false;
+ uint32_t table_size_444 = ARRAY_SIZE(prim_bpp_444);
+ uint32_t table_size_422 = ARRAY_SIZE(prim_bpp_422);
+ uint32_t table_size_420 = ARRAY_SIZE(prim_bpp_420);
+ uint32_t i;
+ uint32_t vid_id;
+
+ if (timing->vic == 0 && timing->hdmi_vic == 0)
+ return false;
+
+ vid_id = timing->vic;
+ switch (timing->hdmi_vic) {
+ case 1:
+ vid_id = 95;
+ break;
+ case 2:
+ vid_id = 94;
+ break;
+ case 3:
+ vid_id = 93;
+ break;
+ case 4:
+ vid_id = 98;
+ break;
+ default:
+ break;
+ }
+
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB ||
+ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ for (i = 0; i < table_size_444 ; i++) {
+ if (prim_bpp_444[i].vic == vid_id) {
+ preset_found = true;
+ *preset_bpp = prim_bpp_444[i].target_bpp;
+ break;
+ }
+ }
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+ for (i = 0; i < table_size_422 ; i++) {
+ if (prim_bpp_422[i].vic == vid_id) {
+ preset_found = true;
+ *preset_bpp = prim_bpp_422[i].target_bpp;
+ break;
+ }
+ }
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+ for (i = 0; i < table_size_420 ; i++) {
+ if (prim_bpp_420[i].vic == vid_id) {
+ preset_found = true;
+ *preset_bpp = prim_bpp_420[i].target_bpp;
+ break;
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return preset_found;
+}
+
+static int hdmi_dsc_get_num_slices(const struct dc_crtc_timing *timing)
+{
+ int k_slice_adjust = 1;
+ int adj_pix_clk_mhz;
+ int min_slices;
+ int slice_target;
+ int slice_width = timing->h_addressable;
+ int h_ratio_adj_pix_clk_mhz;
+
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB ||
+ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ k_slice_adjust = 2;
+
+ adj_pix_clk_mhz = k_slice_adjust * timing->pix_clk_100hz / 10000 / 2;
+ h_ratio_adj_pix_clk_mhz = adj_pix_clk_mhz * timing->h_addressable /
timing->h_total;
+ if (adj_pix_clk_mhz <= 2720) {
+ min_slices = adj_pix_clk_mhz / 340;
+ if (adj_pix_clk_mhz % 340 != 0)
+ min_slices++;
+ } else if (adj_pix_clk_mhz <= 4800) {
+ min_slices = adj_pix_clk_mhz / 400;
+ if (adj_pix_clk_mhz % 400 != 0)
+ min_slices++;
+ } else if (h_ratio_adj_pix_clk_mhz <= 4800) {
+ min_slices = h_ratio_adj_pix_clk_mhz / 600;
+ if (h_ratio_adj_pix_clk_mhz % 600 != 0)
+ min_slices++;
+ } else {
+ min_slices = h_ratio_adj_pix_clk_mhz / 900;
+ if (h_ratio_adj_pix_clk_mhz % 900 != 0)
+ min_slices++;
+ }
+
+ do {
+ if (min_slices <= 1)
+ slice_target = 1;
+ else if (min_slices <= 2)
+ slice_target = 2;
+ else if (min_slices <= 4)
+ slice_target = 4;
+ else if (min_slices <= 8)
+ slice_target = 8;
+ else if (min_slices <= 12)
+ slice_target = 12;
+ else if (min_slices <= 16)
+ slice_target = 16;
+ else
+ return 0;
+
+ slice_width = timing->h_addressable / slice_target;
+ min_slices++;
+ } while (slice_width > 2720);
+
+ return slice_target;
+}
+
+static int hdmi_dsc_get_bpp(const struct dc_crtc_timing *timing,
+ const struct dsc_enc_caps *dsc_common_caps)
+{
+ int max_dsc_bpp, min_dsc_bpp;
+ int target_bytes;
+ bool bpp_found = false;
+ int bpp_decrement_x16;
+ int src_fractional_bpp = dsc_common_caps->bpp_increment_div;
+ int bpp_target;
+ int bpp_target_x16;
+ int bpc_factor = 8;
+ int slice_width;
+ int num_slices;
+ bool hdmi_all_bpp = dsc_common_caps->is_vic_all_bpp;
+ int hdmi_max_chunk_bytes = dsc_common_caps->total_chunk_kbytes;
+
+ int preset_bpp;
+ bool preset_found = false;
+
+ if (timing->display_color_depth == COLOR_DEPTH_101010)
+ bpc_factor = 10;
+ if (timing->display_color_depth == COLOR_DEPTH_121212)
+ bpc_factor = 12;
+
+ /* Assuming: bpc as 8*/
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB ||
+ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ min_dsc_bpp = 8;
+ max_dsc_bpp = 3 * bpc_factor;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+ min_dsc_bpp = 7;
+ max_dsc_bpp = 2 * bpc_factor;
+ } else {
+ min_dsc_bpp = 6;
+ max_dsc_bpp = 3 * bpc_factor / 2;
+ }
+
+ if (!hdmi_all_bpp)
+ max_dsc_bpp = min(max_dsc_bpp, 12);
+
+
+ num_slices = hdmi_dsc_get_num_slices(timing);
+ if (num_slices == 0)
+ return 0;
+
+ slice_width = timing->h_addressable / num_slices;
+
+ bpp_target = max_dsc_bpp;
+ bpp_decrement_x16 = 16 / src_fractional_bpp;
+ bpp_target_x16 = (bpp_target * 16) - bpp_decrement_x16;
+ if (!hdmi_all_bpp)
+ bpp_target_x16 = (bpp_target * 16);
+
+ /* check if byte target is below allowed Kbytes */
+ while (bpp_target_x16 > (min_dsc_bpp * 16)) {
+ target_bytes = num_slices * slice_width * bpp_target_x16 / 16 /
8;
+ if (target_bytes <= hdmi_max_chunk_bytes) {
+ bpp_found = true;
+ break;
+ }
+ bpp_target_x16 -= bpp_decrement_x16;
+ }
+
+ if (bpp_found) {
+ if (!hdmi_all_bpp) {
+ /* Get preset bpp for CTA modes */
+ preset_found = get_vic_preset_bpp(timing, &preset_bpp);
+ if (preset_found) {
+ bpp_target_x16 = preset_bpp;
+ target_bytes =
+ num_slices * slice_width *
bpp_target_x16 / 16 / 8;
+ if (target_bytes > hdmi_max_chunk_bytes)
+ return 0;
+ }
+ }
+ return bpp_target_x16;
+ }
+
+ return 0;
+}
+
bool dc_dsc_parse_dsc_dpcd(const struct dc *dc,
const uint8_t *dpcd_dsc_basic_data,
const uint8_t *dpcd_dsc_branch_decoder_caps,
@@ -450,6 +820,104 @@ bool dc_dsc_parse_dsc_dpcd(const struct dc *dc,
dsc_sink_caps->is_dp = true;
return true;
}
+bool dc_dsc_parse_dsc_edid(const struct dc *dc, const struct dc_edid_caps
*edid_caps,
+ struct dsc_dec_dpcd_caps *dsc_sink_caps)
+{
+ (void)dc;
+ dsc_sink_caps->is_dsc_supported = edid_caps->frl_dsc_support;
+ if (!edid_caps->frl_dsc_support)
+ return false;
+
+ dsc_sink_caps->dsc_version = 0x21;
+ dsc_sink_caps->is_frl = true;
+ dsc_sink_caps->is_dp = false;
+
+ switch (edid_caps->frl_dsc_max_slices) {
+ case 0:
+ break;
+ case 1:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 340;
+ dsc_sink_caps->throughput_mode_1_mps = 680;
+ break;
+ case 2:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 340;
+ dsc_sink_caps->throughput_mode_1_mps = 680;
+ break;
+ case 3:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 340;
+ dsc_sink_caps->throughput_mode_1_mps = 680;
+ break;
+ case 4:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 340;
+ dsc_sink_caps->throughput_mode_1_mps = 680;
+ break;
+ case 5:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 400;
+ dsc_sink_caps->throughput_mode_1_mps = 800;
+ break;
+ case 6:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_12 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 400;
+ dsc_sink_caps->throughput_mode_1_mps = 800;
+ break;
+ case 7:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_12 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 600;
+ dsc_sink_caps->throughput_mode_1_mps = 1200;
+ break;
+ case 8:
+ default:
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 = 1;
+ dsc_sink_caps->slice_caps1.bits.NUM_SLICES_12 = 1;
+ dsc_sink_caps->throughput_mode_0_mps = 900;
+ dsc_sink_caps->throughput_mode_1_mps = 1800;
+ break;
+ }
+ dsc_sink_caps->lb_bit_depth = 13; //Table 7-25
+ dsc_sink_caps->is_block_pred_supported = true; //Table 7-25
+ dsc_sink_caps->color_formats.bits.RGB = 1;
+ dsc_sink_caps->color_formats.bits.YCBCR_444 = 1;
+ dsc_sink_caps->color_formats.bits.YCBCR_NATIVE_422 = 1;
+ dsc_sink_caps->color_formats.bits.YCBCR_NATIVE_420 =
+ (edid_caps->frl_dsc_native_420 == true) ? 1 : 0;
+ dsc_sink_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
+ dsc_sink_caps->color_depth.bits.COLOR_DEPTH_10_BPC =
+ (edid_caps->frl_dsc_10bpc == true) ? 1 : 0;
+ dsc_sink_caps->color_depth.bits.COLOR_DEPTH_12_BPC =
+ (edid_caps->frl_dsc_12bpc == true) ? 1 : 0;
+ dsc_sink_caps->max_slice_width = 2560;
+ dsc_sink_caps->bpp_increment_div = 16; /* bpp increment divisor, e.g.
if 16, it's 1/16th of a bit */
+ dsc_sink_caps->is_vic_all_bpp = edid_caps->frl_dsc_all_bpp;
+ dsc_sink_caps->total_chunk_kbytes =
+ 1024 * (1 + edid_caps->frl_dsc_total_chunk_kbytes);
+
+ return true;
+}
/* If DSC is possbile, get DSC bandwidth range based on [min_bpp, max_bpp]
target bitrate range and
* timing's pixel clock and uncompressed bandwidth.
@@ -757,6 +1225,9 @@ static bool intersect_dsc_caps(
if (pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding ==
PIXEL_ENCODING_YCBCR420)
dsc_common_caps->bpp_increment_div =
min(dsc_common_caps->bpp_increment_div, (uint32_t)8);
+ dsc_common_caps->is_frl = dsc_sink_caps->is_frl;
+ dsc_common_caps->is_vic_all_bpp = dsc_sink_caps->is_vic_all_bpp;
+ dsc_common_caps->total_chunk_kbytes = dsc_sink_caps->total_chunk_kbytes;
dsc_common_caps->edp_sink_max_bits_per_pixel =
dsc_sink_caps->edp_max_bits_per_pixel;
dsc_common_caps->is_dp = dsc_sink_caps->is_dp;
return true;
@@ -786,6 +1257,191 @@ static uint32_t compute_bpp_x16_from_target_bandwidth(
return dc_fixpt_floor(bpp_x16);
}
+static bool convert_bandwidth_to_frl_params(
+ int bandwidth_kbps,
+ int *num_lanes,
+ int *frl_rate)
+{
+ if (bandwidth_kbps == 0)
+ return false;
+
+ switch (bandwidth_kbps) {
+ case 9000000:
+ *num_lanes = 3;
+ *frl_rate = 3000;
+ break;
+ case 18000000:
+ *num_lanes = 3;
+ *frl_rate = 6000;
+ break;
+ case 24000000:
+ *num_lanes = 4;
+ *frl_rate = 6000;
+ break;
+ case 32000000:
+ *num_lanes = 4;
+ *frl_rate = 8000;
+ break;
+ case 40000000:
+ *num_lanes = 4;
+ *frl_rate = 10000;
+ break;
+ case 48000000:
+ *num_lanes = 4;
+ *frl_rate = 12000;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static uint32_t compute_bpp_x16_from_frl_params(
+ const struct dc_crtc_timing *timing,
+ const uint32_t num_slices_h,
+ const struct dsc_enc_caps *dsc_caps)
+{
+ struct fixed31_32 pixel_clock;
+ uint32_t num_lanes = dsc_caps->num_lanes;
+ uint32_t frl_rate = dsc_caps->frl_rate;
+ uint32_t h_active = timing->h_addressable;
+ uint32_t h_blank = timing->h_total - timing->h_addressable;
+ uint32_t bpp_target_x16;
+ struct fixed31_32 r_bit;
+ uint32_t f_audio = 48000;
+ struct fixed31_32 pixel_rate_tolerance;
+ uint32_t audio_tolerance = 1000;
+ uint32_t frl_bit_tolerance = 300;
+ uint32_t acr_rate_max = 1500;
+ uint32_t c_frl_cb = 510;
+ uint32_t c_frl_sb;
+ struct fixed31_32 overhead_sb;
+ struct fixed31_32 overhead_rs;
+ struct fixed31_32 overhead_map;
+ struct fixed31_32 overhead_min;
+ struct fixed31_32 overhead_m;
+ struct fixed31_32 overhead_max;
+ struct fixed31_32 pixel_clock_max;
+ struct fixed31_32 t_line;
+ struct fixed31_32 r_bit_min;
+ struct fixed31_32 r_frl_char_min;
+ struct fixed31_32 c_frl_line;
+ uint32_t c_frl_line_int;
+ struct fixed31_32 c_frl_available;
+ uint32_t c_frl_av_int;
+ struct fixed31_32 c_frl_active_av;
+ struct fixed31_32 c_frl_blank_av;
+ uint32_t acat_ap = 4;
+ struct fixed31_32 r_ap;
+ struct fixed31_32 max_audio_tol_rate;
+ struct fixed31_32 avg_audio_packets_line;
+ uint32_t avg_audio_packets_line_int;
+ int hc_blank_audio_min;
+ uint32_t bytes_target;
+ uint32_t hc_active_target;
+ uint32_t hc_blank_target_est1;
+ uint32_t hc_blank_target_est2;
+ struct fixed31_32 hc_blank_target_bandwidth;
+ int hc_blank_target;
+ uint32_t bpc_factor = 8;
+ uint32_t min_dsc_bpp_x16;
+ uint32_t max_dsc_bpp_x16;
+ bool hdmi_all_bpp = dsc_caps->is_vic_all_bpp;
+ uint32_t slice_width;
+
+ if (timing->display_color_depth == COLOR_DEPTH_101010)
+ bpc_factor = 10;
+ if (timing->display_color_depth == COLOR_DEPTH_121212)
+ bpc_factor = 12;
+
+ /* Assuming: bpc as 8*/
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB ||
+ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ min_dsc_bpp_x16 = 8 * 16;
+ max_dsc_bpp_x16 = 3 * 16 * bpc_factor;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+ min_dsc_bpp_x16 = 7 * 16;
+ max_dsc_bpp_x16 = 2 * 16 * bpc_factor;
+ } else {
+ min_dsc_bpp_x16 = 6 * 16;
+ max_dsc_bpp_x16 = 3 * 16 * bpc_factor / 2;
+ }
+
+ max_dsc_bpp_x16 = MIN(max_dsc_bpp_x16, 256);
+ if (!hdmi_all_bpp)
+ max_dsc_bpp_x16 = MIN(max_dsc_bpp_x16, 192);
+
+ c_frl_sb = 4 * c_frl_cb + num_lanes;
+ pixel_clock =
dc_fixpt_div_int(dc_fixpt_from_int(timing->pix_clk_100hz), 10000);
+ r_bit = dc_fixpt_from_int(frl_rate);
+ pixel_rate_tolerance = dc_fixpt_div_int(dc_fixpt_from_int(5), 1000);
+ overhead_sb = dc_fixpt_div_int(dc_fixpt_from_int(num_lanes), c_frl_sb);
+ overhead_rs = dc_fixpt_div_int(dc_fixpt_from_int(32), c_frl_sb);
+ overhead_map = dc_fixpt_div_int(dc_fixpt_from_int(25), (c_frl_sb * 10));
+ overhead_min = dc_fixpt_add(overhead_sb, overhead_rs);
+ overhead_min = dc_fixpt_add(overhead_min, overhead_map);
+ overhead_m = dc_fixpt_div_int(dc_fixpt_from_int(3), 1000);
+ overhead_max = dc_fixpt_add(overhead_min, overhead_m);
+ pixel_rate_tolerance = dc_fixpt_add_int(pixel_rate_tolerance, 1);
+ pixel_clock_max = dc_fixpt_mul(pixel_clock, pixel_rate_tolerance);
+ t_line = dc_fixpt_div(dc_fixpt_from_int(h_active + h_blank),
pixel_clock_max);
+ r_bit_min = dc_fixpt_div_int(dc_fixpt_from_int(frl_bit_tolerance),
1000000);
+ r_bit_min = dc_fixpt_sub(dc_fixpt_from_int(1), r_bit_min);
+ r_bit_min = dc_fixpt_mul(r_bit, r_bit_min);
+ r_frl_char_min = dc_fixpt_div_int(r_bit_min, 18);
+ c_frl_line = dc_fixpt_mul(t_line, r_frl_char_min);
+ c_frl_line = dc_fixpt_mul_int(c_frl_line, num_lanes);
+ c_frl_line_int = dc_fixpt_floor(c_frl_line);
+ c_frl_available = dc_fixpt_sub(dc_fixpt_from_int(1), overhead_max);
+ c_frl_available = dc_fixpt_mul_int(c_frl_available, c_frl_line_int);
+ c_frl_av_int = dc_fixpt_floor(c_frl_available);
+ c_frl_active_av = dc_fixpt_mul_int(dc_fixpt_from_int(c_frl_av_int),
h_active);
+ c_frl_active_av = dc_fixpt_div_int(c_frl_active_av, (h_active +
h_blank));
+ c_frl_blank_av = dc_fixpt_mul_int(dc_fixpt_from_int(c_frl_av_int),
h_blank);
+ c_frl_blank_av = dc_fixpt_div_int(c_frl_blank_av, (h_active +
h_blank));
+ r_ap = dc_fixpt_max(dc_fixpt_from_int(192000),
+ dc_fixpt_from_int(f_audio * acat_ap));
+ r_ap = dc_fixpt_add(r_ap, dc_fixpt_from_int(2 * acr_rate_max));
+ max_audio_tol_rate =
dc_fixpt_div_int(dc_fixpt_from_int(audio_tolerance), 1000000);
+ max_audio_tol_rate = dc_fixpt_add(dc_fixpt_from_int(1),
max_audio_tol_rate);
+ r_ap = dc_fixpt_mul(r_ap, max_audio_tol_rate);
+ avg_audio_packets_line = dc_fixpt_mul(r_ap, t_line);
+ avg_audio_packets_line = dc_fixpt_div_int(avg_audio_packets_line,
1000000);
+ avg_audio_packets_line_int = dc_fixpt_ceil(avg_audio_packets_line);
+ hc_blank_audio_min = 32 + 32 * avg_audio_packets_line_int;
+ slice_width = dc_fixpt_ceil(dc_fixpt_div_int(
+ dc_fixpt_from_int(h_active), num_slices_h));
+
+ /* Slice width for 420 must be even */
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 && slice_width %
2 != 0) {
+ slice_width++;
+ }
+
+ for (uint32_t i = max_dsc_bpp_x16; i >= min_dsc_bpp_x16; i--) {
+ bpp_target_x16 = i;
+ bytes_target = num_slices_h * dc_fixpt_ceil(dc_fixpt_div_int(
+ dc_fixpt_from_int(bpp_target_x16 *
slice_width), 8 * 16));
+ hc_active_target = dc_fixpt_ceil(dc_fixpt_div_int(
+ dc_fixpt_from_int(bytes_target), 3));
+ hc_blank_target_est1 = dc_fixpt_ceil(dc_fixpt_div_int(
+ dc_fixpt_from_int(hc_active_target * h_blank),
h_active));
+ hc_blank_target_est2 = dc_fixpt_floor(dc_fixpt_max(
+ dc_fixpt_from_int(hc_blank_target_est1),
+ dc_fixpt_from_int(hc_blank_audio_min)));
+ hc_blank_target_bandwidth =
dc_fixpt_div_int(dc_fixpt_from_int(3), 2);
+ hc_blank_target_bandwidth =
dc_fixpt_mul(hc_blank_target_bandwidth,
+ dc_fixpt_from_int(hc_active_target));
+ hc_blank_target_bandwidth =
dc_fixpt_sub(dc_fixpt_from_int(c_frl_av_int),
+ hc_blank_target_bandwidth);
+ hc_blank_target_bandwidth =
dc_fixpt_min(hc_blank_target_bandwidth,
+ dc_fixpt_from_int(hc_blank_target_est2));
+ hc_blank_target_bandwidth =
dc_fixpt_div_int(hc_blank_target_bandwidth, 4);
+ hc_blank_target = dc_fixpt_floor(hc_blank_target_bandwidth) * 4;
+ if (hc_blank_target >= hc_blank_audio_min)
+ return bpp_target_x16;
+ }
+ return 0;
+}
/* Decide DSC bandwidth range based on signal, timing, specs specific and
input min and max
* requirements.
* The range output includes decided min/max target bpp, the respective
bandwidth requirements
@@ -812,6 +1468,30 @@ static bool decide_dsc_bandwidth_range(
range->min_target_bpp_x16 = preferred_bpp_x16;
}
}
+ else if (dsc_caps->is_frl) {
+ uint32_t specs_preferred_bpp_x16 = hdmi_dsc_get_bpp(timing,
dsc_caps);
+ uint32_t specs_calculated_bpp_x16 = 0;
+
+ if (timing->vic) {
+ /* For CTA timing, we should strictly follow HDMI spec.
*/
+ range->max_target_bpp_x16 = specs_preferred_bpp_x16;
+ if (dsc_caps->is_vic_all_bpp || dsc_caps->is_dp)
+ range->min_target_bpp_x16 = min_bpp_x16;
+ else
+ range->min_target_bpp_x16 =
specs_preferred_bpp_x16;
+ } else {
+ if (timing->vic == 0 && timing->hdmi_vic == 0)
+ specs_calculated_bpp_x16 =
compute_bpp_x16_from_frl_params(
+ timing, num_slices_h, dsc_caps);
+
+ if (specs_calculated_bpp_x16 != 0)
+ specs_preferred_bpp_x16 =
MIN(specs_calculated_bpp_x16,
+ specs_preferred_bpp_x16);
+
+ range->max_target_bpp_x16 = MIN(max_bpp_x16,
specs_preferred_bpp_x16);
+ range->min_target_bpp_x16 = min_bpp_x16;
+ }
+ }
/* TODO - make this value generic to all signal types */
else if (dsc_caps->edp_sink_max_bits_per_pixel) {
/* apply max bpp limitation from edp sink */
@@ -877,6 +1557,10 @@ static bool decide_dsc_target_bpp_x16(
dsc_common_caps->bpp_increment_div,
dsc_common_caps->is_dp);
}
+ /* Assign minimum bpp and validate TB borrow scenario later */
+ if (target_bandwidth_kbps < range.min_kbps)
+ if (dsc_common_caps->is_frl)
+ *target_bpp_x16 = range.min_target_bpp_x16;
}
return *target_bpp_x16 != 0;
@@ -1061,6 +1745,8 @@ static bool setup_dsc_config(
int pic_height;
int slice_height;
struct dc_dsc_policy policy;
+ int num_lanes;
+ int frl_rate;
memset(dsc_cfg, 0, sizeof(struct dc_dsc_config));
@@ -1078,6 +1764,11 @@ static bool setup_dsc_config(
is_dsc_possible = intersect_dsc_caps(dsc_sink_caps, dsc_enc_caps,
timing->pixel_encoding, &dsc_common_caps);
if (!is_dsc_possible)
goto done;
+ if (convert_bandwidth_to_frl_params(
+ target_bandwidth_kbps, &num_lanes,
&frl_rate)) {
+ dsc_common_caps.num_lanes = num_lanes;
+ dsc_common_caps.frl_rate = frl_rate;
+ }
sink_per_slice_throughput_mps = 0;
@@ -1201,6 +1892,8 @@ static bool setup_dsc_config(
else
is_dsc_possible = false;
}
+ if (dsc_sink_caps->is_frl)
+ num_slices_h = hdmi_dsc_get_num_slices(timing);
// When we force ODM, num dsc h slices must be divisible by num odm h
slices
switch (options->dsc_force_odm_hslice_override) {
case 0:
@@ -1279,6 +1972,11 @@ static bool setup_dsc_config(
dsc_cfg->block_pred_enable = dsc_common_caps.is_block_pred_supported;
dsc_cfg->linebuf_depth = dsc_common_caps.lb_bit_depth;
dsc_cfg->version_minor = (dsc_common_caps.dsc_version & 0xf0) >> 4;
+ dsc_cfg->is_frl = dsc_sink_caps->is_frl;
+ if (dsc_cfg->is_frl)
+ dsc_cfg->num_slices_h = num_slices_h;
+ dsc_cfg->is_vic_all_bpp = dsc_sink_caps->is_vic_all_bpp;
+ dsc_cfg->total_chunk_kbytes = dsc_sink_caps->total_chunk_kbytes;
dsc_cfg->is_dp = dsc_sink_caps->is_dp;
done:
@@ -1405,6 +2103,12 @@ void dc_dsc_get_policy_for_timing(const struct
dc_crtc_timing *timing,
/* DP specs limits to 3 x bpc */
policy->max_target_bpp = 3 * bpc;
policy->ycbcr422_simple = true;
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 &&
link_encoding == DC_LINK_ENCODING_HDMI_FRL) {
+ /* HDMI FRL YCbCr422 native support */
+ policy->min_target_bpp = 7;
+ policy->max_target_bpp = 2 * bpc;
+ policy->ycbcr422_simple = false;
+ }
break;
case PIXEL_ENCODING_YCBCR420:
/* DP specs limits to 6 */
diff --git
a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
index cd7d2bb661e5..cff5c95a771c 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
@@ -216,6 +216,16 @@ void hpo_enc3_set_hdmi_stream_attribute(struct
hpo_frl_stream_encoder *enc,
break;
}
+ /* When compression active, CD/PP/Phase field shall be zero in GCP */
+ if (crtc_timing->flags.DSC) {
+ REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
+ HDMI_DEEP_COLOR_DEPTH, 0,
+ HDMI_DEEP_COLOR_ENABLE, 0);
+ } else {
+ REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+ HDMI_DSC_MODE, 0);
+ }
+
/* Configure ODM combine mode */
switch (odm_combine_num_segments) {
case 1:
@@ -457,6 +467,94 @@ void hpo_enc3_update_hdmi_info_packet(struct
dcn30_hpo_frl_stream_encoder *enc3,
}
}
+void hpo_enc3_hdmi_set_dsc_config(
+ struct hpo_frl_stream_encoder *enc,
+ struct dc_crtc_timing *timing,
+ uint8_t *dsc_packed_pps)
+{
+ struct dcn30_hpo_frl_stream_encoder *enc3 =
DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
+ enum optc_dsc_mode dsc_mode = OPTC_DSC_DISABLED;
+ uint8_t i;
+
+ if (dsc_packed_pps) {
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
+ (timing->pixel_encoding ==
PIXEL_ENCODING_YCBCR422
+ && !timing->dsc_cfg.ycbcr422_simple))
+ dsc_mode = OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+ else
+ dsc_mode = OPTC_DSC_ENABLED_444;
+ }
+
+ REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
+ FIFO_DSC_MODE, dsc_mode);
+
+ REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
+ HDMI_DSC_MODE, dsc_mode);
+
+ /* 5 packets for hdmi 2.1, use generic packets 5-10 to transmit*/
+ /* TODO: do we change new bit to 0 after first transmission? Do we set
End bit when exiting dsc? */
+ if (dsc_mode != OPTC_DSC_DISABLED) {
+ struct dc_info_packet emp_packet = {0};
+ uint32_t dsc_pic_width = timing->h_addressable +
timing->h_border_left + timing->h_border_right;
+ uint32_t h_back = timing->h_total - dsc_pic_width -
timing->h_sync_width - timing->h_front_porch;
+ /* HCactivebytes = Slices * ceil(SliceWidth * bpp/8)
+ * use ... + 15) / 16 to achieve ceil since bpp is stored as
16x actual value
+ */
+ uint32_t h_cactive_bytes = timing->dsc_cfg.num_slices_h * (
+ (dsc_pic_width / timing->dsc_cfg.num_slices_h *
timing->dsc_cfg.bits_per_pixel / 8 + 15) / 16);
+
+ /* Packet 0 */
+ emp_packet.valid = true;
+ emp_packet.hb0 = 0x7F; /* Default */
+ emp_packet.hb1 = (1 << 7); /* First */
+ emp_packet.hb2 = 0; /* Sequence index */
+ emp_packet.sb[0] = (1 << 1) | (1 << 2) | (1 << 7); /* Sync[1] =
1, VFR[2] = 1, New[7] = 1*/
+ emp_packet.sb[2] = 1; /* Organization_ID = 1 (Vesa spec)*/
+ emp_packet.sb[4] = 2; /* Data_Set_Tag(LSB) = 2*/
+ emp_packet.sb[6] = 136; /* Data_Set_Length(LSB) = 136*/
+ memcpy(&emp_packet.sb[7], dsc_packed_pps, 21);
+ hpo_enc3_update_hdmi_info_packet(enc3, 5, &emp_packet);
+
+ /* Packets 1-3 */
+ emp_packet.hb1 = 0; /* Not first or last*/
+ for (i = 1; i < 4; i++) {
+ emp_packet.hb2 = i; /* Sequence index */
+ memcpy(&emp_packet.sb[0], &dsc_packed_pps[21 + 28 * (i
- 1)], 28);
+ hpo_enc3_update_hdmi_info_packet(enc3, 5 + i,
&emp_packet);
+ }
+
+ /* Packet 4 */
+ emp_packet.hb2 = 4; /* Sequence index */
+ memcpy(&emp_packet.sb[0], &dsc_packed_pps[105], 23);
+ emp_packet.sb[23] = (uint8_t)timing->h_front_porch; /*
Hfront[7:0] */
+ emp_packet.sb[24] = (uint8_t)(timing->h_front_porch >> 8); /*
Hfront[15:8] */
+ emp_packet.sb[25] = (uint8_t)timing->h_sync_width; /*
Hsync[7:0] */
+ emp_packet.sb[26] = (uint8_t)(timing->h_sync_width >> 8); /*
Hsync[15:8] */
+ emp_packet.sb[27] = (uint8_t)h_back; /* Hback[7:0] */
+ hpo_enc3_update_hdmi_info_packet(enc3, 9, &emp_packet);
+
+ /* Packet 5 */
+ emp_packet.hb1 = (1 << 6); /* Last */
+ emp_packet.hb2 = 5;
+ emp_packet.sb[0] = (uint8_t)(h_back >> 8); /* Hback[15:8] */
+ emp_packet.sb[1] = (uint8_t)h_cactive_bytes; /*
HCactive_bytes[7:0] */
+ emp_packet.sb[2] = (uint8_t)(h_cactive_bytes >> 8); /*
HCactive_bytes[15:8] */
+ hpo_enc3_update_hdmi_info_packet(enc3, 10, &emp_packet);
+
+ /* Packet 0 - Clear New[7] */
+ emp_packet.valid = true;
+ emp_packet.hb0 = 0x7F; /* Default */
+ emp_packet.hb1 = (1 << 7); /* First */
+ emp_packet.hb2 = 0; /* Sequence index */
+ emp_packet.sb[0] = (1 << 1) | (1 << 2); /* Sync[1] = 1, VFR[2]
= 1*/
+ emp_packet.sb[2] = 1; /* Organization_ID = 1 (Vesa spec)*/
+ emp_packet.sb[4] = 2; /* Data_Set_Tag(LSB) = 2*/
+ emp_packet.sb[6] = 136; /* Data_Set_Length(LSB) = 136*/
+ memcpy(&emp_packet.sb[7], dsc_packed_pps, 21);
+ hpo_enc3_update_hdmi_info_packet(enc3, 5, &emp_packet);
+ }
+}
+
void hpo_enc3_stop_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc)
{
@@ -777,12 +875,18 @@ bool hpo_enc3_validate_hdmi_frl_output(
default:
break;
}
+ frl_params.allow_all_bpp = timing->dsc_cfg.is_vic_all_bpp;
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_420;
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_422;
else
frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_444;
+ /* DSC parameters */
+ frl_params.bypass_hc_target_calc = false;
+ DC_FP_START();
+ hpo_fpu_enc3_validate_hdmi_frl_output_timing(timing, audio,
&frl_params);
+ DC_FP_END();
/* Audio parameters */
/* TODO: set Audio parameters */
@@ -910,6 +1014,7 @@ static const struct hpo_frl_stream_encoder_funcs
dcn30_str_enc_funcs = {
.set_avmute = enc3_stream_encoder_set_avmute,
.validate_hdmi_frl_output = hpo_enc3_validate_hdmi_frl_output,
.read_state = hpo_enc3_read_state,
+ .hdmi_frl_set_dsc_config = hpo_enc3_hdmi_set_dsc_config,
.set_dynamic_metadata = hpo_enc3_set_dynamic_metadata,
.hdmi_frl_fifo_odm_enabled = hpo_enc3_fifo_odm_enabled,
};
diff --git
a/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
index 27f7ffd89629..28cb14dc87b0 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn401/dcn401_hpo_frl_stream_encoder.c
@@ -879,6 +879,7 @@ static const struct hpo_frl_stream_encoder_funcs
dcn401_str_enc_funcs = {
.hdmi_audio_disable = hpo_enc401_hdmi_audio_disable,
.set_avmute = enc401_stream_encoder_set_avmute,
.read_state = hpo_enc401_read_state,
+ .hdmi_frl_set_dsc_config = hpo_enc401_hdmi_set_dsc_config,
.set_dynamic_metadata = hpo_enc401_set_dynamic_metadata,
};
diff --git
a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
index 0ec386347f80..d4f66e62c729 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
@@ -179,6 +179,7 @@ static const struct hpo_frl_stream_encoder_funcs
dcn42_str_enc_funcs = {
.hdmi_audio_disable = hpo_enc42_hdmi_audio_disable,
.set_avmute = enc401_stream_encoder_set_avmute,
.read_state = hpo_enc401_read_state,
+ .hdmi_frl_set_dsc_config = hpo_enc401_hdmi_set_dsc_config,
.set_dynamic_metadata = hpo_enc401_set_dynamic_metadata,
};
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index cfca7af6cd1f..a416efcc9325 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -955,6 +955,15 @@ enum dc_status dcn30_setup_hdmi_frl_link(
return status;
}
+void dcn30_hw_set_vstartup_dsc_frl(struct dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ (void)dc;
+ if (pipe_ctx->stream_res.tg->funcs->set_vstartup_dsc_frl)
+ pipe_ctx->stream_res.tg->funcs->set_vstartup_dsc_frl(
+ pipe_ctx->stream_res.tg);
+}
+
bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
{
union dmub_rb_cmd cmd;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
index 26c7386a8a36..cd151c75f59e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
@@ -106,6 +106,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.enable_dp_link_output = dce110_enable_dp_link_output,
.disable_link_output = dce110_disable_link_output,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
index 23b30d6f3956..69b8e7030fa4 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
@@ -99,6 +99,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
index 98771fc443c7..8c50604a4895 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
@@ -101,6 +101,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
index 0b3e8512ebf1..203c4f7ecd2b 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
@@ -98,6 +98,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.get_max_dispclk_mhz = dcn32_get_max_dispclk_mhz,
.apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations,
.does_plane_fit_in_mall = NULL,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index fc18d2207711..c0cefeff6e85 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -108,6 +108,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.set_backlight_level = dcn31_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
index 19ec5b4edfdc..a852a2345296 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
@@ -101,6 +101,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.set_backlight_level = dcn31_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.set_pipe = dcn21_set_pipe,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
index d24a352937b4..e1cc16aa207c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
@@ -85,6 +85,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.apply_idle_power_optimizations = dcn401_apply_idle_power_optimizations,
.does_plane_fit_in_mall = NULL,
.set_backlight_level = dcn31_set_backlight_level,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
index 49c13611a518..e54d814b3ea9 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
@@ -86,6 +86,7 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+ .set_vstartup_dsc_frl = dcn30_hw_set_vstartup_dsc_frl,
.apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations,
.does_plane_fit_in_mall = NULL,
.set_backlight_level = dcn31_set_backlight_level,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index 7e65ccd11386..34e386e16d0c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -1437,6 +1437,9 @@ struct hw_sequencer_funcs {
unsigned int (*get_max_dispclk_mhz)(struct dc *dc,
struct dc_state *context);
+ void (*set_vstartup_dsc_frl)(struct dc *dc,
+ struct pipe_ctx *pipe_ctx);
+
/* Idle Optimization Related */
bool (*apply_idle_power_optimizations)(struct dc *dc, bool enable);
@@ -1710,6 +1713,8 @@ void
hwss_hpo_dp_stream_enc_dp_set_dsc_pps_info_packet(union block_sequence_para
void hwss_stream_enc_dp_set_dsc_pps_info_packet(union block_sequence_params
*params);
+void hwss_hpo_frl_stream_enc_set_dsc_config(union block_sequence_params
*params);
+
void hwss_set_dmdata_attributes(union block_sequence_params *params);
void hwss_dp_trace_source_sequence(union block_sequence_params *params);
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 1800b1929b16..570c45c7830f 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
@@ -368,6 +368,10 @@ struct hpo_frl_stream_encoder {
* stream interfaces for setup the FRL stream encoder.
*/
struct hpo_frl_stream_encoder_funcs {
+ void (*hdmi_frl_set_dsc_config)(
+ struct hpo_frl_stream_encoder *enc,
+ struct dc_crtc_timing *timing,
+ uint8_t *dsc_packed_pps);
/**
* @hdmi_frl_enable:
*
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index ca56854dc9f1..1cd4a882f66d 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -549,6 +549,8 @@ static void update_psp_stream_config(struct pipe_ctx
*pipe_ctx, bool dpms_off)
/* dig front end */
config.dig_fe = (uint8_t)
pipe_ctx->stream_res.stream_enc->stream_enc_inst;
+ if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+ config.dig_fe =
(uint8_t)pipe_ctx->stream_res.hpo_frl_stream_enc->stream_enc_inst;
/* stream encoder index */
config.stream_enc_idx = (uint8_t)(pipe_ctx->stream_res.stream_enc->id -
ENGINE_ID_DIGA);
@@ -785,6 +787,22 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx,
bool enable)
/* PPS SDP is set elsewhere because it has to be done
after DIG FE is connected to DIG BE */
}
+ else if (dc_is_hdmi_frl_signal(stream->signal)) {
+ uint8_t dsc_packed_pps[128];
+ struct dc_crtc_timing patched_crtc_timing =
stream->timing;
+
+ DC_LOG_DSC("Setting stream encoder DSC config for
engine %d:", (int)pipe_ctx->stream_res.hpo_frl_stream_enc->id);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+
+ /* if we are borrowing from hblank, h_addressable and
pic_width need to be adjusted */
+ if (dc->debug.enable_hblank_borrow) {
+ dsc_cfg.pic_width =
stream->timing.h_addressable;
+ }
+
+ dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg,
&dsc_packed_pps[0]);
+
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+
pipe_ctx->stream_res.hpo_frl_stream_enc, &patched_crtc_timing,
&dsc_packed_pps[0]);
+ }
/* Enable DSC in OPTC */
DC_LOG_DSC("Setting optc DSC config for tg instance %d:",
pipe_ctx->stream_res.tg->inst);
@@ -816,6 +834,9 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool
enable)
pipe_ctx->stream_res.stream_enc, false, NULL, true);
}
}
+ else if (dc_is_hdmi_frl_signal(stream->signal))
+
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+
pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, NULL);
/* disable DSC block */
for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe =
odm_pipe->next_odm_pipe) {
@@ -903,6 +924,12 @@ bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx,
bool enable, bool immedi
&dsc_packed_pps[0],
immediate_update);
}
+ else if (dc_is_hdmi_frl_signal(stream->signal)) {
+ //TODO: bring HDMI FRL in line with DP
+ DC_LOG_DSC("Setting stream encoder DSC PPS SDP for
engine %d\n", (int)pipe_ctx->stream_res.hpo_frl_stream_enc->id);
+
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+
pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, &dsc_packed_pps[0]);
+ }
} else {
/* disable DSC PPS in stream encoder */
memset(&stream->dsc_packed_pps[0], 0,
sizeof(stream->dsc_packed_pps));
@@ -917,6 +944,10 @@ bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx,
bool enable, bool immedi
pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
pipe_ctx->stream_res.stream_enc, false, NULL, true);
}
+ else if (dc_is_hdmi_frl_signal(stream->signal))
+ //TODO: bring HDMI FRL in line with DP
+
pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config(
+
pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, NULL);
}
return true;
@@ -2426,6 +2457,8 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->stream->timing.flags.DSC) {
if (dc_is_dp_signal(pipe_ctx->stream->signal))
link_set_dsc_enable(pipe_ctx, false);
+ else if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+ link_set_dsc_on_stream(pipe_ctx, false);
}
if (dp_is_128b_132b_signal(pipe_ctx)) {
if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
@@ -2606,6 +2639,11 @@ void link_set_dpms_on(
}
}
+ if (pipe_ctx->stream->timing.flags.DSC &&
+ dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+ //TODO: bring HDMI FRL in line with DP
+ link_set_dsc_on_stream(pipe_ctx, true);
+
/* turn off otg test pattern if enable */
if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c
b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c
index 6db1f07fdb79..decc3061c58c 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hdmi_frl.c
@@ -92,6 +92,25 @@ static void hdmi_return_preeshoot_and_deemphasis(struct
dc_link *link,
}
}
+static bool hdmi_frl_test_dsc_max_rate(struct ddc_service *ddc_service)
+{
+ uint8_t slave_address = HDMI_SCDC_ADDRESS;
+ uint8_t offset = HDMI_SCDC_SOURCE_TEST_REQ;
+ union hdmi_scdc_source_test_req test_req = {0};
+
+ DC_LOGGER_INIT(ddc_service->link->ctx->logger);
+
+ link_query_ddc_data(ddc_service, slave_address,
+ &offset, sizeof(offset), &test_req.byte,
+ sizeof(test_req.byte));
+ if (test_req.fields.DSC_FRL_MAX) {
+ FRL_INFO("FRL TEST REQ: DSC_FRL_MAX = 1");
+ return true;
+ }
+
+ return false;
+}
+
enum clock_source_id hdmi_frl_find_matching_phypll(
struct dc_link *link)
{
@@ -767,6 +786,9 @@ void hdmi_frl_verify_link_cap(struct dc_link *link,
link->preferred_hdmi_frl_settings.force_frl_max ||
link->ctx->dc->debug.force_frl_max ? true :
hdmi_frl_test_max_rate(link->ddc);
+ link->frl_flags.force_frl_dsc =
+ link->ctx->dc->debug.force_frl_dsc ? true :
+ hdmi_frl_test_dsc_max_rate(link->ddc);
link->frl_flags.apply_vsdb_rcc_wa =
link->ctx->dc->debug.apply_vsdb_rcc_wa;
@@ -778,8 +800,16 @@ void hdmi_frl_verify_link_cap(struct dc_link *link,
link->frl_flags.force_frl_always = true;
if (!link->frl_flags.force_frl_max &&
+ !link->frl_flags.force_frl_dsc &&
link->local_sink->edid_caps.panel_patch.hdmi_comp_auto)
{
link->frl_flags.force_frl_max = true;
+ link->frl_flags.force_frl_dsc = true;
+ }
+
+ if (link->frl_flags.force_frl_max &&
+ !link->frl_flags.force_frl_dsc &&
+ link->local_sink->edid_caps.panel_patch.hdmi_comp_auto)
{
+ link->frl_flags.force_frl_dsc = true;
}
if (link->local_sink &&
@@ -996,6 +1026,9 @@ void hdmi_frl_set_preferred_link_settings(struct dc *dc,
resource_build_info_frame(pipe);
link_stream->ctx->dc->hwss.update_info_frame(pipe);
+ if (link_stream->timing.flags.DSC)
+ link_set_dsc_on_stream(pipe, true);
+
link_stream->ctx->dc->hwss.enable_audio_stream(pipe);
link_stream->ctx->dc->hwss.enable_stream(pipe);
link_stream->ctx->dc->hwss.unblank_stream(pipe,
@@ -1104,6 +1137,10 @@ void hdmi_frl_decide_link_settings(struct
dc_stream_state *stream,
*frl_link_settings = stream->link->frl_verified_link_cap;
return;
}
+ if (stream->link->frl_flags.force_frl_dsc) {
+ *frl_link_settings = stream->link->frl_verified_link_cap;
+ return;
+ }
if (stream->link->local_sink)
if
(stream->link->local_sink->edid_caps.panel_patch.hdmi_spe_handling) {
@@ -1126,6 +1163,7 @@ void hdmi_frl_decide_link_settings(struct dc_stream_state
*stream,
} while (!success);
*frl_link_settings = temp_settings;
+ update_borrow_mode_from_dsc_padding(dsc_padding_params,
&stream->timing, frl_link_settings);
}
void hdmi_frl_write_read_request_enable(struct ddc_service *ddc_service)
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
index d72574db1f07..78fd8d262de3 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
@@ -189,7 +189,13 @@ void optc3_set_dsc_config(struct timing_generator *optc,
struct optc *optc1 = DCN10TG_FROM_TG(optc);
optc2_set_dsc_config(optc, dsc_mode, dsc_bytes_per_pixel,
dsc_slice_width);
- REG_UPDATE(OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, 0);
+
+ if (dsc_mode != OPTC_DSC_DISABLED
+ && optc1->signal == SIGNAL_TYPE_HDMI_FRL) {
+ REG_UPDATE(OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, 1);
+ } else {
+ REG_UPDATE(OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, 0);
+ }
}
void optc3_set_odm_bypass(struct timing_generator *optc,
@@ -314,6 +320,27 @@ bool optc3_get_pipe_update_pending(struct timing_generator
*optc)
return (flip_pending == 1 || dc_update_pending == 1);
}
+void optc3_set_vstartup_dsc_frl(struct timing_generator *optc)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ unsigned int vblank_end = 0;
+ unsigned int vstartup_start = 0;
+
+ REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_END, &vblank_end);
+ REG_GET(OTG_VSTARTUP_PARAM, VSTARTUP_START, &vstartup_start);
+
+ /* In FRL+DSC mode the VSYNC is generated in OTG at start of HBALNK
+ * before frame start (VCOUNT=0 and HCOUNT=0). We need to program
+ * VSTARTUP at least one line before frame start to ensure the VSYNC
+ * will be generated in VRR mode. We need to program
+ * VSTARTUP_START >= V_BLANK_END + 1.
+ * When fullscreen = false,
+ * global_sync will restore VSTARTUP_START to normal value
+ */
+ if (vblank_end >= vstartup_start)
+ REG_SET(OTG_VSTARTUP_PARAM, 0, VSTARTUP_START,
+ vblank_end+1);
+}
/**
* optc3_set_timing_double_buffer() - DRR double buffering control
*
@@ -409,6 +436,7 @@ static const struct timing_generator_funcs dcn30_tg_funcs =
{
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc3_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
index 16c5610b49ac..8a88867f4361 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
@@ -349,6 +349,7 @@ void optc3_triplebuffer_lock(struct timing_generator *optc);
void optc3_program_blank_color(struct timing_generator *optc,
const struct tg_color *blank_color);
+void optc3_set_vstartup_dsc_frl(struct timing_generator *optc);
void optc3_set_vtotal_change_limit(struct timing_generator *optc,
uint32_t limit);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
index 98aaa22ce81c..bbf703777f72 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
@@ -500,6 +500,7 @@ static const struct timing_generator_funcs dcn31_tg_funcs =
{
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc3_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
index a7cf34937b2f..4d4b517575e2 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
@@ -244,6 +244,7 @@ static const struct timing_generator_funcs dcn314_tg_funcs
= {
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc3_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
index 60e546b69a05..99258b2fb14e 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
@@ -354,6 +354,7 @@ static const struct timing_generator_funcs dcn32_tg_funcs =
{
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc3_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
index a880e4a6d165..f6183c2e78e4 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
@@ -595,6 +595,7 @@ static const struct timing_generator_funcs dcn35_tg_funcs =
{
.set_h_timing_div_manual_mode =
optc32_set_h_timing_div_manual_mode,
.set_out_mux = optc3_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
index a6d76f451cf8..581517c9cec4 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
@@ -521,6 +521,7 @@ static const struct timing_generator_funcs dcn401_tg_funcs
= {
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc401_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
b/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
index ed66a2bbb8ae..f5280bc3c7ec 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
@@ -250,6 +250,7 @@ static struct timing_generator_funcs dcn42_tg_funcs = {
.wait_otg_disable = optc35_wait_otg_disable,
.set_out_mux = optc401_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
+ .set_vstartup_dsc_frl = optc3_set_vstartup_dsc_frl,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = optc2_set_gsl_source_select,
--
2.54.0