diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic.c')
| -rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 131 | 
1 files changed, 96 insertions, 35 deletions
| diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9a7b44616b55..8ee1db866e80 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -28,6 +28,7 @@  #include <drm/drmP.h>  #include <drm/drm_atomic.h> +#include <drm/drm_mode.h>  #include <drm/drm_plane_helper.h>  /** @@ -376,6 +377,58 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,  EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);  /** + * drm_atomic_replace_property_blob - replace a blob property + * @blob: a pointer to the member blob to be replaced + * @new_blob: the new blob to replace with + * @replaced: whether the blob has been replaced + * + * RETURNS: + * Zero on success, error code on failure + */ +static void +drm_atomic_replace_property_blob(struct drm_property_blob **blob, +				 struct drm_property_blob *new_blob, +				 bool *replaced) +{ +	struct drm_property_blob *old_blob = *blob; + +	if (old_blob == new_blob) +		return; + +	if (old_blob) +		drm_property_unreference_blob(old_blob); +	if (new_blob) +		drm_property_reference_blob(new_blob); +	*blob = new_blob; +	*replaced = true; + +	return; +} + +static int +drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc, +					 struct drm_property_blob **blob, +					 uint64_t blob_id, +					 ssize_t expected_size, +					 bool *replaced) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_property_blob *new_blob = NULL; + +	if (blob_id != 0) { +		new_blob = drm_property_lookup_blob(dev, blob_id); +		if (new_blob == NULL) +			return -EINVAL; +		if (expected_size > 0 && expected_size != new_blob->length) +			return -EINVAL; +	} + +	drm_atomic_replace_property_blob(blob, new_blob, replaced); + +	return 0; +} + +/**   * drm_atomic_crtc_set_property - set property on CRTC   * @crtc: the drm CRTC to set a property on   * @state: the state object to update with the new property value @@ -397,6 +450,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,  {  	struct drm_device *dev = crtc->dev;  	struct drm_mode_config *config = &dev->mode_config; +	bool replaced = false;  	int ret;  	if (property == config->prop_active) @@ -407,8 +461,31 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,  		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);  		drm_property_unreference_blob(mode);  		return ret; -	} -	else if (crtc->funcs->atomic_set_property) +	} else if (property == config->degamma_lut_property) { +		ret = drm_atomic_replace_property_blob_from_id(crtc, +					&state->degamma_lut, +					val, +					-1, +					&replaced); +		state->color_mgmt_changed = replaced; +		return ret; +	} else if (property == config->ctm_property) { +		ret = drm_atomic_replace_property_blob_from_id(crtc, +					&state->ctm, +					val, +					sizeof(struct drm_color_ctm), +					&replaced); +		state->color_mgmt_changed = replaced; +		return ret; +	} else if (property == config->gamma_lut_property) { +		ret = drm_atomic_replace_property_blob_from_id(crtc, +					&state->gamma_lut, +					val, +					-1, +					&replaced); +		state->color_mgmt_changed = replaced; +		return ret; +	} else if (crtc->funcs->atomic_set_property)  		return crtc->funcs->atomic_set_property(crtc, state, property, val);  	else  		return -EINVAL; @@ -444,6 +521,12 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,  		*val = state->active;  	else if (property == config->prop_mode_id)  		*val = (state->mode_blob) ? state->mode_blob->base.id : 0; +	else if (property == config->degamma_lut_property) +		*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; +	else if (property == config->ctm_property) +		*val = (state->ctm) ? state->ctm->base.id : 0; +	else if (property == config->gamma_lut_property) +		*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;  	else if (crtc->funcs->atomic_get_property)  		return crtc->funcs->atomic_get_property(crtc, state, property, val);  	else @@ -1343,44 +1426,23 @@ static struct drm_pending_vblank_event *create_vblank_event(  		struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)  {  	struct drm_pending_vblank_event *e = NULL; -	unsigned long flags; - -	spin_lock_irqsave(&dev->event_lock, flags); -	if (file_priv->event_space < sizeof e->event) { -		spin_unlock_irqrestore(&dev->event_lock, flags); -		goto out; -	} -	file_priv->event_space -= sizeof e->event; -	spin_unlock_irqrestore(&dev->event_lock, flags); +	int ret;  	e = kzalloc(sizeof *e, GFP_KERNEL); -	if (e == NULL) { -		spin_lock_irqsave(&dev->event_lock, flags); -		file_priv->event_space += sizeof e->event; -		spin_unlock_irqrestore(&dev->event_lock, flags); -		goto out; -	} +	if (!e) +		return NULL;  	e->event.base.type = DRM_EVENT_FLIP_COMPLETE; -	e->event.base.length = sizeof e->event; +	e->event.base.length = sizeof(e->event);  	e->event.user_data = user_data; -	e->base.event = &e->event.base; -	e->base.file_priv = file_priv; -	e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; - -out: -	return e; -} -static void destroy_vblank_event(struct drm_device *dev, -		struct drm_file *file_priv, struct drm_pending_vblank_event *e) -{ -	unsigned long flags; +	ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); +	if (ret) { +		kfree(e); +		return NULL; +	} -	spin_lock_irqsave(&dev->event_lock, flags); -	file_priv->event_space += sizeof e->event; -	spin_unlock_irqrestore(&dev->event_lock, flags); -	kfree(e); +	return e;  }  static int atomic_set_prop(struct drm_atomic_state *state, @@ -1642,8 +1704,7 @@ out:  			if (!crtc_state->event)  				continue; -			destroy_vblank_event(dev, file_priv, -					     crtc_state->event); +			drm_event_cancel_free(dev, &crtc_state->event->base);  		}  	} | 
