Commit 8c322309 authored by Roman Li's avatar Roman Li Committed by Alex Deucher

drm/amd/display: Enable PSR

[Why]
PSR (Panel Self-Refresh) is a power-saving feature for eDP panels.
The feature has support in DMCU (Display MicroController Unit).
DMCU/driver communication is implemented in DC.
DM can use existing DC PSR interface to use PSR feature.

[How]
- Read psr caps via dpcd
- Send vsc infoframe if panel supports psr
- Disable psr before h/w programming (FULL_UPDATE)
- Enable psr after h/w programming
- Disable psr for fb console
Signed-off-by: default avatarRoman Li <Roman.Li@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent e0d08a40
......@@ -147,6 +147,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
static void handle_cursor_update(struct drm_plane *plane,
struct drm_plane_state *old_plane_state);
static void amdgpu_dm_set_psr_caps(struct dc_link *link);
static bool amdgpu_dm_psr_enable(struct dc_stream_state *stream);
static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream);
static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream);
/*
* dm_vblank_get_counter
*
......@@ -2418,6 +2424,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
} else if (dc_link_detect(link, DETECT_REASON_BOOT)) {
amdgpu_dm_update_connector_after_detect(aconnector);
register_backlight_device(dm, link);
amdgpu_dm_set_psr_caps(link);
}
......@@ -3743,7 +3750,16 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
if (stream->link->psr_feature_enabled) {
struct dc *core_dc = stream->link->ctx->dc;
if (dc_is_dmcu_initialized(core_dc)) {
struct dmcu *dmcu = core_dc->res_pool->dmcu;
stream->psr_version = dmcu->dmcu_version.psr_version;
mod_build_vsc_infopacket(stream, &stream->vsc_infopacket);
}
}
finish:
dc_sink_release(sink);
......@@ -5821,6 +5837,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
uint32_t target_vblank, last_flip_vblank;
bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
bool pflip_present = false;
bool swizzle = true;
struct {
struct dc_surface_update surface_updates[MAX_SURFACES];
struct dc_plane_info plane_infos[MAX_SURFACES];
......@@ -5866,6 +5883,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
dc_plane = dm_new_plane_state->dc_state;
if (dc_plane && !dc_plane->tiling_info.gfx9.swizzle)
swizzle = false;
bundle->surface_updates[planes_count].surface = dc_plane;
if (new_pcrtc_state->color_mgmt_changed) {
bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction;
......@@ -6057,14 +6077,29 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
&acrtc_state->vrr_params.adjust);
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
}
mutex_lock(&dm->dc_lock);
if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
acrtc_state->stream->link->psr_allow_active)
amdgpu_dm_psr_disable(acrtc_state->stream);
dc_commit_updates_for_stream(dm->dc,
bundle->surface_updates,
planes_count,
acrtc_state->stream,
&bundle->stream_update,
dc_state);
if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
acrtc_state->stream->psr_version &&
!acrtc_state->stream->link->psr_feature_enabled)
amdgpu_dm_link_setup_psr(acrtc_state->stream);
else if ((acrtc_state->update_type == UPDATE_TYPE_FAST) &&
acrtc_state->stream->link->psr_feature_enabled &&
!acrtc_state->stream->link->psr_allow_active &&
swizzle) {
amdgpu_dm_psr_enable(acrtc_state->stream);
}
mutex_unlock(&dm->dc_lock);
}
......@@ -6373,11 +6408,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
crtc->hwmode = new_crtc_state->mode;
} else if (modereset_required(new_crtc_state)) {
DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
/* i.e. reset mode */
if (dm_old_crtc_state->stream)
if (dm_old_crtc_state->stream) {
if (dm_old_crtc_state->stream->link->psr_allow_active)
amdgpu_dm_psr_disable(dm_old_crtc_state->stream);
remove_stream(adev, acrtc, dm_old_crtc_state->stream);
}
}
} /* for_each_crtc_in_state() */
if (dc_state) {
......@@ -7752,3 +7790,92 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
freesync_capable);
}
static void amdgpu_dm_set_psr_caps(struct dc_link *link)
{
uint8_t dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE];
if (!(link->connector_signal & SIGNAL_TYPE_EDP))
return;
if (link->type == dc_connection_none)
return;
if (dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT,
dpcd_data, sizeof(dpcd_data))) {
link->psr_feature_enabled = dpcd_data[0] ? true:false;
DRM_INFO("PSR support:%d\n", link->psr_feature_enabled);
}
}
/*
* amdgpu_dm_link_setup_psr() - configure psr link
* @stream: stream state
*
* Return: true if success
*/
static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream)
{
struct dc_link *link = NULL;
struct psr_config psr_config = {0};
struct psr_context psr_context = {0};
struct dc *dc = NULL;
bool ret = false;
if (stream == NULL)
return false;
link = stream->link;
dc = link->ctx->dc;
psr_config.psr_version = dc->res_pool->dmcu->dmcu_version.psr_version;
if (psr_config.psr_version > 0) {
psr_config.psr_exit_link_training_required = 0x1;
psr_config.psr_frame_capture_indication_req = 0;
psr_config.psr_rfb_setup_time = 0x37;
psr_config.psr_sdp_transmit_line_num_deadline = 0x20;
psr_config.allow_smu_optimizations = 0x0;
ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context);
}
DRM_DEBUG_DRIVER("PSR link: %d\n", link->psr_feature_enabled);
return ret;
}
/*
* amdgpu_dm_psr_enable() - enable psr f/w
* @stream: stream state
*
* Return: true if success
*/
bool amdgpu_dm_psr_enable(struct dc_stream_state *stream)
{
struct dc_link *link = stream->link;
struct dc_static_screen_events triggers = {0};
DRM_DEBUG_DRIVER("Enabling psr...\n");
triggers.cursor_update = true;
triggers.overlay_update = true;
triggers.surface_update = true;
dc_stream_set_static_screen_events(link->ctx->dc,
&stream, 1,
&triggers);
return dc_link_set_psr_allow_active(link, true, false);
}
/*
* amdgpu_dm_psr_disable() - disable psr f/w
* @stream: stream state
*
* Return: true if success
*/
static bool amdgpu_dm_psr_disable(struct dc_stream_state *stream)
{
DRM_DEBUG_DRIVER("Disabling psr...\n");
return dc_link_set_psr_allow_active(stream->link, false, true);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment