diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1007-drm-amd-display-Refactor-atomic-check.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1007-drm-amd-display-Refactor-atomic-check.patch | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1007-drm-amd-display-Refactor-atomic-check.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1007-drm-amd-display-Refactor-atomic-check.patch new file mode 100644 index 00000000..96b6c2b3 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1007-drm-amd-display-Refactor-atomic-check.patch @@ -0,0 +1,666 @@ +From ad3d14ad6eff85578426d10db69eaf2fc56b1c81 Mon Sep 17 00:00:00 2001 +From: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com> +Date: Fri, 18 Aug 2017 10:52:20 -0400 +Subject: [PATCH 1007/4131] drm/amd/display: Refactor atomic check. + +Split into update crtcs and update plane functions. + +Change-Id: I57a739070861553de9b787f995e44a1da4e3c2d0 +Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com> +Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 550 ++++++++++++---------- + 1 file changed, 303 insertions(+), 247 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 4b817bf..edbf952 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -1789,12 +1789,6 @@ static bool modeset_required(struct drm_crtc_state *crtc_state, + struct dc_stream_state *new_stream, + struct dc_stream_state *old_stream) + { +- if (dc_is_stream_unchanged(new_stream, old_stream)) { +- crtc_state->mode_changed = false; +- DRM_DEBUG_KMS("Mode change not required, setting mode_changed to %d", +- crtc_state->mode_changed); +- } +- + if (!drm_atomic_crtc_needs_modeset(crtc_state)) + return false; + +@@ -4119,9 +4113,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + continue; + } + +- if (!fb || !crtc || pcrtc != crtc || !crtc->state->active || +- (!crtc->state->planes_changed && +- !pcrtc->state->color_mgmt_changed)) ++ if (!fb || !crtc || pcrtc != crtc || !crtc->state->active) + continue; + + pflip_needed = !state->allow_modeset; +@@ -4598,76 +4590,18 @@ static int do_aquire_global_lock( + return ret < 0 ? ret : 0; + } + +-int amdgpu_dm_atomic_check(struct drm_device *dev, +- struct drm_atomic_state *state) ++static int dm_update_crtcs_state( ++ struct dc *dc, ++ struct drm_atomic_state *state, ++ bool enable, ++ bool *lock_and_validation_needed) + { + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; +- struct drm_plane *plane; +- struct drm_plane_state *plane_state; +- int i, j; +- int ret; +- struct amdgpu_device *adev = dev->dev_private; +- struct dc *dc = adev->dm.dc; +- struct drm_connector *connector; +- struct drm_connector_state *conn_state; ++ int i; + struct dm_crtc_state *old_acrtc_state, *new_acrtc_state; + struct dm_atomic_state *dm_state = to_dm_atomic_state(state); +- bool pflip_needed = !state->allow_modeset; +- +- /* +- * This bool will be set for true for any modeset/reset +- * or plane update which implies non fast surface update. +- */ +- bool lock_and_validation_needed = false; +- +- ret = drm_atomic_helper_check_modeset(dev, state); +- +- if (ret) { +- DRM_ERROR("Atomic state validation failed with error :%d !\n", ret); +- return ret; +- } +- +- /* Remove exiting planes if they are disabled or their CRTC is updated */ +- for_each_crtc_in_state(state, crtc, crtc_state, i) { +- new_acrtc_state = to_dm_crtc_state(crtc_state); +- +- if (pflip_needed) +- continue; +- +- for_each_plane_in_state(state, plane, plane_state, j) { +- struct drm_crtc *plane_crtc = plane_state->crtc; +- struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); +- +- if (plane->type == DRM_PLANE_TYPE_CURSOR) +- continue; +- +- if (crtc != plane_crtc || !dm_plane_state->dc_state) +- continue; +- +- WARN_ON(!new_acrtc_state->stream); +- +- if (drm_atomic_plane_disabling(plane->state, plane_state) || +- drm_atomic_crtc_needs_modeset(crtc_state)) { +- if (!dc_remove_plane_from_context( +- dc, +- new_acrtc_state->stream, +- dm_plane_state->dc_state, +- dm_state->context)) { +- +- ret = EINVAL; +- goto fail; +- } +- +- } +- +- dc_plane_state_release(dm_plane_state->dc_state); +- dm_plane_state->dc_state = NULL; +- +- DRM_DEBUG_KMS("Disabling DRM plane: %d on DRM crtc %d\n", +- plane->base.id, crtc->base.id); +- } +- } ++ int ret = 0; + + /*TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set */ + /* update changed items */ +@@ -4677,12 +4611,52 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, + struct dc_stream_state *new_stream = NULL; + struct drm_connector_state *conn_state = NULL; + struct dm_connector_state *dm_conn_state = NULL; +- ++ + old_acrtc_state = to_dm_crtc_state(crtc->state); + new_acrtc_state = to_dm_crtc_state(crtc_state); + acrtc = to_amdgpu_crtc(crtc); + + aconnector = amdgpu_dm_find_first_crct_matching_connector(state, crtc, true); ++ ++ /* TODO This hack should go away */ ++ if (aconnector && aconnector->dc_sink) { ++ conn_state = drm_atomic_get_connector_state(state, ++ &aconnector->base); ++ ++ if (IS_ERR(conn_state)) { ++ ret = PTR_ERR_OR_ZERO(conn_state); ++ break; ++ } ++ ++ dm_conn_state = to_dm_connector_state(conn_state); ++ ++ new_stream = create_stream_for_sink(aconnector, ++ &crtc_state->mode, ++ dm_conn_state); ++ /* ++ * we can have no stream on ACTION_SET if a display ++ * was disconnected during S3, in this case it not and ++ * error, the OS will be updated after detection, and ++ * do the right thing on next atomic commit ++ */ ++ ++ if (!new_stream) { ++ DRM_DEBUG_KMS("%s: Failed to create new stream for crtc %d\n", ++ __func__, acrtc->base.base.id); ++ break; ++ } ++ } ++ ++ if (dc_is_stream_unchanged(new_stream, ++ old_acrtc_state->stream)) { ++ crtc_state->mode_changed = false; ++ DRM_DEBUG_KMS("Mode change not required, setting mode_changed to %d", ++ crtc_state->mode_changed); ++ } ++ ++ ++ if (!drm_atomic_crtc_needs_modeset(crtc_state)) ++ continue; + + DRM_DEBUG_KMS( + "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, " +@@ -4696,228 +4670,310 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, + crtc_state->active_changed, + crtc_state->connectors_changed); + +- if (modereset_required(crtc_state)) { +- +- /* i.e. reset mode */ +- if (new_acrtc_state->stream) { +- +- if (!dc_remove_stream_from_ctx( +- dc, +- dm_state->context, +- new_acrtc_state->stream)) { +- ret = -EINVAL; +- goto fail; +- } +- +- dc_stream_release(new_acrtc_state->stream); +- new_acrtc_state->stream = NULL; +- +- lock_and_validation_needed = true; +- } +- +- } else { +- +- if (aconnector) { +- conn_state = drm_atomic_get_connector_state(state, +- &aconnector->base); +- +- if (IS_ERR(conn_state)) { +- ret = PTR_ERR_OR_ZERO(conn_state); +- goto fail; +- } +- +- dm_conn_state = to_dm_connector_state(conn_state); +- +- new_stream = create_stream_for_sink(aconnector, +- &crtc_state->mode, +- dm_conn_state); +- +- /* +- * we can have no stream on ACTION_SET if a display +- * was disconnected during S3, in this case it not and +- * error, the OS will be updated after detection, and +- * do the right thing on next atomic commit +- */ +- +- if (!new_stream) { +- DRM_DEBUG_KMS("%s: Failed to create new stream for crtc %d\n", +- __func__, acrtc->base.base.id); +- break; +- } ++ /* Remove stream for any changed/disabled CRTC */ ++ if (!enable) { + ++ if (!old_acrtc_state->stream) ++ continue; + ++ DRM_DEBUG_KMS("Disabling DRM crtc: %d\n", ++ crtc->base.id); ++ /* i.e. reset mode */ ++ if (!dc_remove_stream_from_ctx( ++ dc, ++ dm_state->context, ++ old_acrtc_state->stream)) { ++ ret = -EINVAL; ++ break; + } + +- if (modeset_required(crtc_state, new_stream, +- old_acrtc_state->stream)) { ++ dc_stream_release(old_acrtc_state->stream); ++ new_acrtc_state->stream = NULL; + +- if (new_acrtc_state->stream) { ++ *lock_and_validation_needed = true; + +- if (!dc_remove_stream_from_ctx( +- dc, +- dm_state->context, +- new_acrtc_state->stream)) { +- ret = -EINVAL; +- goto fail; +- } ++ } else {/* Add stream for any updated/enabled CRTC */ + ++ if (modereset_required(crtc_state)) ++ continue; + +- dc_stream_release(new_acrtc_state->stream); +- } ++ if (modeset_required(crtc_state, new_stream, ++ old_acrtc_state->stream)) { ++ ++ WARN_ON(new_acrtc_state->stream); + + new_acrtc_state->stream = new_stream; ++ dc_stream_retain(new_stream); + ++ DRM_DEBUG_KMS("Enabling DRM crtc: %d\n", ++ crtc->base.id); ++ + if (!dc_add_stream_to_ctx( + dc, + dm_state->context, + new_acrtc_state->stream)) { + ret = -EINVAL; +- goto fail; ++ break; + } +- +- lock_and_validation_needed = true; +- } else { +- /* +- * The new stream is unused, so we release it +- */ +- if (new_stream) +- dc_stream_release(new_stream); +- ++ ++ *lock_and_validation_needed = true; + } + } + ++ /* Release extra reference */ ++ if (new_stream) ++ dc_stream_release(new_stream); ++ } + +- /* +- * Hack: Commit needs planes right now, specifically for gamma +- * TODO rework commit to check CRTC for gamma change +- */ +- if (crtc_state->color_mgmt_changed) { ++ return ret; ++} + +- ret = drm_atomic_add_affected_planes(state, crtc); +- if (ret) +- goto fail; +- } +- } ++static int dm_update_planes_state( ++ struct dc *dc, ++ struct drm_atomic_state *state, ++ bool enable, ++ bool *lock_and_validation_needed) ++{ ++ struct drm_crtc *new_plane_crtc, *old_plane_crtc; ++ struct drm_crtc_state *new_crtc_state; ++ struct drm_plane *plane; ++ struct drm_plane_state *old_plane_state, *new_plane_state; ++ struct dm_crtc_state *new_acrtc_state, *old_acrtc_state; ++ struct dm_atomic_state *dm_state = to_dm_atomic_state(state); ++ struct dm_plane_state *new_dm_plane_state, *old_dm_plane_state; ++ int i ; ++ /* TODO return page_flip_needed() function */ ++ bool pflip_needed = !state->allow_modeset; ++ int ret = 0; + +- /* Check scaling and undersacn changes*/ +- /*TODO Removed scaling changes validation due to inability to commit +- * new stream into context w\o causing full reset. Need to +- * decide how to handle. +- */ +- for_each_connector_in_state(state, connector, conn_state, i) { +- struct amdgpu_connector *aconnector = to_amdgpu_connector(connector); +- struct dm_connector_state *con_old_state = +- to_dm_connector_state(aconnector->base.state); +- struct dm_connector_state *con_new_state = +- to_dm_connector_state(conn_state); +- struct amdgpu_crtc *acrtc = to_amdgpu_crtc(con_new_state->base.crtc); ++ if (pflip_needed) ++ return ret; + +- /* Skip any modesets/resets */ +- if (!acrtc || drm_atomic_crtc_needs_modeset(acrtc->base.state)) +- continue; ++ /* Add new planes */ ++ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { ++ new_plane_crtc = new_plane_state->crtc; ++ old_plane_crtc = old_plane_state->crtc; ++ new_dm_plane_state = to_dm_plane_state(new_plane_state); ++ old_dm_plane_state = to_dm_plane_state(old_plane_state); + +- /* Skip any thing not scale or underscan changes */ +- if (!is_scaling_state_different(con_new_state, con_old_state)) +- continue; ++ /*TODO Implement atomic check for cursor plane */ ++ if (plane->type == DRM_PLANE_TYPE_CURSOR) ++ continue; + +- lock_and_validation_needed = true; +- } ++ /* Remove any changed/removed planes */ ++ if (!enable) { + +- /* Add new planes */ +- for_each_crtc_in_state(state, crtc, crtc_state, i) { +- new_acrtc_state = to_dm_crtc_state(crtc_state); ++ if (!old_plane_crtc) ++ continue; + +- if (pflip_needed) +- continue; ++ old_acrtc_state = to_dm_crtc_state( ++ drm_atomic_get_old_crtc_state( ++ state, ++ old_plane_crtc)); + +- for_each_plane_in_state(state, plane, plane_state, j) { +- struct drm_crtc *plane_crtc = plane_state->crtc; +- struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); ++ if (!old_acrtc_state->stream) ++ continue; + +- /*TODO Implement atomic check for cursor plane */ +- if (plane->type == DRM_PLANE_TYPE_CURSOR) +- continue; ++ DRM_DEBUG_KMS("Disabling DRM plane: %d on DRM crtc %d\n", ++ plane->base.id, old_plane_crtc->base.id); + +- if (crtc != plane_crtc) +- continue; ++ if (!dc_remove_plane_from_context( ++ dc, ++ old_acrtc_state->stream, ++ old_dm_plane_state->dc_state, ++ dm_state->context)) { + +- if (!drm_atomic_plane_disabling(plane->state, plane_state)) { +- struct dc_plane_state *dc_plane_state; ++ ret = EINVAL; ++ return ret; ++ } + +- WARN_ON(!new_acrtc_state->stream); + +- dc_plane_state = dc_create_plane_state(dc); ++ dc_plane_state_release(old_dm_plane_state->dc_state); ++ new_dm_plane_state->dc_state = NULL; + +- WARN_ON(dm_plane_state->dc_state); ++ *lock_and_validation_needed = true; + +- dm_plane_state->dc_state = dc_plane_state; ++ } else { /* Add new planes */ + +- ret = fill_plane_attributes( +- plane_crtc->dev->dev_private, +- dc_plane_state, +- plane_state, +- crtc_state, +- false); +- if (ret) +- goto fail; ++ if (drm_atomic_plane_disabling(plane->state, new_plane_state)) ++ continue; + ++ if (!new_plane_crtc) ++ continue; + +- if (!dc_add_plane_to_context( +- dc, +- new_acrtc_state->stream, +- dc_plane_state, +- dm_state->context)) { ++ new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc); ++ new_acrtc_state = to_dm_crtc_state(new_crtc_state); + +- ret = EINVAL; +- goto fail; +- } ++ if (!new_acrtc_state->stream) ++ continue; + + +- lock_and_validation_needed = true; +- } +- } +- } ++ WARN_ON(new_dm_plane_state->dc_state); + +- /* Run this here since we want to validate the streams we created */ +- ret = drm_atomic_helper_check_planes(dev, state); +- if (ret) +- goto fail; ++ new_dm_plane_state->dc_state = dc_create_plane_state(dc); + +- /* +- * For full updates case when +- * removing/adding/updating streams on once CRTC while flipping +- * on another CRTC, +- * acquiring global lock will guarantee that any such full +- * update commit +- * will wait for completion of any outstanding flip using DRMs +- * synchronization events. +- */ ++ DRM_DEBUG_KMS("Enabling DRM plane: %d on DRM crtc %d\n", ++ plane->base.id, new_plane_crtc->base.id); + +- if (lock_and_validation_needed) { ++ if (!new_dm_plane_state->dc_state) { ++ ret = -EINVAL; ++ return ret; ++ } + +- ret = do_aquire_global_lock(dev, state); +- if (ret) +- goto fail; ++ ret = fill_plane_attributes( ++ new_plane_crtc->dev->dev_private, ++ new_dm_plane_state->dc_state, ++ new_plane_state, ++ new_crtc_state, ++ false); ++ if (ret) ++ return ret; + +- if (!dc_validate_global_state(dc, dm_state->context)) { +- ret = -EINVAL; +- goto fail; +- } +- } + +- /* Must be success */ +- WARN_ON(ret); +- return ret; ++ if (!dc_add_plane_to_context( ++ dc, ++ new_acrtc_state->stream, ++ new_dm_plane_state->dc_state, ++ dm_state->context)) { + +-fail: +- if (ret == -EDEADLK) +- DRM_DEBUG_KMS("Atomic check stopped due to to deadlock.\n"); +- else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS) +- DRM_DEBUG_KMS("Atomic check stopped due to to signal.\n"); +- else +- DRM_ERROR("Atomic check failed with err: %d .\n", ret); ++ ret = -EINVAL; ++ return ret; ++ } + +- return ret; ++ *lock_and_validation_needed = true; ++ } ++ } ++ ++ ++ return ret; ++} ++ ++int amdgpu_dm_atomic_check(struct drm_device *dev, ++ struct drm_atomic_state *state) ++{ ++ int i; ++ int ret; ++ struct amdgpu_device *adev = dev->dev_private; ++ struct dc *dc = adev->dm.dc; ++ struct dm_atomic_state *dm_state = to_dm_atomic_state(state); ++ struct drm_connector *connector; ++ struct drm_connector_state *conn_state; ++ struct drm_crtc *crtc; ++ struct drm_crtc_state *crtc_state; ++ ++ /* ++ * This bool will be set for true for any modeset/reset ++ * or plane update which implies non fast surface update. ++ */ ++ bool lock_and_validation_needed = false; ++ ++ ret = drm_atomic_helper_check_modeset(dev, state); ++ ++ if (ret) { ++ DRM_ERROR("Atomic state validation failed with error :%d !\n", ret); ++ return ret; ++ } ++ ++ /* ++ * Hack: Commit needs planes right now, specifically for gamma ++ * TODO rework commit to check CRTC for gamma change ++ */ ++ for_each_crtc_in_state(state, crtc, crtc_state, i) { ++ if (crtc_state->color_mgmt_changed) { ++ ret = drm_atomic_add_affected_planes(state, crtc); ++ if (ret) ++ goto fail; ++ } ++ } ++ ++ /* Remove exiting planes if they are modified */ ++ ret = dm_update_planes_state(dc, state, false, &lock_and_validation_needed); ++ if (ret) { ++ goto fail; ++ } ++ ++ /* Disable all crtcs which require disable */ ++ ret = dm_update_crtcs_state(dc, state, false, &lock_and_validation_needed); ++ if (ret) { ++ goto fail; ++ } ++ ++ /* Enable all crtcs which require enable */ ++ ret = dm_update_crtcs_state(dc, state, true, &lock_and_validation_needed); ++ if (ret) { ++ goto fail; ++ } ++ ++ /* Add new/modified planes */ ++ ret = dm_update_planes_state(dc, state, true, &lock_and_validation_needed); ++ if (ret) { ++ goto fail; ++ } ++ ++ /* Run this here since we want to validate the streams we created */ ++ ret = drm_atomic_helper_check_planes(dev, state); ++ if (ret) ++ goto fail; ++ ++ /* Check scaling and undersacn changes*/ ++ /*TODO Removed scaling changes validation due to inability to commit ++ * new stream into context w\o causing full reset. Need to ++ * decide how to handle. ++ */ ++ for_each_connector_in_state(state, connector, conn_state, i) { ++ struct amdgpu_connector *aconnector = to_amdgpu_connector(connector); ++ struct dm_connector_state *con_old_state = ++ to_dm_connector_state(aconnector->base.state); ++ struct dm_connector_state *con_new_state = ++ to_dm_connector_state(conn_state); ++ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(con_new_state->base.crtc); ++ ++ /* Skip any modesets/resets */ ++ if (!acrtc || drm_atomic_crtc_needs_modeset(acrtc->base.state)) ++ continue; ++ ++ /* Skip any thing not scale or underscan changes */ ++ if (!is_scaling_state_different(con_new_state, con_old_state)) ++ continue; ++ ++ lock_and_validation_needed = true; ++ } ++ ++ /* ++ * For full updates case when ++ * removing/adding/updating streams on once CRTC while flipping ++ * on another CRTC, ++ * acquiring global lock will guarantee that any such full ++ * update commit ++ * will wait for completion of any outstanding flip using DRMs ++ * synchronization events. ++ */ ++ ++ if (lock_and_validation_needed) { ++ ++ ret = do_aquire_global_lock(dev, state); ++ if (ret) ++ goto fail; ++ ++ if (!dc_validate_global_state(dc, dm_state->context)) { ++ ret = -EINVAL; ++ goto fail; ++ } ++ } ++ ++ /* Must be success */ ++ WARN_ON(ret); ++ return ret; ++ ++fail: ++ if (ret == -EDEADLK) ++ DRM_DEBUG_KMS("Atomic check stopped due to to deadlock.\n"); ++ else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS) ++ DRM_DEBUG_KMS("Atomic check stopped due to to signal.\n"); ++ else ++ DRM_ERROR("Atomic check failed with err: %d \n", ret); ++ ++ return ret; + } + + static bool is_dp_capable_without_timing_msa( +-- +2.7.4 + |