diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_atomic.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_atomic.c | 249 | 
1 files changed, 73 insertions, 176 deletions
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 7ed8033aae60..e2531cf59266 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -35,162 +35,6 @@  #include <drm/drm_plane_helper.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; - -	/* -	 * 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; - -	/* FIXME: move to crtc atomic check function once it is ready */ -	ret = intel_atomic_setup_scalers(dev, nuclear_crtc, crtc_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) -{ -	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 */ - -	/* -	 * FIXME:  The proper sequence here will eventually be: -	 * -	 * drm_atomic_helper_swap_state(dev, state) -	 * drm_atomic_helper_commit_modeset_disables(dev, state); -	 * drm_atomic_helper_commit_planes(dev, state); -	 * drm_atomic_helper_commit_modeset_enables(dev, state); -	 * drm_atomic_helper_wait_for_vblanks(dev, state); -	 * drm_atomic_helper_cleanup_planes(dev, state); -	 * drm_atomic_state_free(state); -	 * -	 * once we have full atomic modeset.  For now, just manually update -	 * plane states to avoid clobbering good states with dummy states -	 * while nuclear pageflipping. -	 */ -	for (i = 0; i < dev->mode_config.num_total_plane; i++) { -		struct drm_plane *plane = state->planes[i]; - -		if (!plane) -			continue; - -		plane->state->state = state; -		swap(state->plane_states[i], plane->state); -		plane->state->state = NULL; -	} - -	/* swap crtc_scaler_state */ -	for (i = 0; i < dev->mode_config.num_crtc; i++) { -		struct drm_crtc *crtc = state->crtcs[i]; -		if (!crtc) { -			continue; -		} - -		to_intel_crtc(crtc)->config->scaler_state = -			to_intel_crtc_state(state->crtc_states[i])->scaler_state; - -		if (INTEL_INFO(dev)->gen >= 9) -			skl_detach_scalers(to_intel_crtc(crtc)); -	} - -	drm_atomic_helper_commit_planes(dev, state); -	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   * @connector: connector to fetch property for @@ -298,17 +142,12 @@ int intel_atomic_setup_scalers(struct drm_device *dev,  	struct drm_plane *plane = NULL;  	struct intel_plane *intel_plane;  	struct intel_plane_state *plane_state = NULL; -	struct intel_crtc_scaler_state *scaler_state; -	struct drm_atomic_state *drm_state; +	struct intel_crtc_scaler_state *scaler_state = +		&crtc_state->scaler_state; +	struct drm_atomic_state *drm_state = crtc_state->base.state;  	int num_scalers_need;  	int i, j; -	if (INTEL_INFO(dev)->gen < 9 || !intel_crtc || !crtc_state) -		return 0; - -	scaler_state = &crtc_state->scaler_state; -	drm_state = crtc_state->base.state; -  	num_scalers_need = hweight32(scaler_state->scaler_users);  	DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users = 0x%x\n",  		crtc_state, num_scalers_need, intel_crtc->num_scalers, @@ -336,17 +175,21 @@ int intel_atomic_setup_scalers(struct drm_device *dev,  	/* walkthrough scaler_users bits and start assigning scalers */  	for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {  		int *scaler_id; +		const char *name; +		int idx;  		/* skip if scaler not required */  		if (!(scaler_state->scaler_users & (1 << i)))  			continue;  		if (i == SKL_CRTC_INDEX) { +			name = "CRTC"; +			idx = intel_crtc->base.base.id; +  			/* panel fitter case: assign as a crtc scaler */  			scaler_id = &scaler_state->scaler_id;  		} else { -			if (!drm_state) -				continue; +			name = "PLANE";  			/* plane scaler case: assign as a plane scaler */  			/* find the plane that set the bit as scaler_user */ @@ -365,9 +208,19 @@ int intel_atomic_setup_scalers(struct drm_device *dev,  						plane->base.id);  					return PTR_ERR(state);  				} + +				/* +				 * the plane is added after plane checks are run, +				 * but since this plane is unchanged just do the +				 * minimum required validation. +				 */ +				if (plane->type == DRM_PLANE_TYPE_PRIMARY) +					intel_crtc->atomic.wait_for_flips = true; +				crtc_state->base.planes_changed = true;  			}  			intel_plane = to_intel_plane(plane); +			idx = plane->base.id;  			/* plane on different crtc cannot be a scaler user of this crtc */  			if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) { @@ -383,23 +236,16 @@ int intel_atomic_setup_scalers(struct drm_device *dev,  			for (j = 0; j < intel_crtc->num_scalers; j++) {  				if (!scaler_state->scalers[j].in_use) {  					scaler_state->scalers[j].in_use = 1; -					*scaler_id = scaler_state->scalers[j].id; +					*scaler_id = j;  					DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n", -						intel_crtc->pipe, -						i == SKL_CRTC_INDEX ? scaler_state->scaler_id : -							plane_state->scaler_id, -						i == SKL_CRTC_INDEX ? "CRTC" : "PLANE", -						i == SKL_CRTC_INDEX ?  intel_crtc->base.base.id : -						plane->base.id); +						intel_crtc->pipe, *scaler_id, name, idx);  					break;  				}  			}  		}  		if (WARN_ON(*scaler_id < 0)) { -			DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", -				i == SKL_CRTC_INDEX ? "CRTC" : "PLANE", -				i == SKL_CRTC_INDEX ? intel_crtc->base.base.id:plane->base.id); +			DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", name, idx);  			continue;  		} @@ -421,3 +267,54 @@ int intel_atomic_setup_scalers(struct drm_device *dev,  	return 0;  } + +static void +intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, +				  struct intel_shared_dpll_config *shared_dpll) +{ +	enum intel_dpll_id i; + +	/* Copy shared dpll state */ +	for (i = 0; i < dev_priv->num_shared_dpll; i++) { +		struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + +		shared_dpll[i] = pll->config; +	} +} + +struct intel_shared_dpll_config * +intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s) +{ +	struct intel_atomic_state *state = to_intel_atomic_state(s); + +	WARN_ON(!drm_modeset_is_locked(&s->dev->mode_config.connection_mutex)); + +	if (!state->dpll_set) { +		state->dpll_set = true; + +		intel_atomic_duplicate_dpll_state(to_i915(s->dev), +						  state->shared_dpll); +	} + +	return state->shared_dpll; +} + +struct drm_atomic_state * +intel_atomic_state_alloc(struct drm_device *dev) +{ +	struct intel_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + +	if (!state || drm_atomic_state_init(dev, &state->base) < 0) { +		kfree(state); +		return NULL; +	} + +	return &state->base; +} + +void intel_atomic_state_clear(struct drm_atomic_state *s) +{ +	struct intel_atomic_state *state = to_intel_atomic_state(s); +	drm_atomic_state_default_clear(&state->base); +	state->dpll_set = false; +}  | 
