diff options
Diffstat (limited to 'drivers/gpu/drm/drm_plane.c')
| -rw-r--r-- | drivers/gpu/drm/drm_plane.c | 169 | 
1 files changed, 121 insertions, 48 deletions
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 035054455301..6153cbda239f 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -177,6 +177,10 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,  	if (WARN_ON(config->num_total_plane >= 32))  		return -EINVAL; +	WARN_ON(drm_drv_uses_atomic_modeset(dev) && +		(!funcs->atomic_destroy_state || +		 !funcs->atomic_duplicate_state)); +  	ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);  	if (ret)  		return ret; @@ -561,19 +565,66 @@ int drm_plane_check_pixel_format(struct drm_plane *plane,  	if (i == plane->format_count)  		return -EINVAL; -	if (!plane->modifier_count) -		return 0; +	if (plane->funcs->format_mod_supported) { +		if (!plane->funcs->format_mod_supported(plane, format, modifier)) +			return -EINVAL; +	} else { +		if (!plane->modifier_count) +			return 0; -	for (i = 0; i < plane->modifier_count; i++) { -		if (modifier == plane->modifiers[i]) -			break; +		for (i = 0; i < plane->modifier_count; i++) { +			if (modifier == plane->modifiers[i]) +				break; +		} +		if (i == plane->modifier_count) +			return -EINVAL;  	} -	if (i == plane->modifier_count) -		return -EINVAL; -	if (plane->funcs->format_mod_supported && -	    !plane->funcs->format_mod_supported(plane, format, modifier)) +	return 0; +} + +static int __setplane_check(struct drm_plane *plane, +			    struct drm_crtc *crtc, +			    struct drm_framebuffer *fb, +			    int32_t crtc_x, int32_t crtc_y, +			    uint32_t crtc_w, uint32_t crtc_h, +			    uint32_t src_x, uint32_t src_y, +			    uint32_t src_w, uint32_t src_h) +{ +	int ret; + +	/* Check whether this plane is usable on this CRTC */ +	if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { +		DRM_DEBUG_KMS("Invalid crtc for plane\n");  		return -EINVAL; +	} + +	/* Check whether this plane supports the fb pixel format. */ +	ret = drm_plane_check_pixel_format(plane, fb->format->format, +					   fb->modifier); +	if (ret) { +		struct drm_format_name_buf format_name; + +		DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", +			      drm_get_format_name(fb->format->format, +						  &format_name), +			      fb->modifier); +		return ret; +	} + +	/* Give drivers some help against integer overflows */ +	if (crtc_w > INT_MAX || +	    crtc_x > INT_MAX - (int32_t) crtc_w || +	    crtc_h > INT_MAX || +	    crtc_y > INT_MAX - (int32_t) crtc_h) { +		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", +			      crtc_w, crtc_h, crtc_x, crtc_y); +		return -ERANGE; +	} + +	ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); +	if (ret) +		return ret;  	return 0;  } @@ -598,6 +649,8 @@ static int __setplane_internal(struct drm_plane *plane,  {  	int ret = 0; +	WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); +  	/* No fb means shut it down */  	if (!fb) {  		plane->old_fb = plane->fb; @@ -611,37 +664,9 @@ static int __setplane_internal(struct drm_plane *plane,  		goto out;  	} -	/* Check whether this plane is usable on this CRTC */ -	if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { -		DRM_DEBUG_KMS("Invalid crtc for plane\n"); -		ret = -EINVAL; -		goto out; -	} - -	/* Check whether this plane supports the fb pixel format. */ -	ret = drm_plane_check_pixel_format(plane, fb->format->format, -					   fb->modifier); -	if (ret) { -		struct drm_format_name_buf format_name; -		DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", -			      drm_get_format_name(fb->format->format, -						  &format_name), -			      fb->modifier); -		goto out; -	} - -	/* Give drivers some help against integer overflows */ -	if (crtc_w > INT_MAX || -	    crtc_x > INT_MAX - (int32_t) crtc_w || -	    crtc_h > INT_MAX || -	    crtc_y > INT_MAX - (int32_t) crtc_h) { -		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", -			      crtc_w, crtc_h, crtc_x, crtc_y); -		ret = -ERANGE; -		goto out; -	} - -	ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); +	ret = __setplane_check(plane, crtc, fb, +			       crtc_x, crtc_y, crtc_w, crtc_h, +			       src_x, src_y, src_w, src_h);  	if (ret)  		goto out; @@ -665,6 +690,41 @@ out:  	return ret;  } +static int __setplane_atomic(struct drm_plane *plane, +			     struct drm_crtc *crtc, +			     struct drm_framebuffer *fb, +			     int32_t crtc_x, int32_t crtc_y, +			     uint32_t crtc_w, uint32_t crtc_h, +			     uint32_t src_x, uint32_t src_y, +			     uint32_t src_w, uint32_t src_h, +			     struct drm_modeset_acquire_ctx *ctx) +{ +	int ret; + +	WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev)); + +	/* No fb means shut it down */ +	if (!fb) +		return plane->funcs->disable_plane(plane, ctx); + +	/* +	 * FIXME: This is redundant with drm_atomic_plane_check(), +	 * but the legacy cursor/"async" .update_plane() tricks +	 * don't call that so we still need this here. Should remove +	 * this when all .update_plane() implementations have been +	 * fixed to call drm_atomic_plane_check(). +	 */ +	ret = __setplane_check(plane, crtc, fb, +			       crtc_x, crtc_y, crtc_w, crtc_h, +			       src_x, src_y, src_w, src_h); +	if (ret) +		return ret; + +	return plane->funcs->update_plane(plane, crtc, fb, +					  crtc_x, crtc_y, crtc_w, crtc_h, +					  src_x, src_y, src_w, src_h, ctx); +} +  static int setplane_internal(struct drm_plane *plane,  			     struct drm_crtc *crtc,  			     struct drm_framebuffer *fb, @@ -682,9 +742,15 @@ retry:  	ret = drm_modeset_lock_all_ctx(plane->dev, &ctx);  	if (ret)  		goto fail; -	ret = __setplane_internal(plane, crtc, fb, -				  crtc_x, crtc_y, crtc_w, crtc_h, -				  src_x, src_y, src_w, src_h, &ctx); + +	if (drm_drv_uses_atomic_modeset(plane->dev)) +		ret = __setplane_atomic(plane, crtc, fb, +					crtc_x, crtc_y, crtc_w, crtc_h, +					src_x, src_y, src_w, src_h, &ctx); +	else +		ret = __setplane_internal(plane, crtc, fb, +					  crtc_x, crtc_y, crtc_w, crtc_h, +					  src_x, src_y, src_w, src_h, &ctx);  fail:  	if (ret == -EDEADLK) { @@ -816,9 +882,14 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,  		src_h = fb->height << 16;  	} -	ret = __setplane_internal(plane, crtc, fb, -				  crtc_x, crtc_y, crtc_w, crtc_h, -				  0, 0, src_w, src_h, ctx); +	if (drm_drv_uses_atomic_modeset(dev)) +		ret = __setplane_atomic(plane, crtc, fb, +					crtc_x, crtc_y, crtc_w, crtc_h, +					0, 0, src_w, src_h, ctx); +	else +		ret = __setplane_internal(plane, crtc, fb, +					  crtc_x, crtc_y, crtc_w, crtc_h, +					  0, 0, src_w, src_h, ctx);  	if (fb)  		drm_framebuffer_put(fb); @@ -1092,8 +1163,10 @@ retry:  		/* Keep the old fb, don't unref it. */  		plane->old_fb = NULL;  	} else { -		plane->fb = fb; -		drm_framebuffer_get(fb); +		if (!plane->state) { +			plane->fb = fb; +			drm_framebuffer_get(fb); +		}  	}  out:  |