drm/amd/display: Enable PSR
authorRoman Li <Roman.Li@amd.com>
Fri, 20 Sep 2019 23:03:17 +0000 (19:03 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 25 Oct 2019 20:50:08 +0000 (16:50 -0400)
[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: Roman Li <Roman.Li@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index a0bad13..04c5bcc 100644 (file)
@@ -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,10 +6408,13 @@ 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() */
 
@@ -7752,3 +7790,92 @@ update:
                                                       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);
+}