Commit 62f55537 authored by Andrey Grodzovsky's avatar Andrey Grodzovsky Committed by Alex Deucher

drm/amd/display: Refactor atomic check.

Split into update crtcs and update plane functions.
Signed-off-by: default avatarAndrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Reviewed-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 19f89e23
...@@ -1640,12 +1640,6 @@ static bool modeset_required(struct drm_crtc_state *crtc_state, ...@@ -1640,12 +1640,6 @@ static bool modeset_required(struct drm_crtc_state *crtc_state,
struct dc_stream_state *new_stream, struct dc_stream_state *new_stream,
struct dc_stream_state *old_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)) if (!drm_atomic_crtc_needs_modeset(crtc_state))
return false; return false;
...@@ -3875,9 +3869,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, ...@@ -3875,9 +3869,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
continue; continue;
} }
if (!fb || !crtc || pcrtc != crtc || !crtc->state->active || if (!fb || !crtc || pcrtc != crtc || !crtc->state->active)
(!crtc->state->planes_changed &&
!pcrtc->state->color_mgmt_changed))
continue; continue;
pflip_needed = !state->allow_modeset; pflip_needed = !state->allow_modeset;
...@@ -4354,80 +4346,18 @@ static int do_aquire_global_lock( ...@@ -4354,80 +4346,18 @@ static int do_aquire_global_lock(
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
} }
int amdgpu_dm_atomic_check(struct drm_device *dev, static int dm_update_crtcs_state(
struct drm_atomic_state *state) struct dc *dc,
struct drm_atomic_state *state,
bool enable,
bool *lock_and_validation_needed)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
struct drm_plane *plane; int i;
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;
struct dm_crtc_state *old_acrtc_state, *new_acrtc_state; struct dm_crtc_state *old_acrtc_state, *new_acrtc_state;
struct dm_atomic_state *dm_state = to_dm_atomic_state(state); struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
bool pflip_needed = !state->allow_modeset; int ret = 0;
/*
* 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;
}
dm_state->context = dc_create_state();
ASSERT(dm_state->context);
dc_resource_validate_ctx_copy_construct_current(dc, dm_state->context);
/* 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);
}
}
/*TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set */ /*TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set */
/* update changed items */ /* update changed items */
...@@ -4444,46 +4374,14 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -4444,46 +4374,14 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
aconnector = amdgpu_dm_find_first_crct_matching_connector(state, crtc, true); aconnector = amdgpu_dm_find_first_crct_matching_connector(state, crtc, true);
DRM_DEBUG_KMS( /* TODO This hack should go away */
"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, " if (aconnector && aconnector->dc_sink) {
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
"connectors_changed:%d\n",
acrtc->crtc_id,
crtc_state->enable,
crtc_state->active,
crtc_state->planes_changed,
crtc_state->mode_changed,
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, conn_state = drm_atomic_get_connector_state(state,
&aconnector->base); &aconnector->base);
if (IS_ERR(conn_state)) { if (IS_ERR(conn_state)) {
ret = PTR_ERR_OR_ZERO(conn_state); ret = PTR_ERR_OR_ZERO(conn_state);
goto fail; break;
} }
dm_conn_state = to_dm_connector_state(conn_state); dm_conn_state = to_dm_connector_state(conn_state);
...@@ -4504,138 +4402,276 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -4504,138 +4402,276 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
__func__, acrtc->base.base.id); __func__, acrtc->base.base.id);
break; 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 (modeset_required(crtc_state, new_stream,
old_acrtc_state->stream)) {
if (new_acrtc_state->stream) { if (!drm_atomic_crtc_needs_modeset(crtc_state))
continue;
DRM_DEBUG_KMS(
"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
"connectors_changed:%d\n",
acrtc->crtc_id,
crtc_state->enable,
crtc_state->active,
crtc_state->planes_changed,
crtc_state->mode_changed,
crtc_state->active_changed,
crtc_state->connectors_changed);
/* 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( if (!dc_remove_stream_from_ctx(
dc, dc,
dm_state->context, dm_state->context,
new_acrtc_state->stream)) { old_acrtc_state->stream)) {
ret = -EINVAL; ret = -EINVAL;
goto fail; break;
} }
dc_stream_release(old_acrtc_state->stream);
new_acrtc_state->stream = NULL;
dc_stream_release(new_acrtc_state->stream); *lock_and_validation_needed = true;
}
} else {/* Add stream for any updated/enabled CRTC */
if (modereset_required(crtc_state))
continue;
if (modeset_required(crtc_state, new_stream,
old_acrtc_state->stream)) {
WARN_ON(new_acrtc_state->stream);
new_acrtc_state->stream = new_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( if (!dc_add_stream_to_ctx(
dc, dc,
dm_state->context, dm_state->context,
new_acrtc_state->stream)) { new_acrtc_state->stream)) {
ret = -EINVAL; ret = -EINVAL;
goto fail; break;
} }
lock_and_validation_needed = true; *lock_and_validation_needed = true;
} else { }
/* }
* The new stream is unused, so we release it
*/ /* Release extra reference */
if (new_stream) if (new_stream)
dc_stream_release(new_stream); dc_stream_release(new_stream);
}
} }
return ret;
}
/* static int dm_update_planes_state(
* Hack: Commit needs planes right now, specifically for gamma struct dc *dc,
* TODO rework commit to check CRTC for gamma change struct drm_atomic_state *state,
*/ bool enable,
if (crtc_state->color_mgmt_changed) { 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;
ret = drm_atomic_add_affected_planes(state, crtc); if (pflip_needed)
if (ret) return ret;
goto fail;
}
}
/* Check scaling and undersacn changes*/ /* Add new planes */
/*TODO Removed scaling changes validation due to inability to commit for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
* new stream into context w\o causing full reset. Need to new_plane_crtc = new_plane_state->crtc;
* decide how to handle. old_plane_crtc = old_plane_state->crtc;
*/ new_dm_plane_state = to_dm_plane_state(new_plane_state);
for_each_connector_in_state(state, connector, conn_state, i) { old_dm_plane_state = to_dm_plane_state(old_plane_state);
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 */ /*TODO Implement atomic check for cursor plane */
if (!acrtc || drm_atomic_crtc_needs_modeset(acrtc->base.state)) if (plane->type == DRM_PLANE_TYPE_CURSOR)
continue; continue;
/* Skip any thing not scale or underscan changes */ /* Remove any changed/removed planes */
if (!is_scaling_state_different(con_new_state, con_old_state)) if (!enable) {
if (!old_plane_crtc)
continue; continue;
lock_and_validation_needed = true; old_acrtc_state = to_dm_crtc_state(
drm_atomic_get_old_crtc_state(
state,
old_plane_crtc));
if (!old_acrtc_state->stream)
continue;
DRM_DEBUG_KMS("Disabling DRM plane: %d on DRM crtc %d\n",
plane->base.id, old_plane_crtc->base.id);
if (!dc_remove_plane_from_context(
dc,
old_acrtc_state->stream,
old_dm_plane_state->dc_state,
dm_state->context)) {
ret = EINVAL;
return ret;
} }
/* Add new planes */
for_each_crtc_in_state(state, crtc, crtc_state, i) {
new_acrtc_state = to_dm_crtc_state(crtc_state);
if (pflip_needed) dc_plane_state_release(old_dm_plane_state->dc_state);
continue; new_dm_plane_state->dc_state = NULL;
for_each_plane_in_state(state, plane, plane_state, j) { *lock_and_validation_needed = true;
struct drm_crtc *plane_crtc = plane_state->crtc;
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
/*TODO Implement atomic check for cursor plane */ } else { /* Add new planes */
if (plane->type == DRM_PLANE_TYPE_CURSOR)
if (drm_atomic_plane_disabling(plane->state, new_plane_state))
continue; continue;
if (crtc != plane_crtc) if (!new_plane_crtc)
continue; continue;
if (!drm_atomic_plane_disabling(plane->state, plane_state)) { new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc);
struct dc_plane_state *dc_plane_state; new_acrtc_state = to_dm_crtc_state(new_crtc_state);
WARN_ON(!new_acrtc_state->stream); if (!new_acrtc_state->stream)
continue;
WARN_ON(new_dm_plane_state->dc_state);
dc_plane_state = dc_create_plane_state(dc); new_dm_plane_state->dc_state = dc_create_plane_state(dc);
WARN_ON(dm_plane_state->dc_state); DRM_DEBUG_KMS("Enabling DRM plane: %d on DRM crtc %d\n",
plane->base.id, new_plane_crtc->base.id);
dm_plane_state->dc_state = dc_plane_state; if (!new_dm_plane_state->dc_state) {
ret = -EINVAL;
return ret;
}
ret = fill_plane_attributes( ret = fill_plane_attributes(
plane_crtc->dev->dev_private, new_plane_crtc->dev->dev_private,
dc_plane_state, new_dm_plane_state->dc_state,
plane_state, new_plane_state,
crtc_state, new_crtc_state,
false); false);
if (ret) if (ret)
goto fail; return ret;
if (!dc_add_plane_to_context( if (!dc_add_plane_to_context(
dc, dc,
new_acrtc_state->stream, new_acrtc_state->stream,
dc_plane_state, new_dm_plane_state->dc_state,
dm_state->context)) { dm_state->context)) {
ret = EINVAL; ret = -EINVAL;
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; goto fail;
} }
}
dm_state->context = dc_create_state();
ASSERT(dm_state->context);
dc_resource_validate_ctx_copy_construct_current(dc, dm_state->context);
/* Remove exiting planes if they are modified */
ret = dm_update_planes_state(dc, state, false, &lock_and_validation_needed);
if (ret) {
goto fail;
}
lock_and_validation_needed = true; /* 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 */ /* Run this here since we want to validate the streams we created */
...@@ -4643,6 +4679,30 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -4643,6 +4679,30 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
if (ret) if (ret)
goto fail; 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 * For full updates case when
* removing/adding/updating streams on once CRTC while flipping * removing/adding/updating streams on once CRTC while flipping
...@@ -4675,7 +4735,7 @@ int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -4675,7 +4735,7 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS) else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
DRM_DEBUG_KMS("Atomic check stopped due to to signal.\n"); DRM_DEBUG_KMS("Atomic check stopped due to to signal.\n");
else else
DRM_ERROR("Atomic check failed with err: %d .\n", ret); DRM_ERROR("Atomic check failed with err: %d \n", ret);
return ret; return ret;
} }
......
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