aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.19.8/1140-drm-amd-display-Perform-plane-updates-only-when-need.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/1140-drm-amd-display-Perform-plane-updates-only-when-need.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.19.8/1140-drm-amd-display-Perform-plane-updates-only-when-need.patch296
1 files changed, 296 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/1140-drm-amd-display-Perform-plane-updates-only-when-need.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/1140-drm-amd-display-Perform-plane-updates-only-when-need.patch
new file mode 100644
index 00000000..9dbb41c2
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/1140-drm-amd-display-Perform-plane-updates-only-when-need.patch
@@ -0,0 +1,296 @@
+From 680e231f11bf8bb768eeecfa0b4a10baad1ab788 Mon Sep 17 00:00:00 2001
+From: David Francis <David.Francis@amd.com>
+Date: Wed, 19 Dec 2018 10:45:16 -0500
+Subject: [PATCH 1140/2940] drm/amd/display: Perform plane updates only when
+ needed
+
+[Why]
+Our old logic: if pageflip, update freesync and plane address.
+Otherwise, update everything.
+This over-updated on non-pageflip cases, and it failed to
+update if pageflip and non-pageflip changes occurred on
+the same commit
+
+[How]
+Update flip_addrs on pageflips.
+Update scaling_info when it changes.
+Update color fields on color changes.
+Updates plane_info always because we don't have a good way of
+knowing when it needs to be updated.
+
+Unfortunately, this means that every stream commit involves two
+calls into DC. In particular, on pageflips there is a second,
+pointless update that changes nothing but costs several
+microseconds (about a 50% increase in time taken). The update is
+fast, but there are comparisons and some useless programming.
+
+Leave TODOs indicating dissatisfaction.
+
+Signed-off-by: David Francis <David.Francis@amd.com>
+Reviewed-by: Harry Wentland <Harry.Wentland@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>
+Signed-off-by: Chaudhary Amit Kumar <Chaudharyamit.Kumar@amd.com>
+---
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 191 ++++++------------
+ 1 file changed, 62 insertions(+), 129 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 ea948755ced8..0c18b1e89b5d 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -4649,105 +4649,6 @@ static void update_freesync_state_on_stream(
+ vrr_params.adjust.v_total_max);
+ }
+
+-/*
+- * TODO this whole function needs to go
+- *
+- * dc_surface_update is needlessly complex. See if we can just replace this
+- * with a dc_plane_state and follow the atomic model a bit more closely here.
+- */
+-static bool commit_planes_to_stream(
+- struct amdgpu_display_manager *dm,
+- struct dc *dc,
+- struct dc_plane_state **plane_states,
+- uint8_t new_plane_count,
+- struct dm_crtc_state *dm_new_crtc_state,
+- struct dm_crtc_state *dm_old_crtc_state,
+- struct dc_state *state)
+-{
+- /* no need to dynamically allocate this. it's pretty small */
+- struct dc_surface_update updates[MAX_SURFACES];
+- struct dc_flip_addrs *flip_addr;
+- struct dc_plane_info *plane_info;
+- struct dc_scaling_info *scaling_info;
+- int i;
+- struct dc_stream_state *dc_stream = dm_new_crtc_state->stream;
+- struct dc_stream_update *stream_update =
+- kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL);
+- unsigned int abm_level;
+-
+- if (!stream_update) {
+- BREAK_TO_DEBUGGER();
+- return false;
+- }
+-
+- flip_addr = kcalloc(MAX_SURFACES, sizeof(struct dc_flip_addrs),
+- GFP_KERNEL);
+- plane_info = kcalloc(MAX_SURFACES, sizeof(struct dc_plane_info),
+- GFP_KERNEL);
+- scaling_info = kcalloc(MAX_SURFACES, sizeof(struct dc_scaling_info),
+- GFP_KERNEL);
+-
+- if (!flip_addr || !plane_info || !scaling_info) {
+- kfree(flip_addr);
+- kfree(plane_info);
+- kfree(scaling_info);
+- kfree(stream_update);
+- return false;
+- }
+-
+- memset(updates, 0, sizeof(updates));
+-
+- stream_update->src = dc_stream->src;
+- stream_update->dst = dc_stream->dst;
+- stream_update->out_transfer_func = dc_stream->out_transfer_func;
+-
+- if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) {
+- abm_level = dm_new_crtc_state->abm_level;
+- stream_update->abm_level = &abm_level;
+- }
+-
+- for (i = 0; i < new_plane_count; i++) {
+- updates[i].surface = plane_states[i];
+- updates[i].gamma =
+- (struct dc_gamma *)plane_states[i]->gamma_correction;
+- updates[i].in_transfer_func = plane_states[i]->in_transfer_func;
+- flip_addr[i].address = plane_states[i]->address;
+- flip_addr[i].flip_immediate = plane_states[i]->flip_immediate;
+- plane_info[i].color_space = plane_states[i]->color_space;
+- plane_info[i].format = plane_states[i]->format;
+- plane_info[i].plane_size = plane_states[i]->plane_size;
+- plane_info[i].rotation = plane_states[i]->rotation;
+- plane_info[i].horizontal_mirror = plane_states[i]->horizontal_mirror;
+- plane_info[i].stereo_format = plane_states[i]->stereo_format;
+- plane_info[i].tiling_info = plane_states[i]->tiling_info;
+- plane_info[i].visible = plane_states[i]->visible;
+- plane_info[i].per_pixel_alpha = plane_states[i]->per_pixel_alpha;
+- plane_info[i].dcc = plane_states[i]->dcc;
+- scaling_info[i].scaling_quality = plane_states[i]->scaling_quality;
+- scaling_info[i].src_rect = plane_states[i]->src_rect;
+- scaling_info[i].dst_rect = plane_states[i]->dst_rect;
+- scaling_info[i].clip_rect = plane_states[i]->clip_rect;
+-
+- updates[i].flip_addr = &flip_addr[i];
+- updates[i].plane_info = &plane_info[i];
+- updates[i].scaling_info = &scaling_info[i];
+- }
+-
+- mutex_lock(&dm->dc_lock);
+- dc_commit_updates_for_stream(
+- dc,
+- updates,
+- new_plane_count,
+- dc_stream, stream_update, state);
+- mutex_unlock(&dm->dc_lock);
+-
+- kfree(flip_addr);
+- kfree(plane_info);
+- kfree(scaling_info);
+- kfree(stream_update);
+- return true;
+-}
+-
+ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ struct dc_state *dc_state,
+ struct drm_device *dev,
+@@ -4759,7 +4660,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ uint64_t timestamp_ns;
+ struct drm_plane *plane;
+ struct drm_plane_state *old_plane_state, *new_plane_state;
+- struct dc_plane_state *plane_states_constructed[MAX_SURFACES];
+ struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
+ struct drm_crtc_state *new_pcrtc_state =
+ drm_atomic_get_new_crtc_state(state, pcrtc);
+@@ -4779,9 +4679,17 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ struct dc_stream_update stream_update;
+ } *flip;
+
++ struct {
++ struct dc_surface_update surface_updates[MAX_SURFACES];
++ struct dc_plane_info plane_infos[MAX_SURFACES];
++ struct dc_scaling_info scaling_infos[MAX_SURFACES];
++ struct dc_stream_update stream_update;
++ } *full;
++
+ flip = kzalloc(sizeof(*flip), GFP_KERNEL);
++ full = kzalloc(sizeof(*full), GFP_KERNEL);
+
+- if (!flip)
++ if (!flip || !full)
+ dm_error("Failed to allocate update bundles\n");
+
+ /* update planes when needed */
+@@ -4791,10 +4699,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ struct drm_framebuffer *fb = new_plane_state->fb;
+ struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
+ bool pflip_needed;
+- struct dc_plane_state *surface;
++ struct dc_plane_state *surface, *dc_plane;
+ struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
+
+-
+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+ handle_cursor_update(plane, old_plane_state);
+ continue;
+@@ -4809,14 +4716,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+
+ pflip_needed = !state->allow_modeset;
+
+- if (!pflip_needed || plane->type == DRM_PLANE_TYPE_OVERLAY) {
+- WARN_ON(!dm_new_plane_state->dc_state);
+-
+- plane_states_constructed[planes_count] = dm_new_plane_state->dc_state;
++ dc_plane = dm_new_plane_state->dc_state;
+
+- planes_count++;
+-
+- } else if (new_crtc_state->planes_changed) {
++ if (pflip_needed) {
+ /*
+ * Assume even ONE crtc with immediate flip means
+ * entire can't wait for VBLANK
+@@ -4900,8 +4802,42 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ flip_count += 1;
+ }
+
++ full->surface_updates[planes_count].surface = dc_plane;
++ if (new_pcrtc_state->color_mgmt_changed) {
++ full->surface_updates[planes_count].gamma = dc_plane->gamma_correction;
++ full->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func;
++ }
++
++
++ full->scaling_infos[planes_count].scaling_quality = dc_plane->scaling_quality;
++ full->scaling_infos[planes_count].src_rect = dc_plane->src_rect;
++ full->scaling_infos[planes_count].dst_rect = dc_plane->dst_rect;
++ full->scaling_infos[planes_count].clip_rect = dc_plane->clip_rect;
++ full->surface_updates[planes_count].scaling_info = &full->scaling_infos[planes_count];
++
++
++ full->plane_infos[planes_count].color_space = dc_plane->color_space;
++ full->plane_infos[planes_count].format = dc_plane->format;
++ full->plane_infos[planes_count].plane_size = dc_plane->plane_size;
++ full->plane_infos[planes_count].rotation = dc_plane->rotation;
++ full->plane_infos[planes_count].horizontal_mirror = dc_plane->horizontal_mirror;
++ full->plane_infos[planes_count].stereo_format = dc_plane->stereo_format;
++ full->plane_infos[planes_count].tiling_info = dc_plane->tiling_info;
++ full->plane_infos[planes_count].visible = dc_plane->visible;
++ full->plane_infos[planes_count].per_pixel_alpha = dc_plane->per_pixel_alpha;
++ full->plane_infos[planes_count].dcc = dc_plane->dcc;
++ full->surface_updates[planes_count].plane_info = &full->plane_infos[planes_count];
++
++ planes_count += 1;
++
+ }
+
++ /*
++ * TODO: For proper atomic behaviour, we should be calling into DC once with
++ * all the changes. However, DC refuses to do pageflips and non-pageflip
++ * changes in the same call. Change DC to respect atomic behaviour,
++ * hopefully eliminating dc_*_update structs in their entirety.
++ */
+ if (flip_count) {
+ target = (uint32_t)drm_crtc_vblank_count(pcrtc) + *wait_for_vblank;
+ /* Prepare wait for target vblank early - before the fence-waits */
+@@ -4956,29 +4892,26 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ }
+
+ if (planes_count) {
+- unsigned long flags;
+-
+- if (new_pcrtc_state->event) {
+-
+- drm_crtc_vblank_get(pcrtc);
+-
+- spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+- prepare_flip_isr(acrtc_attach);
+- spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
++ if (new_pcrtc_state->mode_changed) {
++ full->stream_update.src = acrtc_state->stream->src;
++ full->stream_update.dst = acrtc_state->stream->dst;
+ }
+
++ if (new_pcrtc_state->color_mgmt_changed)
++ full->stream_update.out_transfer_func = acrtc_state->stream->out_transfer_func;
++
+ acrtc_state->stream->abm_level = acrtc_state->abm_level;
++ if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
++ full->stream_update.abm_level = &acrtc_state->abm_level;
+
+- if (false == commit_planes_to_stream(dm,
+- dm->dc,
+- plane_states_constructed,
+- planes_count,
+- acrtc_state,
+- dm_old_crtc_state,
+- dc_state))
+- dm_error("%s: Failed to attach plane!\n", __func__);
+- } else {
+- /*TODO BUG Here should go disable planes on CRTC. */
++ mutex_lock(&dm->dc_lock);
++ dc_commit_updates_for_stream(dm->dc,
++ full->surface_updates,
++ planes_count,
++ acrtc_state->stream,
++ &full->stream_update,
++ dc_state);
++ mutex_unlock(&dm->dc_lock);
+ }
+ }
+
+--
+2.17.1
+