1
0
Fork 0

drm/amd/display: Refactor atomic check.

Split into update crtcs and update plane functions.

Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
hifive-unleashed-5.1
Andrey Grodzovsky 2017-08-18 10:52:20 -04:00 committed by Alex Deucher
parent 19f89e2392
commit 62f555377f
1 changed files with 270 additions and 210 deletions

View File

@ -1640,12 +1640,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;
@ -3875,9 +3869,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;
@ -4354,80 +4346,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;
}
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);
}
}
int ret = 0;
/*TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set */
/* update changed items */
@ -4444,6 +4374,49 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
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, "
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
@ -4456,109 +4429,256 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
crtc_state->active_changed,
crtc_state->connectors_changed);
if (modereset_required(crtc_state)) {
/* 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 (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;
if (!dc_remove_stream_from_ctx(
dc,
dm_state->context,
old_acrtc_state->stream)) {
ret = -EINVAL;
break;
}
} else {
dc_stream_release(old_acrtc_state->stream);
new_acrtc_state->stream = NULL;
if (aconnector) {
conn_state = drm_atomic_get_connector_state(state,
&aconnector->base);
*lock_and_validation_needed = true;
if (IS_ERR(conn_state)) {
ret = PTR_ERR_OR_ZERO(conn_state);
goto fail;
}
} else {/* Add stream for any updated/enabled CRTC */
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 (modereset_required(crtc_state))
continue;
if (modeset_required(crtc_state, new_stream,
old_acrtc_state->stream)) {
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);
}
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
*/
return ret;
}
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;
if (pflip_needed)
return ret;
/* 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);
/*TODO Implement atomic check for cursor plane */
if (plane->type == DRM_PLANE_TYPE_CURSOR)
continue;
/* Remove any changed/removed planes */
if (!enable) {
if (!old_plane_crtc)
continue;
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;
}
dc_plane_state_release(old_dm_plane_state->dc_state);
new_dm_plane_state->dc_state = NULL;
*lock_and_validation_needed = true;
} else { /* Add new planes */
if (drm_atomic_plane_disabling(plane->state, new_plane_state))
continue;
if (!new_plane_crtc)
continue;
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc);
new_acrtc_state = to_dm_crtc_state(new_crtc_state);
if (!new_acrtc_state->stream)
continue;
WARN_ON(new_dm_plane_state->dc_state);
new_dm_plane_state->dc_state = dc_create_plane_state(dc);
DRM_DEBUG_KMS("Enabling DRM plane: %d on DRM crtc %d\n",
plane->base.id, new_plane_crtc->base.id);
if (!new_dm_plane_state->dc_state) {
ret = -EINVAL;
return ret;
}
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_add_plane_to_context(
dc,
new_acrtc_state->stream,
new_dm_plane_state->dc_state,
dm_state->context)) {
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;
}
}
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;
}
/* 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
@ -4583,66 +4703,6 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
lock_and_validation_needed = true;
}
/* 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)
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);
/*TODO Implement atomic check for cursor plane */
if (plane->type == DRM_PLANE_TYPE_CURSOR)
continue;
if (crtc != plane_crtc)
continue;
if (!drm_atomic_plane_disabling(plane->state, plane_state)) {
struct dc_plane_state *dc_plane_state;
WARN_ON(!new_acrtc_state->stream);
dc_plane_state = dc_create_plane_state(dc);
WARN_ON(dm_plane_state->dc_state);
dm_plane_state->dc_state = dc_plane_state;
ret = fill_plane_attributes(
plane_crtc->dev->dev_private,
dc_plane_state,
plane_state,
crtc_state,
false);
if (ret)
goto fail;
if (!dc_add_plane_to_context(
dc,
new_acrtc_state->stream,
dc_plane_state,
dm_state->context)) {
ret = EINVAL;
goto fail;
}
lock_and_validation_needed = true;
}
}
}
/* Run this here since we want to validate the streams we created */
ret = drm_atomic_helper_check_planes(dev, state);
if (ret)
goto fail;
/*
* For full updates case when
* removing/adding/updating streams on once CRTC while flipping
@ -4675,7 +4735,7 @@ fail:
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);
DRM_ERROR("Atomic check failed with err: %d \n", ret);
return ret;
}