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

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
Loading
Loading
Loading
Loading
+261 −201
Original line number Diff line number Diff line
@@ -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,46 +4374,14 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,

		aconnector = amdgpu_dm_find_first_crct_matching_connector(state, crtc, true);

		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);

		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) {
		/* 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);
					goto fail;
				break;
			}

			dm_conn_state = to_dm_connector_state(conn_state);
@@ -4504,138 +4402,276 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
						__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 (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(
					dc,
					dm_state->context,
							new_acrtc_state->stream)) {
					old_acrtc_state->stream)) {
				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;
				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
				 */
				*lock_and_validation_needed = true;
			}
		}

		/* Release extra reference */
		if (new_stream)
			 dc_stream_release(new_stream);

	}

	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;

		/*
		 * Hack: Commit needs planes right now, specifically for gamma
		 * TODO rework commit to check CRTC for gamma change
		 */
		if (crtc_state->color_mgmt_changed) {
	if (pflip_needed)
		return ret;

			ret = drm_atomic_add_affected_planes(state, crtc);
			if (ret)
				goto fail;
		}
	}
	/* 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);

	/* 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);
		/*TODO Implement atomic check for cursor plane */
		if (plane->type == DRM_PLANE_TYPE_CURSOR)
			continue;

		/* Skip any modesets/resets */
		if (!acrtc || drm_atomic_crtc_needs_modeset(acrtc->base.state))
		/* Remove any changed/removed planes */
		if (!enable) {

			if (!old_plane_crtc)
				continue;

		/* Skip any thing not scale or underscan changes */
		if (!is_scaling_state_different(con_new_state, con_old_state))
			old_acrtc_state = to_dm_crtc_state(
					drm_atomic_get_old_crtc_state(
							state,
							old_plane_crtc));

			if (!old_acrtc_state->stream)
				continue;

		lock_and_validation_needed = true;
			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)
			continue;
			dc_plane_state_release(old_dm_plane_state->dc_state);
			new_dm_plane_state->dc_state = NULL;

		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);
			*lock_and_validation_needed = true;

			/*TODO Implement atomic check for cursor plane */
			if (plane->type == DRM_PLANE_TYPE_CURSOR)
		} else { /* Add new planes */

			if (drm_atomic_plane_disabling(plane->state, new_plane_state))
				continue;

			if (crtc != plane_crtc)
			if (!new_plane_crtc)
				continue;

			if (!drm_atomic_plane_disabling(plane->state, plane_state)) {
				struct dc_plane_state *dc_plane_state;
			new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc);
			new_acrtc_state = to_dm_crtc_state(new_crtc_state);

				WARN_ON(!new_acrtc_state->stream);
			if (!new_acrtc_state->stream)
				continue;

				dc_plane_state = dc_create_plane_state(dc);

				WARN_ON(dm_plane_state->dc_state);
			WARN_ON(new_dm_plane_state->dc_state);

				dm_plane_state->dc_state = dc_plane_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(
					plane_crtc->dev->dev_private,
					dc_plane_state,
					plane_state,
					crtc_state,
				new_plane_crtc->dev->dev_private,
				new_dm_plane_state->dc_state,
				new_plane_state,
				new_crtc_state,
				false);
			if (ret)
					goto fail;
				return ret;


			if (!dc_add_plane_to_context(
					dc,
					new_acrtc_state->stream,
						dc_plane_state,
					new_dm_plane_state->dc_state,
					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;
		}
	}

	dm_state->context = dc_create_state();
	ASSERT(dm_state->context);
	dc_resource_validate_ctx_copy_construct_current(dc, dm_state->context);

				lock_and_validation_needed = true;
	/* 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 */
@@ -4643,6 +4679,30 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
	 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
@@ -4675,7 +4735,7 @@ int amdgpu_dm_atomic_check(struct drm_device *dev,
	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;
}