28,6 → 28,7 |
|
#include <drm/drmP.h> |
#include <drm/drm_atomic.h> |
#include <drm/drm_mode.h> |
#include <drm/drm_plane_helper.h> |
|
/** |
353,6 → 354,8 |
drm_property_unreference_blob(state->mode_blob); |
state->mode_blob = NULL; |
|
memset(&state->mode, 0, sizeof(state->mode)); |
|
if (blob) { |
if (blob->length != sizeof(struct drm_mode_modeinfo) || |
drm_mode_convert_umode(&state->mode, |
365,7 → 368,6 |
DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", |
state->mode.name, state); |
} else { |
memset(&state->mode, 0, sizeof(state->mode)); |
state->enable = false; |
DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", |
state); |
376,6 → 378,58 |
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 → 451,7 |
{ |
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 → 462,31 |
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 → 522,12 |
*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 |
1204,14 → 1288,39 |
*/ |
void drm_atomic_legacy_backoff(struct drm_atomic_state *state) |
{ |
struct drm_device *dev = state->dev; |
unsigned crtc_mask = 0; |
struct drm_crtc *crtc; |
int ret; |
bool global = false; |
|
drm_for_each_crtc(crtc, dev) { |
if (crtc->acquire_ctx != state->acquire_ctx) |
continue; |
|
crtc_mask |= drm_crtc_mask(crtc); |
crtc->acquire_ctx = NULL; |
} |
|
if (WARN_ON(dev->mode_config.acquire_ctx == state->acquire_ctx)) { |
global = true; |
|
dev->mode_config.acquire_ctx = NULL; |
} |
|
retry: |
drm_modeset_backoff(state->acquire_ctx); |
|
ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx); |
ret = drm_modeset_lock_all_ctx(dev, state->acquire_ctx); |
if (ret) |
goto retry; |
|
drm_for_each_crtc(crtc, dev) |
if (drm_crtc_mask(crtc) & crtc_mask) |
crtc->acquire_ctx = state->acquire_ctx; |
|
if (global) |
dev->mode_config.acquire_ctx = state->acquire_ctx; |
} |
EXPORT_SYMBOL(drm_atomic_legacy_backoff); |
|
1343,44 → 1452,23 |
struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) |
{ |
struct drm_pending_vblank_event *e = NULL; |
unsigned long flags; |
int ret; |
|
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); |
|
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; |
ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); |
if (ret) { |
kfree(e); |
return NULL; |
} |
|
static void destroy_vblank_event(struct drm_device *dev, |
struct drm_file *file_priv, struct drm_pending_vblank_event *e) |
{ |
unsigned long flags; |
|
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, |