mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
drm/amd/display: Tie FRL support into amdgpu_dm
Tie FRL support into amdgpu_dm, including the FRL status polling workqueue. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
952df08d5b
commit
5c9b8b27a8
|
|
@ -1952,6 +1952,40 @@ static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hdmi_frl_status_polling_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct amdgpu_display_manager *dm =
|
||||||
|
container_of(to_delayed_work(work), struct amdgpu_display_manager,
|
||||||
|
hdmi_frl_status_polling_work);
|
||||||
|
struct dc *dc = dm->dc;
|
||||||
|
struct dc_link *dc_link;
|
||||||
|
bool link_update = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_LINKS; i++) {
|
||||||
|
dc_link = dc->links[i];
|
||||||
|
|
||||||
|
if (!dc_link || !dc_link->local_sink)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!dc_is_hdmi_signal(dc_link->connector_signal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
link_update = dc_link_frl_poll_status_flag(dc_link);
|
||||||
|
if (link_update) {
|
||||||
|
mutex_lock(&dm->dc_lock);
|
||||||
|
dc_link_detect(dc_link, DETECT_REASON_RETRAIN);
|
||||||
|
mutex_unlock(&dm->dc_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_delayed_work(dm->hdmi_frl_status_polling_wq,
|
||||||
|
&dm->hdmi_frl_status_polling_work,
|
||||||
|
msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms));
|
||||||
|
}
|
||||||
|
|
||||||
static int amdgpu_dm_init(struct amdgpu_device *adev)
|
static int amdgpu_dm_init(struct amdgpu_device *adev)
|
||||||
{
|
{
|
||||||
struct dc_init_data init_data;
|
struct dc_init_data init_data;
|
||||||
|
|
@ -2223,6 +2257,14 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
|
||||||
|
|
||||||
dc_init_callbacks(adev->dm.dc, &init_params);
|
dc_init_callbacks(adev->dm.dc, &init_params);
|
||||||
}
|
}
|
||||||
|
if (adev->dm.dc->caps.max_links > 0) {
|
||||||
|
adev->dm.hdmi_frl_status_polling_wq =
|
||||||
|
create_singlethread_workqueue("hdmi_frl_status_polling_workqueue");
|
||||||
|
if (!adev->dm.hdmi_frl_status_polling_wq)
|
||||||
|
drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n");
|
||||||
|
adev->dm.hdmi_frl_status_polling_delay_ms = 200;
|
||||||
|
INIT_DELAYED_WORK(&adev->dm.hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
|
||||||
|
}
|
||||||
if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
|
if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
|
||||||
init_completion(&adev->dm.dmub_aux_transfer_done);
|
init_completion(&adev->dm.dmub_aux_transfer_done);
|
||||||
adev->dm.dmub_notify = kzalloc_obj(struct dmub_notification);
|
adev->dm.dmub_notify = kzalloc_obj(struct dmub_notification);
|
||||||
|
|
@ -6972,7 +7014,8 @@ static void fill_stream_properties_from_drm_display_mode(
|
||||||
timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
|
timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
|
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||||
|
stream->signal == SIGNAL_TYPE_HDMI_FRL) {
|
||||||
err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
|
err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
|
||||||
(struct drm_connector *)connector,
|
(struct drm_connector *)connector,
|
||||||
mode_in);
|
mode_in);
|
||||||
|
|
@ -7619,7 +7662,8 @@ create_stream_for_sink(struct drm_connector *connector,
|
||||||
|
|
||||||
update_stream_signal(stream, sink);
|
update_stream_signal(stream, sink);
|
||||||
|
|
||||||
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
|
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||||
|
stream->signal == SIGNAL_TYPE_HDMI_FRL)
|
||||||
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
|
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
|
||||||
|
|
||||||
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
|
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
|
||||||
|
|
@ -8322,6 +8366,7 @@ create_validate_stream_for_sink(struct drm_connector *connector,
|
||||||
|
|
||||||
if (aconnector &&
|
if (aconnector &&
|
||||||
(aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
(aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||||
|
aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL ||
|
||||||
aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
|
aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
|
||||||
bpc_limit = 8;
|
bpc_limit = 8;
|
||||||
|
|
||||||
|
|
@ -10889,6 +10934,25 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
|
||||||
dc_exit_ips_for_hw_access(dm->dc);
|
dc_exit_ips_for_hw_access(dm->dc);
|
||||||
WARN_ON(!dc_commit_streams(dm->dc, ¶ms));
|
WARN_ON(!dc_commit_streams(dm->dc, ¶ms));
|
||||||
|
|
||||||
|
bool frl_stream_found = false;
|
||||||
|
|
||||||
|
for (i = 0; i < params.stream_count; i++) {
|
||||||
|
struct dc_stream_state *stream = params.streams[i];
|
||||||
|
|
||||||
|
if (stream->signal == SIGNAL_TYPE_HDMI_FRL) {
|
||||||
|
frl_stream_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (frl_stream_found) {
|
||||||
|
if (queue_delayed_work(dm->hdmi_frl_status_polling_wq,
|
||||||
|
&dm->hdmi_frl_status_polling_work,
|
||||||
|
msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms)))
|
||||||
|
drm_dbg_kms(dev, "200ms frl status polling starts ...\n");
|
||||||
|
} else {
|
||||||
|
if (cancel_delayed_work_sync(&dm->hdmi_frl_status_polling_work))
|
||||||
|
drm_dbg_kms(dev, "200ms frl status polling stops ...\n");
|
||||||
|
}
|
||||||
/* Allow idle optimization when vblank count is 0 for display off */
|
/* Allow idle optimization when vblank count is 0 for display off */
|
||||||
if ((dm->active_vblank_irq_count == 0) && amdgpu_dm_is_headless(dm->adev))
|
if ((dm->active_vblank_irq_count == 0) && amdgpu_dm_is_headless(dm->adev))
|
||||||
dc_allow_idle_optimizations(dm->dc, true);
|
dc_allow_idle_optimizations(dm->dc, true);
|
||||||
|
|
|
||||||
|
|
@ -704,6 +704,14 @@ struct amdgpu_display_manager {
|
||||||
struct completion replied;
|
struct completion replied;
|
||||||
char reply_data[0x40]; // Cannot include dmub_cmd here
|
char reply_data[0x40]; // Cannot include dmub_cmd here
|
||||||
} fused_io[8];
|
} fused_io[8];
|
||||||
|
/**
|
||||||
|
* @hdmi_frl_status_polling_work:
|
||||||
|
*
|
||||||
|
* workqueue for 200ms frl status polling
|
||||||
|
*/
|
||||||
|
struct workqueue_struct *hdmi_frl_status_polling_wq;
|
||||||
|
struct delayed_work hdmi_frl_status_polling_work;
|
||||||
|
unsigned int hdmi_frl_status_polling_delay_ms;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dm_boot_time_crc_info:
|
* @dm_boot_time_crc_info:
|
||||||
|
|
@ -850,6 +858,8 @@ struct amdgpu_dm_connector {
|
||||||
bool disallow_edp_enter_psr;
|
bool disallow_edp_enter_psr;
|
||||||
bool disallow_edp_enter_replay;
|
bool disallow_edp_enter_replay;
|
||||||
|
|
||||||
|
union dwnstream_portxcaps mst_downstream_port_caps;
|
||||||
|
|
||||||
/* Record progress status of mst*/
|
/* Record progress status of mst*/
|
||||||
uint8_t mst_status;
|
uint8_t mst_status;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -581,6 +581,8 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
|
||||||
link->dp.mst_enabled = config->mst_enabled;
|
link->dp.mst_enabled = config->mst_enabled;
|
||||||
link->dp.dp2_enabled = config->dp2_enabled;
|
link->dp.dp2_enabled = config->dp2_enabled;
|
||||||
link->dp.usb4_enabled = config->usb4_enabled;
|
link->dp.usb4_enabled = config->usb4_enabled;
|
||||||
|
if (aconnector->dc_sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)
|
||||||
|
link->hdmi.frl_enabled = config->frl_enabled;
|
||||||
display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
|
display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
|
||||||
link->adjust.auth_delay = 2;
|
link->adjust.auth_delay = 2;
|
||||||
link->adjust.retry_limit = MAX_NUM_OF_ATTEMPTS;
|
link->adjust.retry_limit = MAX_NUM_OF_ATTEMPTS;
|
||||||
|
|
|
||||||
|
|
@ -1071,9 +1071,32 @@ dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_conn
|
||||||
return edid;
|
return edid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
|
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->scdc_present = hdmi->scdc.supported;
|
||||||
|
edid_caps->max_frl_rate = get_max_frl_rate(hdmi->max_lanes, hdmi->max_frl_rate_per_lane);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum dc_edid_status dm_helpers_read_local_edid(
|
enum dc_edid_status dm_helpers_read_local_edid(
|
||||||
|
|
|
||||||
|
|
@ -1174,6 +1174,77 @@ static int try_disable_dsc(struct drm_atomic_commit *state,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
|
||||||
|
uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps)
|
||||||
|
{
|
||||||
|
unsigned int max_conv_bw_in_kbps = 0;
|
||||||
|
unsigned int max_sink_bw_in_kbps = 0;
|
||||||
|
unsigned int dsc_max_sink_bw_in_kbps = 0;
|
||||||
|
|
||||||
|
if (aconnector->dc_link->dc->caps.dp_hdmi21_pcon_support &&
|
||||||
|
aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE == DOWN_STREAM_DETAILED_HDMI) {
|
||||||
|
max_conv_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(
|
||||||
|
aconnector->dc_link->dc,
|
||||||
|
aconnector->mst_downstream_port_caps.bytes.byte2.bits.MAX_ENCODED_LINK_BW_SUPPORT);
|
||||||
|
if (aconnector->dc_sink->edid_caps.max_frl_rate && max_conv_bw_in_kbps) {
|
||||||
|
max_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(
|
||||||
|
aconnector->dc_link->dc,
|
||||||
|
aconnector->dc_sink->edid_caps.max_frl_rate);
|
||||||
|
dsc_max_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(
|
||||||
|
aconnector->dc_link->dc,
|
||||||
|
aconnector->dc_sink->edid_caps.frl_dsc_max_frl_rate);
|
||||||
|
|
||||||
|
*bw_in_kbps = min(max_conv_bw_in_kbps, max_sink_bw_in_kbps);
|
||||||
|
*dsc_bw_in_kbps = min(*bw_in_kbps, dsc_max_sink_bw_in_kbps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *bw_in_kbps > 0; // Frl endpoint is detected
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build_frl_mst_dsc_params(struct amdgpu_dm_connector *aconnector,
|
||||||
|
struct dc_stream_state *stream,
|
||||||
|
struct dc_dsc_policy *dsc_policy,
|
||||||
|
struct dsc_mst_fairness_params *params,
|
||||||
|
uint32_t frl_conv_dsc_bw_in_kbps)
|
||||||
|
{
|
||||||
|
uint32_t min_bpp_x16, max_bpp_x16;
|
||||||
|
struct dc_dsc_config_options dsc_options = {0};
|
||||||
|
|
||||||
|
min_bpp_x16 = dsc_policy->min_target_bpp * 16;
|
||||||
|
max_bpp_x16 = dsc_policy->max_target_bpp * 16;
|
||||||
|
|
||||||
|
dc_dsc_get_default_config_option(stream->sink->ctx->dc, &dsc_options);
|
||||||
|
dsc_options.max_target_bpp_limit_override_x16 =
|
||||||
|
stream->sink->edid_caps.panel_patch.max_dsc_target_bpp_limit * 16;
|
||||||
|
|
||||||
|
if (dc_dsc_compute_config(
|
||||||
|
stream->sink->ctx->dc->res_pool->dscs[0],
|
||||||
|
&stream->sink->dsc_caps.dsc_dec_caps,
|
||||||
|
&dsc_options,
|
||||||
|
frl_conv_dsc_bw_in_kbps,
|
||||||
|
&stream->timing,
|
||||||
|
dc_link_get_highest_encoding_format(aconnector->dc_link),
|
||||||
|
&stream->timing.dsc_cfg)) {
|
||||||
|
// The timing can enable dsc
|
||||||
|
if (stream->sink->dsc_caps.dsc_dec_caps.is_vic_all_bpp && min_bpp_x16 <= stream->timing.dsc_cfg.bits_per_pixel) {
|
||||||
|
// with all supported bpp within the range limit
|
||||||
|
params->bw_range.max_target_bpp_x16 = min(stream->timing.dsc_cfg.bits_per_pixel, dsc_policy->max_target_bpp * 16);
|
||||||
|
params->bw_range.min_target_bpp_x16 = min_bpp_x16;
|
||||||
|
params->bw_range.max_kbps = (params->bw_range.max_target_bpp_x16 * stream->timing.pix_clk_100hz + 159) / 160;
|
||||||
|
params->bw_range.min_kbps = (params->bw_range.min_target_bpp_x16 * stream->timing.pix_clk_100hz + 159) / 160;
|
||||||
|
} else if (!stream->sink->dsc_caps.dsc_dec_caps.is_vic_all_bpp &&
|
||||||
|
min_bpp_x16 <= stream->timing.dsc_cfg.bits_per_pixel &&
|
||||||
|
max_bpp_x16 >= stream->timing.dsc_cfg.bits_per_pixel) {
|
||||||
|
// with selected bpp only within the range limit
|
||||||
|
params->bw_range.max_target_bpp_x16 = stream->timing.dsc_cfg.bits_per_pixel;
|
||||||
|
params->bw_range.max_kbps = (params->bw_range.max_target_bpp_x16 * stream->timing.pix_clk_100hz + 159) / 160;
|
||||||
|
params->bw_range.min_target_bpp_x16 = params->bw_range.max_target_bpp_x16;
|
||||||
|
params->bw_range.min_kbps = params->bw_range.max_kbps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
|
static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -1199,6 +1270,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
|
||||||
bool debugfs_overwrite = false;
|
bool debugfs_overwrite = false;
|
||||||
uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
|
uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
|
||||||
struct drm_connector_state *new_conn_state;
|
struct drm_connector_state *new_conn_state;
|
||||||
|
bool is_frl_endpoint_present;
|
||||||
|
uint32_t frl_conv_bw_in_kbps, frl_conv_dsc_bw_in_kbps;
|
||||||
|
|
||||||
memset(params, 0, sizeof(params));
|
memset(params, 0, sizeof(params));
|
||||||
|
|
||||||
|
|
@ -1244,6 +1317,12 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
|
||||||
params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel;
|
params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel;
|
||||||
params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported;
|
params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported;
|
||||||
dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
|
dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
|
||||||
|
is_frl_endpoint_present = get_conv_frl_bw(aconnector, &frl_conv_bw_in_kbps, &frl_conv_dsc_bw_in_kbps);
|
||||||
|
if (stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported &&
|
||||||
|
is_frl_endpoint_present &&
|
||||||
|
frl_conv_dsc_bw_in_kbps &&
|
||||||
|
stream->sink->dsc_caps.dsc_dec_caps.is_frl)
|
||||||
|
build_frl_mst_dsc_params(aconnector, stream, &dsc_policy, ¶ms[count], frl_conv_dsc_bw_in_kbps);
|
||||||
if (!dc_dsc_compute_bandwidth_range(
|
if (!dc_dsc_compute_bandwidth_range(
|
||||||
stream->sink->ctx->dc->res_pool->dscs[0],
|
stream->sink->ctx->dc->res_pool->dscs[0],
|
||||||
stream->sink->ctx->dc->debug.dsc_min_slice_height_override,
|
stream->sink->ctx->dc->debug.dsc_min_slice_height_override,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user