aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1139-drm-amd-display-Call-into-DC-once-per-multiplane-fli.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1139-drm-amd-display-Call-into-DC-once-per-multiplane-fli.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1139-drm-amd-display-Call-into-DC-once-per-multiplane-fli.patch448
1 files changed, 448 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1139-drm-amd-display-Call-into-DC-once-per-multiplane-fli.patch b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1139-drm-amd-display-Call-into-DC-once-per-multiplane-fli.patch
new file mode 100644
index 00000000..282d11ba
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1139-drm-amd-display-Call-into-DC-once-per-multiplane-fli.patch
@@ -0,0 +1,448 @@
+From 13bcfc356164620d223a46d607adf1c5fd2cac4c Mon Sep 17 00:00:00 2001
+From: David Francis <David.Francis@amd.com>
+Date: Tue, 11 Dec 2018 15:17:15 -0500
+Subject: [PATCH 1139/2940] drm/amd/display: Call into DC once per multiplane
+ flip
+
+[Why]
+amdgpu_dm_commit_planes was performing multi-plane
+flips incorrectly:
+
+It waited for vblank once per flipped plane
+
+It prepared flip ISR and acquired the corresponding vblank ref
+once per plane, although it closed ISR and put the ref once
+per crtc
+
+It called into dc once per flipped plane, duplicating some work
+
+[How]
+Wait for vblank, get vblank ref, prepare flip ISR, and call into
+DC only once, and only if there is a pageflip
+
+Make freesync continue to update planes even if vrr information
+has already been changed
+
+Signed-off-by: David Francis <David.Francis@amd.com>
+Reviewed-by: Harry Wentland <Harry.Wentland@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 | 336 ++++++++----------
+ 1 file changed, 155 insertions(+), 181 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 83838469d074..ea948755ced8 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -4620,12 +4620,12 @@ static void update_freesync_state_on_stream(
+ TRANSFER_FUNC_UNKNOWN,
+ &vrr_infopacket);
+
+- new_crtc_state->freesync_timing_changed =
++ new_crtc_state->freesync_timing_changed |=
+ (memcmp(&new_crtc_state->vrr_params.adjust,
+ &vrr_params.adjust,
+ sizeof(vrr_params.adjust)) != 0);
+
+- new_crtc_state->freesync_vrr_info_changed =
++ new_crtc_state->freesync_vrr_info_changed |=
+ (memcmp(&new_crtc_state->vrr_infopacket,
+ &vrr_infopacket,
+ sizeof(vrr_infopacket)) != 0);
+@@ -4649,156 +4649,6 @@ static void update_freesync_state_on_stream(
+ vrr_params.adjust.v_total_max);
+ }
+
+-/*
+- * Executes flip
+- *
+- * Waits on all BO's fences and for proper vblank count
+- */
+-static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
+- struct drm_framebuffer *fb,
+- uint32_t target,
+- struct dc_state *state)
+-{
+- unsigned long flags;
+- uint64_t timestamp_ns;
+- uint32_t target_vblank;
+- int r, vpos, hpos;
+- struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+- struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
+- struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]);
+- struct amdgpu_device *adev = crtc->dev->dev_private;
+- bool async_flip = (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
+- struct dc_flip_addrs addr = { {0} };
+- /* TODO eliminate or rename surface_update */
+- struct dc_surface_update surface_updates[1] = { {0} };
+- struct dc_stream_update stream_update = {0};
+- struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
+- struct dc_stream_status *stream_status;
+- struct dc_plane_state *surface;
+- uint64_t tiling_flags, dcc_address;
+-
+-
+- /* Prepare wait for target vblank early - before the fence-waits */
+- target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
+- amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id);
+-
+- /*
+- * TODO This might fail and hence better not used, wait
+- * explicitly on fences instead
+- * and in general should be called for
+- * blocking commit to as per framework helpers
+- */
+- r = amdgpu_bo_reserve(abo, true);
+- if (unlikely(r != 0)) {
+- DRM_ERROR("failed to reserve buffer before flip\n");
+- WARN_ON(1);
+- }
+-
+- /* Wait for all fences on this FB */
+- WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false,
+- MAX_SCHEDULE_TIMEOUT) < 0);
+-
+- amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
+-
+- amdgpu_bo_unreserve(abo);
+-
+- /*
+- * Wait until we're out of the vertical blank period before the one
+- * targeted by the flip
+- */
+- while ((acrtc->enabled &&
+- (amdgpu_display_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id,
+- 0, &vpos, &hpos, NULL,
+- NULL, &crtc->hwmode)
+- & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
+- (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
+- (int)(target_vblank -
+- amdgpu_get_vblank_counter_kms(adev->ddev, acrtc->crtc_id)) > 0)) {
+- usleep_range(1000, 1100);
+- }
+-
+- /* Flip */
+- spin_lock_irqsave(&crtc->dev->event_lock, flags);
+-
+- WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
+- WARN_ON(!acrtc_state->stream);
+-
+- addr.address.grph.addr.low_part = lower_32_bits(afb->address);
+- addr.address.grph.addr.high_part = upper_32_bits(afb->address);
+-
+- dcc_address = get_dcc_address(afb->address, tiling_flags);
+- addr.address.grph.meta_addr.low_part = lower_32_bits(dcc_address);
+- addr.address.grph.meta_addr.high_part = upper_32_bits(dcc_address);
+-
+- addr.flip_immediate = async_flip;
+-
+- timestamp_ns = ktime_get_ns();
+- addr.flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
+-
+-
+- if (acrtc->base.state->event)
+- prepare_flip_isr(acrtc);
+-
+- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+-
+- stream_status = dc_stream_get_status(acrtc_state->stream);
+- if (!stream_status) {
+- DRM_ERROR("No stream status for CRTC: id=%d\n",
+- acrtc->crtc_id);
+- return;
+- }
+-
+- surface = stream_status->plane_states[0];
+- surface_updates->surface = surface;
+-
+- if (!surface) {
+- DRM_ERROR("No surface for CRTC: id=%d\n",
+- acrtc->crtc_id);
+- return;
+- }
+- surface_updates->flip_addr = &addr;
+-
+- if (acrtc_state->stream) {
+- update_freesync_state_on_stream(
+- &adev->dm,
+- acrtc_state,
+- acrtc_state->stream,
+- surface,
+- addr.flip_timestamp_in_us);
+-
+- if (acrtc_state->freesync_timing_changed)
+- stream_update.adjust =
+- &acrtc_state->stream->adjust;
+-
+- if (acrtc_state->freesync_vrr_info_changed)
+- stream_update.vrr_infopacket =
+- &acrtc_state->stream->vrr_infopacket;
+- }
+-
+- /* Update surface timing information. */
+- surface->time.time_elapsed_in_us[surface->time.index] =
+- addr.flip_timestamp_in_us - surface->time.prev_update_time_in_us;
+- surface->time.prev_update_time_in_us = addr.flip_timestamp_in_us;
+- surface->time.index++;
+- if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
+- surface->time.index = 0;
+-
+- mutex_lock(&adev->dm.dc_lock);
+-
+- dc_commit_updates_for_stream(adev->dm.dc,
+- surface_updates,
+- 1,
+- acrtc_state->stream,
+- &stream_update,
+- state);
+- mutex_unlock(&adev->dm.dc_lock);
+-
+- DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
+- __func__,
+- addr.address.grph.addr.high_part,
+- addr.address.grph.addr.low_part);
+-}
+-
+ /*
+ * TODO this whole function needs to go
+ *
+@@ -4905,10 +4755,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ struct drm_crtc *pcrtc,
+ bool *wait_for_vblank)
+ {
+- uint32_t i;
++ uint32_t i, r;
++ uint64_t timestamp_ns;
+ struct drm_plane *plane;
+ struct drm_plane_state *old_plane_state, *new_plane_state;
+- struct dc_stream_state *dc_stream_attach;
+ 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 =
+@@ -4916,17 +4766,35 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state);
+ struct dm_crtc_state *dm_old_crtc_state =
+ to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
+- int planes_count = 0;
++ int flip_count = 0, planes_count = 0, vpos, hpos;
+ unsigned long flags;
++ struct amdgpu_bo *abo;
++ uint64_t tiling_flags, dcc_address;
++ struct dc_stream_status *stream_status;
++ uint32_t target, target_vblank;
++
++ struct {
++ struct dc_surface_update surface_updates[MAX_SURFACES];
++ struct dc_flip_addrs flip_addrs[MAX_SURFACES];
++ struct dc_stream_update stream_update;
++ } *flip;
++
++ flip = kzalloc(sizeof(*flip), GFP_KERNEL);
++
++ if (!flip)
++ dm_error("Failed to allocate update bundles\n");
+
+ /* update planes when needed */
+ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+ struct drm_crtc *crtc = new_plane_state->crtc;
+ struct drm_crtc_state *new_crtc_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 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;
+@@ -4941,44 +4809,150 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+
+ pflip_needed = !state->allow_modeset;
+
+- spin_lock_irqsave(&crtc->dev->event_lock, flags);
+- if (acrtc_attach->pflip_status != AMDGPU_FLIP_NONE) {
+- DRM_ERROR("%s: acrtc %d, already busy\n",
+- __func__,
+- acrtc_attach->crtc_id);
+- /* In commit tail framework this cannot happen */
+- WARN_ON(1);
+- }
+- spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+-
+ 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_stream_attach = acrtc_state->stream;
+ planes_count++;
+
+ } else if (new_crtc_state->planes_changed) {
+- /* Assume even ONE crtc with immediate flip means
++ /*
++ * Assume even ONE crtc with immediate flip means
+ * entire can't wait for VBLANK
+ * TODO Check if it's correct
+ */
+- *wait_for_vblank =
+- new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC ?
+- false : true;
+-
+- /* TODO: Needs rework for multiplane flip */
+- if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+- drm_crtc_vblank_get(crtc);
+-
+- amdgpu_dm_do_flip(
+- crtc,
+- fb,
+- (uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank,
+- dc_state);
++ if (new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC)
++ *wait_for_vblank = false;
++
++ /*
++ * TODO This might fail and hence better not used, wait
++ * explicitly on fences instead
++ * and in general should be called for
++ * blocking commit to as per framework helpers
++ */
++ abo = gem_to_amdgpu_bo(fb->obj[0]);
++ r = amdgpu_bo_reserve(abo, true);
++ if (unlikely(r != 0)) {
++ DRM_ERROR("failed to reserve buffer before flip\n");
++ WARN_ON(1);
++ }
++
++ /* Wait for all fences on this FB */
++ WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false,
++ MAX_SCHEDULE_TIMEOUT) < 0);
++
++ amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
++
++ amdgpu_bo_unreserve(abo);
++
++ flip->flip_addrs[flip_count].address.grph.addr.low_part = lower_32_bits(afb->address);
++ flip->flip_addrs[flip_count].address.grph.addr.high_part = upper_32_bits(afb->address);
++
++ dcc_address = get_dcc_address(afb->address, tiling_flags);
++ flip->flip_addrs[flip_count].address.grph.meta_addr.low_part = lower_32_bits(dcc_address);
++ flip->flip_addrs[flip_count].address.grph.meta_addr.high_part = upper_32_bits(dcc_address);
++
++ flip->flip_addrs[flip_count].flip_immediate =
++ (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
++
++ timestamp_ns = ktime_get_ns();
++ flip->flip_addrs[flip_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
++ flip->surface_updates[flip_count].flip_addr = &flip->flip_addrs[flip_count];
++
++ stream_status = dc_stream_get_status(acrtc_state->stream);
++ if (!stream_status) {
++ DRM_ERROR("No stream status for CRTC: id=%d\n",
++ acrtc_attach->crtc_id);
++ continue;
++ }
++
++ surface = stream_status->plane_states[0];
++ flip->surface_updates[flip_count].surface = surface;
++ if (!flip->surface_updates[flip_count].surface) {
++ DRM_ERROR("No surface for CRTC: id=%d\n",
++ acrtc_attach->crtc_id);
++ continue;
++ }
++
++ if (acrtc_state->stream)
++ update_freesync_state_on_stream(
++ dm,
++ acrtc_state,
++ acrtc_state->stream,
++ surface,
++ flip->flip_addrs[flip_count].flip_timestamp_in_us);
++
++ /* Update surface timing information. */
++ surface->time.time_elapsed_in_us[surface->time.index] =
++ flip->flip_addrs[flip_count].flip_timestamp_in_us -
++ surface->time.prev_update_time_in_us;
++ surface->time.prev_update_time_in_us = flip->flip_addrs[flip_count].flip_timestamp_in_us;
++ surface->time.index++;
++ if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
++ surface->time.index = 0;
++
++ DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x\n",
++ __func__,
++ flip->flip_addrs[flip_count].address.grph.addr.high_part,
++ flip->flip_addrs[flip_count].address.grph.addr.low_part);
++
++ flip_count += 1;
++ }
++
++ }
++
++ if (flip_count) {
++ target = (uint32_t)drm_crtc_vblank_count(pcrtc) + *wait_for_vblank;
++ /* Prepare wait for target vblank early - before the fence-waits */
++ target_vblank = target - (uint32_t)drm_crtc_vblank_count(pcrtc) +
++ amdgpu_get_vblank_counter_kms(pcrtc->dev, acrtc_attach->crtc_id);
++
++ /*
++ * Wait until we're out of the vertical blank period before the one
++ * targeted by the flip
++ */
++ while ((acrtc_attach->enabled &&
++ (amdgpu_display_get_crtc_scanoutpos(dm->ddev, acrtc_attach->crtc_id,
++ 0, &vpos, &hpos, NULL,
++ NULL, &pcrtc->hwmode)
++ & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
++ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
++ (int)(target_vblank -
++ amdgpu_get_vblank_counter_kms(dm->ddev, acrtc_attach->crtc_id)) > 0)) {
++ usleep_range(1000, 1100);
++ }
++
++ if (acrtc_attach->base.state->event) {
++ drm_crtc_vblank_get(pcrtc);
++
++ spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
++
++ WARN_ON(acrtc_attach->pflip_status != AMDGPU_FLIP_NONE);
++ prepare_flip_isr(acrtc_attach);
++
++ spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
+ }
+
++ if (acrtc_state->stream) {
++
++ if (acrtc_state->freesync_timing_changed)
++ flip->stream_update.adjust =
++ &acrtc_state->stream->adjust;
++
++ if (acrtc_state->freesync_vrr_info_changed)
++ flip->stream_update.vrr_infopacket =
++ &acrtc_state->stream->vrr_infopacket;
++ }
++
++ mutex_lock(&dm->dc_lock);
++ dc_commit_updates_for_stream(dm->dc,
++ flip->surface_updates,
++ flip_count,
++ acrtc_state->stream,
++ &flip->stream_update,
++ dc_state);
++ mutex_unlock(&dm->dc_lock);
+ }
+
+ if (planes_count) {
+@@ -4993,7 +4967,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+ spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
+ }
+
+- dc_stream_attach->abm_level = acrtc_state->abm_level;
++ acrtc_state->stream->abm_level = acrtc_state->abm_level;
+
+ if (false == commit_planes_to_stream(dm,
+ dm->dc,
+--
+2.17.1
+