Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 84 additions & 11 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1983,6 +1983,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP2_0)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP2_0 = true;

if (amdgpu_dc_feature_mask & DC_FRL_MASK)
init_data.flags.enable_frl = true;

init_data.flags.seamless_boot_edp_requested = false;

if (amdgpu_device_seamless_boot_supported(adev)) {
Expand Down Expand Up @@ -6790,18 +6793,26 @@ static void fill_stream_properties_from_drm_display_mode(
timing_out->v_border_bottom = 0;
/* TODO: un-hardcode */
if (drm_mode_is_420_only(info, mode_in)
&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_HDMI_FRL)
&& aconnector
&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if (drm_mode_is_420_also(info, mode_in)
&& aconnector
&& aconnector->force_yuv420_output)
&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420
|| aconnector->force_yuv420_output))
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
&& aconnector
&& aconnector->force_yuv422_output)
&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422
|| aconnector->force_yuv422_output))
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
stream->signal == SIGNAL_TYPE_HDMI_FRL)
&& aconnector
&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR444)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
else
timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
Expand Down Expand Up @@ -7171,12 +7182,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);
}
}

Expand Down Expand Up @@ -7250,6 +7279,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 =
Expand Down Expand Up @@ -7288,8 +7321,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 &&
Expand All @@ -7302,11 +7345,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)
Expand Down Expand Up @@ -7345,7 +7418,7 @@ create_stream_for_sink(struct drm_connector *connector,
int preferred_refresh = 0;
enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
#if defined(CONFIG_DRM_AMD_DC_FP)
struct dsc_dec_dpcd_caps dsc_caps;
struct dsc_dec_dpcd_caps dsc_caps = {0};
#endif
struct dc_link *link = NULL;
struct dc_sink *sink = NULL;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,7 @@ struct amdgpu_dm_connector {
bool fake_enable;
bool force_yuv420_output;
bool force_yuv422_output;
uint8_t force_yuv_pixel_format;
struct dsc_preferred_settings dsc_settings;
union dp_downstream_port_present mst_downstream_port_present;
/* Cached display modes */
Expand Down Expand Up @@ -1098,7 +1099,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
void amdgpu_dm_update_connector_after_detect(
struct amdgpu_dm_connector *aconnector);

void populate_hdmi_info_from_connector(struct drm_hdmi_info *info,
void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *info,
struct dc_edid_caps *edid_caps);

extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;
Expand Down
28 changes: 28 additions & 0 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3141,6 +3141,7 @@ static int force_yuv420_output_set(void *data, u64 val)
struct amdgpu_dm_connector *connector = data;

connector->force_yuv420_output = (bool)val;
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR420;

return 0;
}
Expand All @@ -3160,6 +3161,31 @@ static int force_yuv420_output_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv420_output_fops, force_yuv420_output_get,
force_yuv420_output_set, "%llu\n");

static int force_yuv422_output_set(void *data, u64 val)
{
struct amdgpu_dm_connector *connector = data;

connector->force_yuv422_output = (bool)val;
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR422;

return 0;
}

DEFINE_DEBUGFS_ATTRIBUTE(force_yuv422_output_fops, NULL,
force_yuv422_output_set, "%llu\n");

static int force_yuv444_output_set(void *data, u64 val)
{
struct amdgpu_dm_connector *connector = data;

connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR444;

return 0;
}

DEFINE_DEBUGFS_ATTRIBUTE(force_yuv444_output_fops, NULL,
force_yuv444_output_set, "%llu\n");

/*
* Read Replay state
*/
Expand Down Expand Up @@ -3500,6 +3526,8 @@ static const struct {
const struct file_operations *fops;
} connector_debugfs_entries[] = {
{"force_yuv420_output", &force_yuv420_output_fops},
{"force_yuv422_output", &force_yuv422_output_fops},
{"force_yuv444_output", &force_yuv444_output_fops},
{"trigger_hotplug", &trigger_hotplug_debugfs_fops},
{"internal_display", &internal_display_fops},
{"odm_combine_segments", &odm_combine_segments_fops}
Expand Down
74 changes: 71 additions & 3 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
populate_hdmi_info_from_connector(&connector->display_info.hdmi, edid_caps);
if (edid_caps->edid_hdmi) {
populate_hdmi_info_from_connector(link->dc->config.enable_frl, &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);

Expand Down Expand Up @@ -1071,9 +1078,70 @@ dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_conn
return edid;
}

void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
static uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane)
{
uint8_t max_frl_rate;

if ((max_lanes == 3) && (max_rate_per_lane == 3))
max_frl_rate = 1;
else if ((max_lanes == 3) && (max_rate_per_lane == 6))
max_frl_rate = 2;
else if ((max_lanes == 4) && (max_rate_per_lane == 6))
max_frl_rate = 3;
else if ((max_lanes == 4) && (max_rate_per_lane == 8))
max_frl_rate = 4;
else if ((max_lanes == 4) && (max_rate_per_lane == 10))
max_frl_rate = 5;
else if ((max_lanes == 4) && (max_rate_per_lane == 12))
max_frl_rate = 6;
else
max_frl_rate = 0;

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(bool enable_frl, struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
{
edid_caps->scdc_present = hdmi->scdc.supported;
if (enable_frl) {
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(
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ static int dcn31_get_active_display_cnt_wa(
if (dc_is_dp_signal(stream->signal) && !stream->dpms_off)
display_count++;

/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}

for (i = 0; i < dc->link_count; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ static int dcn314_get_active_display_cnt_wa(
if (dc_is_dp_signal(stream->signal) && !stream->dpms_off)
display_count++;

/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}

for (i = 0; i < dc->link_count; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ static int dcn315_get_active_display_cnt_wa(
stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
tmds_present = true;
/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}

for (i = 0; i < dc->link_count; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ static int dcn316_get_active_display_cnt_wa(
stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
tmds_present = true;
/* FRL can't be tracked by DIG enablement */
if (dc_is_hdmi_frl_signal(stream->signal))
display_count++;
}

for (i = 0; i < dc->link_count; i++) {
Expand Down
12 changes: 12 additions & 0 deletions drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,18 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
dto_params.ref_dtbclk_khz = ref_dtbclk_khz;

if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ||
dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;

if (pipe_ctx->stream_res.audio != NULL)
dto_params.req_audio_dtbclk_khz = 24000;
}

if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
dc_is_dvi_signal(pipe_ctx->stream->signal))
dto_params.is_hdmi = true;

dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
}
Expand Down
Loading