diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
| -rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 126 | 
1 files changed, 92 insertions, 34 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 20be86d89a20..c3f83476f996 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -594,7 +594,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,  	struct drm_plane_state *plane_state;  	int i, ret = 0; -	ret = drm_atomic_helper_normalize_zpos(dev, state); +	ret = drm_atomic_normalize_zpos(dev, state);  	if (ret)  		return ret; @@ -749,6 +749,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)  		/* Right function depends upon target state. */  		if (crtc->state->enable && funcs->prepare)  			funcs->prepare(crtc); +		else if (funcs->atomic_disable) +			funcs->atomic_disable(crtc, old_crtc_state);  		else if (funcs->disable)  			funcs->disable(crtc);  		else @@ -886,8 +888,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)  		 * Each encoder has at most one connector (since we always steal  		 * it away), so we won't call mode_set hooks twice.  		 */ -		if (funcs && funcs->mode_set) +		if (funcs && funcs->atomic_mode_set) { +			funcs->atomic_mode_set(encoder, new_crtc_state, +					       connector->state); +		} else if (funcs && funcs->mode_set) {  			funcs->mode_set(encoder, mode, adjusted_mode); +		}  		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);  	} @@ -1003,29 +1009,46 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);   * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state   * @dev: DRM device   * @state: atomic state object with old state structures + * @pre_swap: if true, do an interruptible wait   *   * For implicit sync, driver should fish the exclusive fence out from the   * incoming fb's and stash it in the drm_plane_state.  This is called after   * drm_atomic_helper_swap_state() so it uses the current plane state (and   * just uses the atomic state to find the changed planes) + * + * Returns zero if success or < 0 if fence_wait() fails.   */ -void drm_atomic_helper_wait_for_fences(struct drm_device *dev, -			    struct drm_atomic_state *state) +int drm_atomic_helper_wait_for_fences(struct drm_device *dev, +				      struct drm_atomic_state *state, +				      bool pre_swap)  {  	struct drm_plane *plane;  	struct drm_plane_state *plane_state; -	int i; +	int i, ret;  	for_each_plane_in_state(state, plane, plane_state, i) { -		if (!plane->state->fence) +		if (!pre_swap) +			plane_state = plane->state; + +		if (!plane_state->fence)  			continue; -		WARN_ON(!plane->state->fb); +		WARN_ON(!plane_state->fb); + +		/* +		 * If waiting for fences pre-swap (ie: nonblock), userspace can +		 * still interrupt the operation. Instead of blocking until the +		 * timer expires, make the wait interruptible. +		 */ +		ret = fence_wait(plane_state->fence, pre_swap); +		if (ret) +			return ret; -		fence_wait(plane->state->fence, false); -		fence_put(plane->state->fence); -		plane->state->fence = NULL; +		fence_put(plane_state->fence); +		plane_state->fence = NULL;  	} + +	return 0;  }  EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences); @@ -1142,7 +1165,8 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);   *   *     drm_atomic_helper_commit_modeset_enables(dev, state);   * - *     drm_atomic_helper_commit_planes(dev, state, true); + *     drm_atomic_helper_commit_planes(dev, state, + *                                     DRM_PLANE_COMMIT_ACTIVE_ONLY);   *   * for committing the atomic update to hardware.  See the kerneldoc entries for   * these three functions for more details. @@ -1153,7 +1177,7 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *state)  	drm_atomic_helper_commit_modeset_disables(dev, state); -	drm_atomic_helper_commit_planes(dev, state, false); +	drm_atomic_helper_commit_planes(dev, state, 0);  	drm_atomic_helper_commit_modeset_enables(dev, state); @@ -1172,7 +1196,7 @@ static void commit_tail(struct drm_atomic_state *state)  	funcs = dev->mode_config.helper_private; -	drm_atomic_helper_wait_for_fences(dev, state); +	drm_atomic_helper_wait_for_fences(dev, state, false);  	drm_atomic_helper_wait_for_dependencies(state); @@ -1231,6 +1255,12 @@ int drm_atomic_helper_commit(struct drm_device *dev,  	if (ret)  		return ret; +	if (!nonblock) { +		ret = drm_atomic_helper_wait_for_fences(dev, state, true); +		if (ret) +			return ret; +	} +  	/*  	 * This is the point of no return - everything below never fails except  	 * when the hw goes bonghits. Which means we can commit the new state on @@ -1631,6 +1661,9 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,  		funcs = plane->helper_private; +		if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc)) +			continue; +  		if (funcs->prepare_fb) {  			ret = funcs->prepare_fb(plane, plane_state);  			if (ret) @@ -1647,18 +1680,20 @@ fail:  		if (j >= i)  			continue; +		if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc)) +			continue; +  		funcs = plane->helper_private;  		if (funcs->cleanup_fb)  			funcs->cleanup_fb(plane, plane_state); -  	}  	return ret;  }  EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); -bool plane_crtc_active(struct drm_plane_state *state) +static bool plane_crtc_active(const struct drm_plane_state *state)  {  	return state->crtc && state->crtc->state->active;  } @@ -1667,7 +1702,7 @@ bool plane_crtc_active(struct drm_plane_state *state)   * drm_atomic_helper_commit_planes - commit plane state   * @dev: DRM device   * @old_state: atomic state object with old state structures - * @active_only: Only commit on active CRTC if set + * @flags: flags for committing plane state   *   * This function commits the new plane state using the plane and atomic helper   * functions for planes and crtcs. It assumes that the atomic state has already @@ -1687,25 +1722,34 @@ bool plane_crtc_active(struct drm_plane_state *state)   * most drivers don't need to be immediately notified of plane updates for a   * disabled CRTC.   * - * Unless otherwise needed, drivers are advised to set the @active_only - * parameters to true in order not to receive plane update notifications related - * to a disabled CRTC. This avoids the need to manually ignore plane updates in + * Unless otherwise needed, drivers are advised to set the ACTIVE_ONLY flag in + * @flags in order not to receive plane update notifications related to a + * disabled CRTC. This avoids the need to manually ignore plane updates in   * driver code when the driver and/or hardware can't or just don't need to deal   * with updates on disabled CRTCs, for example when supporting runtime PM.   * - * The drm_atomic_helper_commit() default implementation only sets @active_only - * to false to most closely match the behaviour of the legacy helpers. This should - * not be copied blindly by drivers. + * Drivers may set the NO_DISABLE_AFTER_MODESET flag in @flags if the relevant + * display controllers require to disable a CRTC's planes when the CRTC is + * disabled. This function would skip the ->atomic_disable call for a plane if + * the CRTC of the old plane state needs a modesetting operation. Of course, + * the drivers need to disable the planes in their CRTC disable callbacks + * since no one else would do that. + * + * The drm_atomic_helper_commit() default implementation doesn't set the + * ACTIVE_ONLY flag to most closely match the behaviour of the legacy helpers. + * This should not be copied blindly by drivers.   */  void drm_atomic_helper_commit_planes(struct drm_device *dev,  				     struct drm_atomic_state *old_state, -				     bool active_only) +				     uint32_t flags)  {  	struct drm_crtc *crtc;  	struct drm_crtc_state *old_crtc_state;  	struct drm_plane *plane;  	struct drm_plane_state *old_plane_state;  	int i; +	bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY; +	bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET;  	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs; @@ -1749,10 +1793,19 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  		/*  		 * Special-case disabling the plane if drivers support it.  		 */ -		if (disabling && funcs->atomic_disable) +		if (disabling && funcs->atomic_disable) { +			struct drm_crtc_state *crtc_state; + +			crtc_state = old_plane_state->crtc->state; + +			if (drm_atomic_crtc_needs_modeset(crtc_state) && +			    no_disable) +				continue; +  			funcs->atomic_disable(plane, old_plane_state); -		else if (plane->state->crtc || disabling) +		} else if (plane->state->crtc || disabling) {  			funcs->atomic_update(plane, old_plane_state); +		}  	}  	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { @@ -1831,12 +1884,12 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);  /**   * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes - * @crtc: CRTC + * @old_crtc_state: atomic state object with the old CRTC state   * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks   *   * Disables all planes associated with the given CRTC. This can be - * used for instance in the CRTC helper disable callback to disable - * all planes before shutting down the display pipeline. + * used for instance in the CRTC helper atomic_disable callback to disable + * all planes.   *   * If the atomic-parameter is set the function calls the CRTC's   * atomic_begin hook before and atomic_flush hook after disabling the @@ -1845,9 +1898,11 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);   * It is a bug to call this function without having implemented the   * ->atomic_disable() plane hook.   */ -void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, -					      bool atomic) +void +drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state, +					 bool atomic)  { +	struct drm_crtc *crtc = old_crtc_state->crtc;  	const struct drm_crtc_helper_funcs *crtc_funcs =  		crtc->helper_private;  	struct drm_plane *plane; @@ -1855,11 +1910,11 @@ void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,  	if (atomic && crtc_funcs && crtc_funcs->atomic_begin)  		crtc_funcs->atomic_begin(crtc, NULL); -	drm_for_each_plane(plane, crtc->dev) { +	drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {  		const struct drm_plane_helper_funcs *plane_funcs =  			plane->helper_private; -		if (plane->state->crtc != crtc || !plane_funcs) +		if (!plane_funcs)  			continue;  		WARN_ON(!plane_funcs->atomic_disable); @@ -1894,6 +1949,9 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,  	for_each_plane_in_state(old_state, plane, plane_state, i) {  		const struct drm_plane_helper_funcs *funcs; +		if (!drm_atomic_helper_framebuffer_changed(dev, old_state, plane_state->crtc)) +			continue; +  		funcs = plane->helper_private;  		if (funcs->cleanup_fb) @@ -2354,7 +2412,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,  	primary_state->crtc_h = vdisplay;  	primary_state->src_x = set->x << 16;  	primary_state->src_y = set->y << 16; -	if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { +	if (primary_state->rotation & (DRM_ROTATE_90 | DRM_ROTATE_270)) {  		primary_state->src_w = vdisplay << 16;  		primary_state->src_h = hdisplay << 16;  	} else { @@ -3039,7 +3097,7 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)  	if (plane->state) {  		plane->state->plane = plane; -		plane->state->rotation = BIT(DRM_ROTATE_0); +		plane->state->rotation = DRM_ROTATE_0;  	}  }  EXPORT_SYMBOL(drm_atomic_helper_plane_reset);  |