Commit 92cc37fb authored by Andrey Grodzovsky's avatar Andrey Grodzovsky Committed by Alex Deucher
Browse files

drm/amd/display: Refactor headless to use atomic commit. (v2)



Headless mode set needs to be synchronized against outstanding nonblocking
commits. This achieved by building atomic state and commiting it.

v2: rebase on 4.11

Signed-off-by: default avatarAndrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 5f42aa39
Loading
Loading
Loading
Loading
+61 −79
Original line number Diff line number Diff line
@@ -2602,108 +2602,90 @@ void amdgpu_dm_atomic_commit_tail(
	/* Release old FB */
	drm_atomic_helper_cleanup_planes(dev, state);
}
/*
 * This functions handle all cases when set mode does not come upon hotplug.
 * This include when the same display is unplugged then plugged back into the
 * same port and when we are running without usermode desktop manager supprot
 */
void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector)
{
	struct drm_crtc *crtc;
	struct amdgpu_device *adev = dev->dev_private;
	struct dc *dc = adev->dm.dc;
	struct amdgpu_connector *aconnector = to_amdgpu_connector(connector);
	struct amdgpu_crtc *disconnected_acrtc;
	const struct dc_sink *sink;
	const struct dc_stream *commit_streams[MAX_STREAMS];
	const struct dc_stream *current_stream;
	uint32_t commit_streams_count = 0;

	if (!aconnector->dc_sink || !connector->state || !connector->encoder)
		return;

	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);

	if (!disconnected_acrtc || !disconnected_acrtc->stream)
		return;
static int dm_force_atomic_commit(struct drm_connector *connector)
{
	int ret = 0;
	struct drm_device *ddev = connector->dev;
	struct drm_atomic_state *state = drm_atomic_state_alloc(ddev);
	struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
	struct drm_plane *plane = disconnected_acrtc->base.primary;
	struct drm_connector_state *conn_state;
	struct drm_crtc_state *crtc_state;
	struct drm_plane_state *plane_state;

	sink = disconnected_acrtc->stream->sink;
	if (!state)
		return -ENOMEM;

	/*
	 * If the previous sink is not released and different from the current,
	 * we deduce we are in a state where we can not rely on usermode call
	 * to turn on the display, so we do it here
	 */
	if (sink != aconnector->dc_sink) {
		struct dm_connector_state *dm_state =
				to_dm_connector_state(aconnector->base.state);
	state->acquire_ctx = ddev->mode_config.acquire_ctx;

		struct dc_stream *new_stream =
			create_stream_for_sink(
				aconnector,
				&disconnected_acrtc->base.state->mode,
				dm_state);
	/* Construct an atomic state to restore previous display setting */

		DRM_INFO("Headless hotplug, restoring connector state\n");
	/*
		 * we evade vblanks and pflips on crtc that
		 * should be changed
	 * Attach connectors to drm_atomic_state
	 */
		manage_dm_interrupts(adev, disconnected_acrtc, false);
		/* this is the update mode case */
	conn_state = drm_atomic_get_connector_state(state, connector);

		current_stream = disconnected_acrtc->stream;
	ret = PTR_ERR_OR_ZERO(conn_state);
	if (ret)
		goto err;

		disconnected_acrtc->stream = new_stream;
		disconnected_acrtc->enabled = true;
		disconnected_acrtc->hw_mode = disconnected_acrtc->base.state->mode;
	/* Attach crtc to drm_atomic_state*/
	crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);

		commit_streams_count = 0;
	ret = PTR_ERR_OR_ZERO(crtc_state);
	if (ret)
		goto err;

		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
			struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
	/* force a restore */
	crtc_state->mode_changed = true;

			if (acrtc->stream) {
				commit_streams[commit_streams_count] = acrtc->stream;
				++commit_streams_count;
			}
		}
	/* Attach plane to drm_atomic_state */
	plane_state = drm_atomic_get_plane_state(state, plane);

		/* DC is optimized not to do anything if 'streams' didn't change. */
		if (!dc_commit_streams(dc, commit_streams,
				commit_streams_count)) {
			DRM_INFO("Failed to restore connector state!\n");
			dc_stream_release(disconnected_acrtc->stream);
			disconnected_acrtc->stream = current_stream;
			manage_dm_interrupts(adev, disconnected_acrtc, true);
			return;
		}
	ret = PTR_ERR_OR_ZERO(plane_state);
	if (ret)
		goto err;

		if (adev->dm.freesync_module) {
			mod_freesync_remove_stream(adev->dm.freesync_module,
				current_stream);

			mod_freesync_add_stream(adev->dm.freesync_module,
						new_stream, &aconnector->caps);
		}
	/* Call commit internally with the state we just constructed */
	ret = drm_atomic_commit(state);
	if (!ret)
		return 0;

		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
			struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
err:
	DRM_ERROR("Restoring old state failed with %i\n", ret);
	drm_atomic_state_put(state);

			if (acrtc->stream != NULL) {
				acrtc->otg_inst =
					dc_stream_get_status(acrtc->stream)->primary_otg_inst;
			}
	return ret;
}

		dc_stream_release(current_stream);
/*
 * This functions handle all cases when set mode does not come upon hotplug.
 * This include when the same display is unplugged then plugged back into the
 * same port and when we are running without usermode desktop manager supprot
 */
void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector)
{
	struct amdgpu_connector *aconnector = to_amdgpu_connector(connector);
	struct amdgpu_crtc *disconnected_acrtc;

	if (!aconnector->dc_sink || !connector->state || !connector->encoder)
		return;

		dm_dc_surface_commit(dc, &disconnected_acrtc->base);
	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);

		manage_dm_interrupts(adev, disconnected_acrtc, true);
		dm_crtc_cursor_reset(&disconnected_acrtc->base);
	if (!disconnected_acrtc || !disconnected_acrtc->stream)
		return;

	}
	/*
	 * If the previous sink is not released and different from the current,
	 * we deduce we are in a state where we can not rely on usermode call
	 * to turn on the display, so we do it here
	 */
	if (disconnected_acrtc->stream->sink != aconnector->dc_sink)
		dm_force_atomic_commit(&aconnector->base);
}

static uint32_t add_val_sets_surface(