Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74c090b1 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Daniel Vetter
Browse files

drm/i915: Use full atomic modeset.

parent 9b01435d
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -1731,7 +1731,7 @@ static int __init i915_init(void)
	 * to the atomic ioctl and the atomic properties.  Only plane operations on
	 * to the atomic ioctl and the atomic properties.  Only plane operations on
	 * a single CRTC will actually work.
	 * a single CRTC will actually work.
	 */
	 */
	if (i915.nuclear_pageflip)
	if (driver.driver_features & DRIVER_MODESET)
		driver.driver_features |= DRIVER_ATOMIC;
		driver.driver_features |= DRIVER_ATOMIC;


	return drm_pci_init(&driver, &i915_pci_driver);
	return drm_pci_init(&driver, &i915_pci_driver);
+0 −1
Original line number Original line Diff line number Diff line
@@ -2614,7 +2614,6 @@ struct i915_params {
	int use_mmio_flip;
	int use_mmio_flip;
	int mmio_debug;
	int mmio_debug;
	bool verbose_state_checks;
	bool verbose_state_checks;
	bool nuclear_pageflip;
	int edp_vswing;
	int edp_vswing;
};
};
extern struct i915_params i915 __read_mostly;
extern struct i915_params i915 __read_mostly;
+0 −5
Original line number Original line Diff line number Diff line
@@ -51,7 +51,6 @@ struct i915_params i915 __read_mostly = {
	.use_mmio_flip = 0,
	.use_mmio_flip = 0,
	.mmio_debug = 0,
	.mmio_debug = 0,
	.verbose_state_checks = 1,
	.verbose_state_checks = 1,
	.nuclear_pageflip = 0,
	.edp_vswing = 0,
	.edp_vswing = 0,
};
};


@@ -176,10 +175,6 @@ module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
MODULE_PARM_DESC(verbose_state_checks,
MODULE_PARM_DESC(verbose_state_checks,
	"Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");
	"Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");


module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600);
MODULE_PARM_DESC(nuclear_pageflip,
		 "Force atomic modeset functionality; only planes work for now (default: false).");

/* WA to get away with the default setting in VBT for early platforms.Will be removed */
/* WA to get away with the default setting in VBT for early platforms.Will be removed */
module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400);
module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400);
MODULE_PARM_DESC(edp_vswing,
MODULE_PARM_DESC(edp_vswing,
+0 −123
Original line number Original line Diff line number Diff line
@@ -35,129 +35,6 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_plane_helper.h>
#include "intel_drv.h"
#include "intel_drv.h"



/**
 * intel_atomic_check - validate state object
 * @dev: drm device
 * @state: state to validate
 */
int intel_atomic_check(struct drm_device *dev,
		       struct drm_atomic_state *state)
{
	int nplanes = dev->mode_config.num_total_plane;
	int ncrtcs = dev->mode_config.num_crtc;
	int nconnectors = dev->mode_config.num_connector;
	enum pipe nuclear_pipe = INVALID_PIPE;
	struct intel_crtc *nuclear_crtc = NULL;
	struct intel_crtc_state *crtc_state = NULL;
	int ret;
	int i;
	bool not_nuclear = false;

	to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq;

	/*
	 * FIXME:  At the moment, we only support "nuclear pageflip" on a
	 * single CRTC.  Cross-crtc updates will be added later.
	 */
	for (i = 0; i < nplanes; i++) {
		struct intel_plane *plane = to_intel_plane(state->planes[i]);
		if (!plane)
			continue;

		if (nuclear_pipe == INVALID_PIPE) {
			nuclear_pipe = plane->pipe;
		} else if (nuclear_pipe != plane->pipe) {
			DRM_DEBUG_KMS("i915 only support atomic plane operations on a single CRTC at the moment\n");
			return -EINVAL;
		}
	}

	/*
	 * FIXME:  We only handle planes for now; make sure there are no CRTC's
	 * or connectors involved.
	 */
	state->allow_modeset = false;
	for (i = 0; i < ncrtcs; i++) {
		struct intel_crtc *crtc = to_intel_crtc(state->crtcs[i]);
		if (crtc)
			memset(&crtc->atomic, 0, sizeof(crtc->atomic));
		if (crtc && crtc->pipe != nuclear_pipe)
			not_nuclear = true;
		if (crtc && crtc->pipe == nuclear_pipe) {
			nuclear_crtc = crtc;
			crtc_state = to_intel_crtc_state(state->crtc_states[i]);
		}
	}
	for (i = 0; i < nconnectors; i++)
		if (state->connectors[i] != NULL)
			not_nuclear = true;

	if (not_nuclear) {
		DRM_DEBUG_KMS("i915 only supports atomic plane operations at the moment\n");
		return -EINVAL;
	}

	ret = drm_atomic_helper_check_planes(dev, state);
	if (ret)
		return ret;

	return ret;
}


/**
 * intel_atomic_commit - commit validated state object
 * @dev: DRM device
 * @state: the top-level driver state object
 * @async: asynchronous commit
 *
 * This function commits a top-level state object that has been validated
 * with drm_atomic_helper_check().
 *
 * FIXME:  Atomic modeset support for i915 is not yet complete.  At the moment
 * we can only handle plane-related operations and do not yet support
 * asynchronous commit.
 *
 * RETURNS
 * Zero for success or -errno.
 */
int intel_atomic_commit(struct drm_device *dev,
			struct drm_atomic_state *state,
			bool async)
{
	struct drm_crtc_state *crtc_state;
	struct drm_crtc *crtc;
	int ret;
	int i;

	if (async) {
		DRM_DEBUG_KMS("i915 does not yet support async commit\n");
		return -EINVAL;
	}

	ret = drm_atomic_helper_prepare_planes(dev, state);
	if (ret)
		return ret;

	/* Point of no return */
	drm_atomic_helper_swap_state(dev, state);

	for_each_crtc_in_state(state, crtc, crtc_state, i) {
		to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state);

		drm_atomic_helper_commit_planes_on_crtc(crtc_state);
	}

	/* FIXME: This function should eventually call __intel_set_mode when needed */

	drm_atomic_helper_wait_for_vblanks(dev, state);
	drm_atomic_helper_cleanup_planes(dev, state);
	drm_atomic_state_free(state);

	return 0;
}

/**
/**
 * intel_connector_atomic_get_property - fetch connector property value
 * intel_connector_atomic_get_property - fetch connector property value
 * @connector: connector to fetch property for
 * @connector: connector to fetch property for
+42 −237
Original line number Original line Diff line number Diff line
@@ -86,7 +86,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
				   struct intel_crtc_state *pipe_config);
				   struct intel_crtc_state *pipe_config);


static int intel_set_mode(struct drm_atomic_state *state);
static int intel_framebuffer_init(struct drm_device *dev,
static int intel_framebuffer_init(struct drm_device *dev,
				  struct intel_framebuffer *ifb,
				  struct intel_framebuffer *ifb,
				  struct drm_mode_fb_cmd2 *mode_cmd,
				  struct drm_mode_fb_cmd2 *mode_cmd,
@@ -111,14 +110,6 @@ static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
			   int num_connectors);
			   int num_connectors);
static void intel_modeset_setup_hw_state(struct drm_device *dev);
static void intel_modeset_setup_hw_state(struct drm_device *dev);


static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
{
	if (!connector->mst_port)
		return connector->encoder;
	else
		return &connector->mst_port->mst_encoders[pipe]->base;
}

typedef struct {
typedef struct {
	int	min, max;
	int	min, max;
} intel_range_t;
} intel_range_t;
@@ -6262,7 +6253,7 @@ int intel_display_suspend(struct drm_device *dev)
	}
	}


	if (crtc_mask) {
	if (crtc_mask) {
		ret = intel_set_mode(state);
		ret = drm_atomic_commit(state);


		if (!ret) {
		if (!ret) {
			for_each_crtc(dev, crtc)
			for_each_crtc(dev, crtc)
@@ -6316,7 +6307,7 @@ int intel_crtc_control(struct drm_crtc *crtc, bool enable)
	}
	}
	pipe_config->base.active = enable;
	pipe_config->base.active = enable;


	ret = intel_set_mode(state);
	ret = drm_atomic_commit(state);
	if (!ret)
	if (!ret)
		return ret;
		return ret;


@@ -10430,7 +10421,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,


	drm_mode_copy(&crtc_state->base.mode, mode);
	drm_mode_copy(&crtc_state->base.mode, mode);


	if (intel_set_mode(state)) {
	if (drm_atomic_commit(state)) {
		DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
		DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
		if (old->release_fb)
		if (old->release_fb)
			old->release_fb->funcs->destroy(old->release_fb);
			old->release_fb->funcs->destroy(old->release_fb);
@@ -10498,7 +10489,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
		if (ret)
		if (ret)
			goto fail;
			goto fail;


		ret = intel_set_mode(state);
		ret = drm_atomic_commit(state);
		if (ret)
		if (ret)
			goto fail;
			goto fail;


@@ -13119,7 +13110,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
}
}




/* Code that should eventually be part of atomic_check() */
static int intel_modeset_checks(struct drm_atomic_state *state)
static int intel_modeset_checks(struct drm_atomic_state *state)
{
{
	struct drm_device *dev = state->dev;
	struct drm_device *dev = state->dev;
@@ -13160,15 +13150,20 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
	return 0;
	return 0;
}
}


static int
/**
intel_modeset_compute_config(struct drm_atomic_state *state)
 * intel_atomic_check - validate state object
 * @dev: drm device
 * @state: state to validate
 */
static int intel_atomic_check(struct drm_device *dev,
			      struct drm_atomic_state *state)
{
{
	struct drm_crtc *crtc;
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
	struct drm_crtc_state *crtc_state;
	int ret, i;
	int ret, i;
	bool any_ms = false;
	bool any_ms = false;


	ret = drm_atomic_helper_check_modeset(state->dev, state);
	ret = drm_atomic_helper_check_modeset(dev, state);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -13231,9 +13226,26 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
	return drm_atomic_helper_check_planes(state->dev, state);
	return drm_atomic_helper_check_planes(state->dev, state);
}
}


static int __intel_set_mode(struct drm_atomic_state *state)
/**
 * intel_atomic_commit - commit validated state object
 * @dev: DRM device
 * @state: the top-level driver state object
 * @async: asynchronous commit
 *
 * This function commits a top-level state object that has been validated
 * with drm_atomic_helper_check().
 *
 * FIXME:  Atomic modeset support for i915 is not yet complete.  At the moment
 * we can only handle plane-related operations and do not yet support
 * asynchronous commit.
 *
 * RETURNS
 * Zero for success or -errno.
 */
static int intel_atomic_commit(struct drm_device *dev,
			       struct drm_atomic_state *state,
			       bool async)
{
{
	struct drm_device *dev = state->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_crtc *crtc;
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
	struct drm_crtc_state *crtc_state;
@@ -13241,6 +13253,11 @@ static int __intel_set_mode(struct drm_atomic_state *state)
	int i;
	int i;
	bool any_ms = false;
	bool any_ms = false;


	if (async) {
		DRM_DEBUG_KMS("i915 does not yet support async commit\n");
		return -EINVAL;
	}

	ret = drm_atomic_helper_prepare_planes(dev, state);
	ret = drm_atomic_helper_prepare_planes(dev, state);
	if (ret)
	if (ret)
		return ret;
		return ret;
@@ -13285,34 +13302,14 @@ static int __intel_set_mode(struct drm_atomic_state *state)


	/* FIXME: add subpixel order */
	/* FIXME: add subpixel order */


	drm_atomic_helper_wait_for_vblanks(dev, state);
	drm_atomic_helper_cleanup_planes(dev, state);
	drm_atomic_helper_cleanup_planes(dev, state);

	drm_atomic_state_free(state);
	drm_atomic_state_free(state);


	return 0;
	if (any_ms)
}

static int intel_set_mode_checked(struct drm_atomic_state *state)
{
	struct drm_device *dev = state->dev;
	int ret;

	ret = __intel_set_mode(state);
	if (ret == 0)
		intel_modeset_check_state(dev);
		intel_modeset_check_state(dev);


	return ret;
	return 0;
}

static int intel_set_mode(struct drm_atomic_state *state)
{
	int ret;

	ret = intel_modeset_compute_config(state);
	if (ret)
		return ret;

	return intel_set_mode_checked(state);
}
}


void intel_crtc_restore_mode(struct drm_crtc *crtc)
void intel_crtc_restore_mode(struct drm_crtc *crtc)
@@ -13339,7 +13336,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc)
			goto out;
			goto out;


		crtc_state->mode_changed = true;
		crtc_state->mode_changed = true;
		ret = intel_set_mode(state);
		ret = drm_atomic_commit(state);
	}
	}


	if (ret == -EDEADLK) {
	if (ret == -EDEADLK) {
@@ -13355,201 +13352,9 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc)


#undef for_each_intel_crtc_masked
#undef for_each_intel_crtc_masked


static bool intel_connector_in_mode_set(struct intel_connector *connector,
					struct drm_mode_set *set)
{
	int ro;

	for (ro = 0; ro < set->num_connectors; ro++)
		if (set->connectors[ro] == &connector->base)
			return true;

	return false;
}

static int
intel_modeset_stage_output_state(struct drm_device *dev,
				 struct drm_mode_set *set,
				 struct drm_atomic_state *state)
{
	struct intel_connector *connector;
	struct drm_connector *drm_connector;
	struct drm_connector_state *connector_state;
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
	int i, ret;

	/* The upper layers ensure that we either disable a crtc or have a list
	 * of connectors. For paranoia, double-check this. */
	WARN_ON(!set->fb && (set->num_connectors != 0));
	WARN_ON(set->fb && (set->num_connectors == 0));

	for_each_intel_connector(dev, connector) {
		bool in_mode_set = intel_connector_in_mode_set(connector, set);

		if (!in_mode_set && connector->base.state->crtc != set->crtc)
			continue;

		connector_state =
			drm_atomic_get_connector_state(state, &connector->base);
		if (IS_ERR(connector_state))
			return PTR_ERR(connector_state);

		if (in_mode_set) {
			int pipe = to_intel_crtc(set->crtc)->pipe;
			connector_state->best_encoder =
				&intel_find_encoder(connector, pipe)->base;
		}

		if (connector->base.state->crtc != set->crtc)
			continue;

		/* If we disable the crtc, disable all its connectors. Also, if
		 * the connector is on the changing crtc but not on the new
		 * connector list, disable it. */
		if (!set->fb || !in_mode_set) {
			connector_state->best_encoder = NULL;

			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
				connector->base.base.id,
				connector->base.name);
		}
	}
	/* connector->new_encoder is now updated for all connectors. */

	for_each_connector_in_state(state, drm_connector, connector_state, i) {
		connector = to_intel_connector(drm_connector);

		if (!connector_state->best_encoder) {
			ret = drm_atomic_set_crtc_for_connector(connector_state,
								NULL);
			if (ret)
				return ret;

			continue;
		}

		if (intel_connector_in_mode_set(connector, set)) {
			struct drm_crtc *crtc = connector->base.state->crtc;

			/* If this connector was in a previous crtc, add it
			 * to the state. We might need to disable it. */
			if (crtc) {
				crtc_state =
					drm_atomic_get_crtc_state(state, crtc);
				if (IS_ERR(crtc_state))
					return PTR_ERR(crtc_state);
			}

			ret = drm_atomic_set_crtc_for_connector(connector_state,
								set->crtc);
			if (ret)
				return ret;
		}

		/* Make sure the new CRTC will work with the encoder */
		if (!drm_encoder_crtc_ok(connector_state->best_encoder,
					 connector_state->crtc)) {
			return -EINVAL;
		}

		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
			connector->base.base.id,
			connector->base.name,
			connector_state->crtc->base.id);

		if (connector_state->best_encoder != &connector->encoder->base)
			connector->encoder =
				to_intel_encoder(connector_state->best_encoder);
	}

	for_each_crtc_in_state(state, crtc, crtc_state, i) {
		bool has_connectors;

		ret = drm_atomic_add_affected_connectors(state, crtc);
		if (ret)
			return ret;

		has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc);
		if (has_connectors != crtc_state->enable)
			crtc_state->enable =
			crtc_state->active = has_connectors;
	}

	ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode,
					      set->fb, set->x, set->y);
	if (ret)
		return ret;

	crtc_state = drm_atomic_get_crtc_state(state, set->crtc);
	if (IS_ERR(crtc_state))
		return PTR_ERR(crtc_state);

	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
	if (ret)
		return ret;

	if (set->num_connectors)
		crtc_state->active = true;

	return 0;
}

static int intel_crtc_set_config(struct drm_mode_set *set)
{
	struct drm_device *dev;
	struct drm_atomic_state *state = NULL;
	int ret;

	BUG_ON(!set);
	BUG_ON(!set->crtc);
	BUG_ON(!set->crtc->helper_private);

	/* Enforce sane interface api - has been abused by the fb helper. */
	BUG_ON(!set->mode && set->fb);
	BUG_ON(set->fb && set->num_connectors == 0);

	if (set->fb) {
		DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
				set->crtc->base.id, set->fb->base.id,
				(int)set->num_connectors, set->x, set->y);
	} else {
		DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
	}

	dev = set->crtc->dev;

	state = drm_atomic_state_alloc(dev);
	if (!state)
		return -ENOMEM;

	state->acquire_ctx = dev->mode_config.acquire_ctx;

	ret = intel_modeset_stage_output_state(dev, set, state);
	if (ret)
		goto out;

	ret = intel_modeset_compute_config(state);
	if (ret)
		goto out;

	intel_update_pipe_size(to_intel_crtc(set->crtc));

	ret = intel_set_mode_checked(state);
	if (ret) {
		DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
			      set->crtc->base.id, ret);
	}

out:
	if (ret)
		drm_atomic_state_free(state);
	return ret;
}

static const struct drm_crtc_funcs intel_crtc_funcs = {
static const struct drm_crtc_funcs intel_crtc_funcs = {
	.gamma_set = intel_crtc_gamma_set,
	.gamma_set = intel_crtc_gamma_set,
	.set_config = intel_crtc_set_config,
	.set_config = drm_atomic_helper_set_config,
	.destroy = intel_crtc_destroy,
	.destroy = intel_crtc_destroy,
	.page_flip = intel_crtc_page_flip,
	.page_flip = intel_crtc_page_flip,
	.atomic_duplicate_state = intel_crtc_duplicate_state,
	.atomic_duplicate_state = intel_crtc_duplicate_state,
@@ -15654,7 +15459,7 @@ void intel_display_resume(struct drm_device *dev)
	intel_modeset_setup_hw_state(dev);
	intel_modeset_setup_hw_state(dev);


	i915_redisable_vga(dev);
	i915_redisable_vga(dev);
	ret = intel_set_mode(state);
	ret = drm_atomic_commit(state);
	if (!ret)
	if (!ret)
		return;
		return;


Loading