Commit 21773f16 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/atomic-core-2015-01-27' of git://anongit.freedesktop.org/drm-intel into drm-next

* tag 'topic/atomic-core-2015-01-27' of git://anongit.freedesktop.org/drm-intel:
  drm/atomic: Fix potential use of state after free
  drm/atomic-helper: debug output for modesets
  drm/atomic-helpers: Saner encoder/crtc callbacks
  drm/atomic-helpers: Recover full cursor plane behaviour
  drm/atomic-helper: add connector->dpms() implementation
  drm/atomic: Add drm_crtc_state->active
  drm: Add standardized boolean props
  drm/plane-helper: Fix transitional helper kerneldocs
  drm/plane-helper: Skip prepare_fb/cleanup_fb when newfb==oldfb

Conflicts:
	include/drm/drm_crtc_helper.h
parents 2f5b4ef1 9469244d
...@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
connector->funcs->atomic_destroy_state(connector, connector->funcs->atomic_destroy_state(connector,
state->connector_states[i]); state->connector_states[i]);
state->connector_states[i] = NULL;
} }
for (i = 0; i < config->num_crtc; i++) { for (i = 0; i < config->num_crtc; i++) {
...@@ -144,6 +145,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -144,6 +145,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
crtc->funcs->atomic_destroy_state(crtc, crtc->funcs->atomic_destroy_state(crtc,
state->crtc_states[i]); state->crtc_states[i]);
state->crtc_states[i] = NULL;
} }
for (i = 0; i < config->num_total_plane; i++) { for (i = 0; i < config->num_total_plane; i++) {
...@@ -154,6 +156,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) ...@@ -154,6 +156,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
plane->funcs->atomic_destroy_state(plane, plane->funcs->atomic_destroy_state(plane,
state->plane_states[i]); state->plane_states[i]);
state->plane_states[i] = NULL;
} }
} }
EXPORT_SYMBOL(drm_atomic_state_clear); EXPORT_SYMBOL(drm_atomic_state_clear);
...@@ -241,7 +244,13 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ...@@ -241,7 +244,13 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
struct drm_crtc_state *state, struct drm_property *property, struct drm_crtc_state *state, struct drm_property *property,
uint64_t val) uint64_t val)
{ {
if (crtc->funcs->atomic_set_property) struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
/* FIXME: Mode prop is missing, which also controls ->enable. */
if (property == config->prop_active) {
state->active = val;
} else if (crtc->funcs->atomic_set_property)
return crtc->funcs->atomic_set_property(crtc, state, property, val); return crtc->funcs->atomic_set_property(crtc, state, property, val);
return -EINVAL; return -EINVAL;
} }
...@@ -282,6 +291,13 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, ...@@ -282,6 +291,13 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
* *
* TODO: Add generic modeset state checks once we support those. * TODO: Add generic modeset state checks once we support those.
*/ */
if (state->active && !state->enable) {
DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n",
crtc->base.id);
return -EINVAL;
}
return 0; return 0;
} }
...@@ -978,7 +994,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ...@@ -978,7 +994,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
if (!crtc) if (!crtc)
continue; continue;
if (crtc_state->mode_changed) { if (crtc_state->mode_changed ||
crtc_state->active_changed) {
DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n",
crtc->base.id); crtc->base.id);
return -EINVAL; return -EINVAL;
......
...@@ -339,6 +339,12 @@ mode_fixup(struct drm_atomic_state *state) ...@@ -339,6 +339,12 @@ mode_fixup(struct drm_atomic_state *state)
return 0; return 0;
} }
static bool
needs_modeset(struct drm_crtc_state *state)
{
return state->mode_changed || state->active_changed;
}
/** /**
* drm_atomic_helper_check - validate state object for modeset changes * drm_atomic_helper_check - validate state object for modeset changes
* @dev: DRM device * @dev: DRM device
...@@ -413,12 +419,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, ...@@ -413,12 +419,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
crtc = state->crtcs[i]; crtc = state->crtcs[i];
crtc_state = state->crtc_states[i]; crtc_state = state->crtc_states[i];
if (!crtc || !crtc_state->mode_changed) if (!crtc)
continue; continue;
DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n", /*
* We must set ->active_changed after walking connectors for
* otherwise an update that only changes active would result in
* a full modeset because update_connector_routing force that.
*/
if (crtc->state->active != crtc_state->active) {
DRM_DEBUG_KMS("[CRTC:%d] active changed\n",
crtc->base.id);
crtc_state->active_changed = true;
}
if (!needs_modeset(crtc_state))
continue;
DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
crtc->base.id, crtc->base.id,
crtc_state->enable ? 'y' : 'n'); crtc_state->enable ? 'y' : 'n',
crtc_state->active ? 'y' : 'n');
ret = drm_atomic_add_affected_connectors(state, crtc); ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret != 0) if (ret != 0)
...@@ -554,6 +575,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -554,6 +575,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder_helper_funcs *funcs; struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_crtc_state *old_crtc_state;
old_conn_state = old_state->connector_states[i]; old_conn_state = old_state->connector_states[i];
connector = old_state->connectors[i]; connector = old_state->connectors[i];
...@@ -563,6 +585,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -563,6 +585,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
if (!old_conn_state || !old_conn_state->crtc) if (!old_conn_state || !old_conn_state->crtc)
continue; continue;
old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
if (!old_crtc_state->active)
continue;
encoder = old_conn_state->best_encoder; encoder = old_conn_state->best_encoder;
/* We shouldn't get this far if we didn't previously have /* We shouldn't get this far if we didn't previously have
...@@ -573,6 +600,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -573,6 +600,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs = encoder->helper_private; funcs = encoder->helper_private;
DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n",
encoder->base.id, encoder->name);
/* /*
* Each encoder has at most one connector (since we always steal * Each encoder has at most one connector (since we always steal
* it away), so we won't call call disable hooks twice. * it away), so we won't call call disable hooks twice.
...@@ -581,7 +611,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -581,7 +611,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
encoder->bridge->funcs->disable(encoder->bridge); encoder->bridge->funcs->disable(encoder->bridge);
/* Right function depends upon target state. */ /* Right function depends upon target state. */
if (connector->state->crtc) if (connector->state->crtc && funcs->prepare)
funcs->prepare(encoder); funcs->prepare(encoder);
else if (funcs->disable) else if (funcs->disable)
funcs->disable(encoder); funcs->disable(encoder);
...@@ -595,17 +625,26 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -595,17 +625,26 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
for (i = 0; i < ncrtcs; i++) { for (i = 0; i < ncrtcs; i++) {
struct drm_crtc_helper_funcs *funcs; struct drm_crtc_helper_funcs *funcs;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
crtc = old_state->crtcs[i]; crtc = old_state->crtcs[i];
old_crtc_state = old_state->crtc_states[i];
/* Shut down everything that needs a full modeset. */ /* Shut down everything that needs a full modeset. */
if (!crtc || !crtc->state->mode_changed) if (!crtc || !needs_modeset(crtc->state))
continue;
if (!old_crtc_state->active)
continue; continue;
funcs = crtc->helper_private; funcs = crtc->helper_private;
DRM_DEBUG_KMS("disabling [CRTC:%d]\n",
crtc->base.id);
/* Right function depends upon target state. */ /* Right function depends upon target state. */
if (crtc->state->enable) if (crtc->state->enable && funcs->prepare)
funcs->prepare(crtc); funcs->prepare(crtc);
else if (funcs->disable) else if (funcs->disable)
funcs->disable(crtc); funcs->disable(crtc);
...@@ -684,9 +723,13 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -684,9 +723,13 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs = crtc->helper_private; funcs = crtc->helper_private;
if (crtc->state->enable) if (crtc->state->enable) {
DRM_DEBUG_KMS("modeset on [CRTC:%d]\n",
crtc->base.id);
funcs->mode_set_nofb(crtc); funcs->mode_set_nofb(crtc);
} }
}
for (i = 0; i < old_state->num_connector; i++) { for (i = 0; i < old_state->num_connector; i++) {
struct drm_connector *connector; struct drm_connector *connector;
...@@ -706,6 +749,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) ...@@ -706,6 +749,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
mode = &new_crtc_state->mode; mode = &new_crtc_state->mode;
adjusted_mode = &new_crtc_state->adjusted_mode; adjusted_mode = &new_crtc_state->adjusted_mode;
if (!new_crtc_state->mode_changed)
continue;
DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n",
encoder->base.id, encoder->name);
/* /*
* Each encoder has at most one connector (since we always steal * Each encoder has at most one connector (since we always steal
* it away), so we won't call call mode_set hooks twice. * it away), so we won't call call mode_set hooks twice.
...@@ -758,14 +807,24 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, ...@@ -758,14 +807,24 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
crtc = old_state->crtcs[i]; crtc = old_state->crtcs[i];
/* Need to filter out CRTCs where only planes change. */ /* Need to filter out CRTCs where only planes change. */
if (!crtc || !crtc->state->mode_changed) if (!crtc || !needs_modeset(crtc->state))
continue;
if (!crtc->state->active)
continue; continue;
funcs = crtc->helper_private; funcs = crtc->helper_private;
if (crtc->state->enable) if (crtc->state->enable) {
DRM_DEBUG_KMS("enabling [CRTC:%d]\n",
crtc->base.id);
if (funcs->enable)
funcs->enable(crtc);
else
funcs->commit(crtc); funcs->commit(crtc);
} }
}
for (i = 0; i < old_state->num_connector; i++) { for (i = 0; i < old_state->num_connector; i++) {
struct drm_connector *connector; struct drm_connector *connector;
...@@ -777,9 +836,15 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, ...@@ -777,9 +836,15 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
if (!connector || !connector->state->best_encoder) if (!connector || !connector->state->best_encoder)
continue; continue;
if (!connector->state->crtc->state->active)
continue;
encoder = connector->state->best_encoder; encoder = connector->state->best_encoder;
funcs = encoder->helper_private; funcs = encoder->helper_private;
DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n",
encoder->base.id, encoder->name);
/* /*
* Each encoder has at most one connector (since we always steal * Each encoder has at most one connector (since we always steal
* it away), so we won't call call enable hooks twice. * it away), so we won't call call enable hooks twice.
...@@ -787,6 +852,9 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, ...@@ -787,6 +852,9 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
if (encoder->bridge) if (encoder->bridge)
encoder->bridge->funcs->pre_enable(encoder->bridge); encoder->bridge->funcs->pre_enable(encoder->bridge);
if (funcs->enable)
funcs->enable(encoder);
else
funcs->commit(encoder); funcs->commit(encoder);
if (encoder->bridge) if (encoder->bridge)
...@@ -877,6 +945,11 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, ...@@ -877,6 +945,11 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
if (!crtc->state->enable) if (!crtc->state->enable)
continue; continue;
/* Legacy cursor ioctls are completely unsynced, and userspace
* relies on that (by doing tons of cursor updates). */
if (old_state->legacy_cursor_update)
continue;
if (!framebuffer_changed(dev, old_state, crtc)) if (!framebuffer_changed(dev, old_state, crtc))
continue; continue;
...@@ -1310,6 +1383,9 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, ...@@ -1310,6 +1383,9 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
if (ret != 0) if (ret != 0)
goto fail; goto fail;
if (plane == crtc->cursor)
state->legacy_cursor_update = true;
/* Driver takes ownership of state on successful commit. */ /* Driver takes ownership of state on successful commit. */
return 0; return 0;
fail: fail:
...@@ -1385,6 +1461,9 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane) ...@@ -1385,6 +1461,9 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
plane_state->src_h = 0; plane_state->src_h = 0;
plane_state->src_w = 0; plane_state->src_w = 0;
if (plane == plane->crtc->cursor)
state->legacy_cursor_update = true;
ret = drm_atomic_commit(state); ret = drm_atomic_commit(state);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
...@@ -1534,6 +1613,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) ...@@ -1534,6 +1613,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
WARN_ON(set->num_connectors); WARN_ON(set->num_connectors);
crtc_state->enable = false; crtc_state->enable = false;
crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
if (ret != 0) if (ret != 0)
...@@ -1548,6 +1628,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) ...@@ -1548,6 +1628,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
WARN_ON(!set->num_connectors); WARN_ON(!set->num_connectors);
crtc_state->enable = true; crtc_state->enable = true;
crtc_state->active = true;
drm_mode_copy(&crtc_state->mode, set->mode); drm_mode_copy(&crtc_state->mode, set->mode);
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
...@@ -1859,6 +1940,83 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, ...@@ -1859,6 +1940,83 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
} }
EXPORT_SYMBOL(drm_atomic_helper_page_flip); EXPORT_SYMBOL(drm_atomic_helper_page_flip);
/**
* drm_atomic_helper_connector_dpms() - connector dpms helper implementation
* @connector: affected connector
* @mode: DPMS mode
*
* This is the main helper function provided by the atomic helper framework for
* implementing the legacy DPMS connector interface. It computes the new desired
* ->active state for the corresponding CRTC (if the connector is enabled) and
* updates it.
*/
void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
int mode)
{
struct drm_mode_config *config = &connector->dev->mode_config;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
struct drm_connector *tmp_connector;
int ret;
bool active = false;
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
connector->dpms = mode;
crtc = connector->state->crtc;
if (!crtc)
return;
/* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */
state = drm_atomic_state_alloc(connector->dev);
if (!state)
return;
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
retry:
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state))
return;
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
list_for_each_entry(tmp_connector, &config->connector_list, head) {
if (connector->state->crtc != crtc)
continue;
if (connector->dpms == DRM_MODE_DPMS_ON) {
active = true;
break;
}
}
crtc_state->active = active;
ret = drm_atomic_commit(state);
if (ret != 0)
goto fail;
/* Driver takes ownership of state on successful async commit. */
return;
fail:
if (ret == -EDEADLK)
goto backoff;
drm_atomic_state_free(state);
WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret);
return;
backoff:
drm_atomic_state_clear(state);
drm_atomic_legacy_backoff(state);
goto retry;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
/** /**
* DOC: atomic state reset and initialization * DOC: atomic state reset and initialization
* *
...@@ -1910,6 +2068,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) ...@@ -1910,6 +2068,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
if (state) { if (state) {
state->mode_changed = false; state->mode_changed = false;
state->active_changed = false;
state->planes_changed = false; state->planes_changed = false;
state->event = NULL; state->event = NULL;
} }
......
...@@ -691,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, ...@@ -691,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
if (cursor) if (cursor)
cursor->possible_crtcs = 1 << drm_crtc_index(crtc); cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
drm_object_attach_property(&crtc->base, config->prop_active, 0);
}
return 0; return 0;
} }
EXPORT_SYMBOL(drm_crtc_init_with_planes); EXPORT_SYMBOL(drm_crtc_init_with_planes);
...@@ -1481,6 +1485,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) ...@@ -1481,6 +1485,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
return -ENOMEM; return -ENOMEM;
dev->mode_config.prop_crtc_id = prop; dev->mode_config.prop_crtc_id = prop;
prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
"ACTIVE");
if (!prop)
return -ENOMEM;
dev->mode_config.prop_active = prop;
return 0; return 0;
} }
...@@ -3810,7 +3820,7 @@ static struct drm_property *property_create_range(struct drm_device *dev, ...@@ -3810,7 +3820,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
} }
/** /**
* drm_property_create_range - create a new ranged property type * drm_property_create_range - create a new unsigned ranged property type
* @dev: drm device * @dev: drm device
* @flags: flags specifying the property type * @flags: flags specifying the property type
* @name: name of the property * @name: name of the property
...@@ -3821,8 +3831,8 @@ static struct drm_property *property_create_range(struct drm_device *dev, ...@@ -3821,8 +3831,8 @@ static struct drm_property *property_create_range(struct drm_device *dev,
* object with drm_object_attach_property. The returned property object must be * object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy. * freed with drm_property_destroy.
* *
* Userspace is allowed to set any integer value in the (min, max) range * Userspace is allowed to set any unsigned integer value in the (min, max)
* inclusive. * range inclusive.
* *
* Returns: * Returns:
* A pointer to the newly created property on success, NULL on failure. * A pointer to the newly created property on success, NULL on failure.
...@@ -3836,6 +3846,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags ...@@ -3836,6 +3846,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
} }
EXPORT_SYMBOL(drm_property_create_range); EXPORT_SYMBOL(drm_property_create_range);
/**
* drm_property_create_signed_range - create a new signed ranged property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
* @min: minimum value of the property
* @max: maximum value of the property
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Userspace is allowed to set any signed integer value in the (min, max)
* range inclusive.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_signed_range(struct drm_device *dev, struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
int flags, const char *name, int flags, const char *name,
int64_t min, int64_t max) int64_t min, int64_t max)
...@@ -3845,6 +3873,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, ...@@ -3845,6 +3873,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
} }
EXPORT_SYMBOL(drm_property_create_signed_range); EXPORT_SYMBOL(drm_property_create_signed_range);
/**
* drm_property_create_object - create a new object property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
* @type: object type from DRM_MODE_OBJECT_* defines
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Userspace is only allowed to set this to any property value of the given
* @type. Only useful for atomic properties, which is enforced.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_object(struct drm_device *dev, struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name, uint32_t type) int flags, const char *name, uint32_t type)
{ {
...@@ -3852,6 +3897,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev, ...@@ -3852,6 +3897,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
flags |= DRM_MODE_PROP_OBJECT; flags |= DRM_MODE_PROP_OBJECT;
if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
return NULL;
property = drm_property_create(dev, flags, name, 1); property = drm_property_create(dev, flags, name, 1);
if (!property) if (!property)
return NULL; return NULL;
...@@ -3862,6 +3910,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev, ...@@ -3862,6 +3910,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
} }
EXPORT_SYMBOL(drm_property_create_object); EXPORT_SYMBOL(drm_property_create_object);
/**
* drm_property_create_bool - create a new boolean property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
*
* This creates a new generic drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* This is implemented as a ranged property with only {0, 1} as valid values.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
const char *name)
{
return drm_property_create_range(dev, flags, name, 0, 1);
}
EXPORT_SYMBOL(drm_property_create_bool);
/** /**
* drm_property_add_enum - add a possible value to an enumeration property * drm_property_add_enum - add a possible value to an enumeration property
* @property: enumeration property to change * @property: enumeration property to change
......
...@@ -435,7 +435,8 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -435,7 +435,8 @@ int drm_plane_helper_commit(struct drm_plane *plane,
goto out; goto out;
} }
if (plane_funcs->prepare_fb && plane_state->fb) { if (plane_funcs->prepare_fb && plane_state->fb &&
plane_state->fb != old_fb) {
ret = plane_funcs->prepare_fb(plane, plane_state->fb); ret = plane_funcs->prepare_fb(plane, plane_state->fb);
if (ret) if (ret)
goto out; goto out;
...@@ -464,6 +465,13 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -464,6 +465,13 @@ int drm_plane_helper_commit(struct drm_plane *plane,
crtc_funcs[i]->atomic_flush(crtc[i]); crtc_funcs[i]->atomic_flush(crtc[i]);
} }
/*
* If we only moved the plane and didn't change fb's, there's no need to
* wait for vblank.
*/
if (plane->state->fb == old_fb)
goto out;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (!crtc[i]) if (!crtc[i])
continue; continue;
...@@ -492,7 +500,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, ...@@ -492,7 +500,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
} }
/** /**
* drm_plane_helper_update() - Helper for primary plane update * drm_plane_helper_update() - Transitional helper for plane update
* @plane: plane object to update * @plane: plane object to update
* @crtc: owning CRTC of owning plane * @crtc: owning CRTC of owning plane
* @fb: framebuffer to flip onto plane * @fb: framebuffer to flip onto plane
...@@ -549,7 +557,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -549,7 +557,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
EXPORT_SYMBOL(drm_plane_helper_update); EXPORT_SYMBOL(drm_plane_helper_update);
/** /**
* drm_plane_helper_disable() - Helper for primary plane disable * drm_plane_helper_disable() - Transitional helper for plane disable
* @plane: plane to disable * @plane: plane to disable
* *
* Provides a default plane disable handler using the atomic plane update * Provides a default plane disable handler using the atomic plane update
......
...@@ -82,6 +82,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, ...@@ -82,6 +82,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb, struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event, struct drm_pending_vblank_event *event,
uint32_t flags); uint32_t flags);
void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
int mode);
/* default implementations for state handling */ /* default implementations for state handling */
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
......
...@@ -253,6 +253,7 @@ struct drm_atomic_state; ...@@ -253,6 +253,7 @@ struct drm_atomic_state;
* @enable: whether the CRTC should be enabled, gates all other state * @enable: whether the CRTC should be enabled, gates all other state
* @active: whether the CRTC is actively displaying (used for DPMS) * @active: whether the CRTC is actively displaying (used for DPMS)
* @mode_changed: for use by helpers and drivers when computing state updates * @mode_changed: for use by helpers and drivers when computing state updates
* @active_changed: for use by helpers and drivers when computing state updates
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
* @last_vblank_count: for helpers and drivers to capture the vblank of the * @last_vblank_count: for helpers and drivers to capture the vblank of the
* update to ensure framebuffer cleanup isn't done too early * update to ensure framebuffer cleanup isn't done too early
...@@ -278,6 +279,7 @@ struct drm_crtc_state { ...@@ -278,6 +279,7 @@ struct drm_crtc_state {
/* computed state bits used by helpers and drivers */ /* computed state bits used by helpers and drivers */
bool planes_changed : 1; bool planes_changed : 1;
bool mode_changed : 1; bool mode_changed : 1;
bool active_changed : 1;
/* attached planes bitmask: /* attached planes bitmask:
* WARNING: transitional helpers do not maintain plane_mask so * WARNING: transitional helpers do not maintain plane_mask so
...@@ -910,6 +912,7 @@ struct drm_bridge { ...@@ -910,6 +912,7 @@ struct drm_bridge {
* struct struct drm_atomic_state - the global state object for atomic updates * struct struct drm_atomic_state - the global state object for atomic updates
* @dev: parent DRM device * @dev: parent DRM device
* @allow_modeset: allow full modeset * @allow_modeset: allow full modeset
* @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
* @planes: pointer to array of plane pointers * @planes: pointer to array of plane pointers
* @plane_states: pointer to array of plane states pointers * @plane_states: pointer to array of plane states pointers
* @crtcs: pointer to array of CRTC pointers * @crtcs: pointer to array of CRTC pointers
...@@ -922,6 +925,7 @@ struct drm_bridge { ...@@ -922,6 +925,7 @@ struct drm_bridge {
struct drm_atomic_state { struct drm_atomic_state {
struct drm_device *dev; struct drm_device *dev;
bool allow_modeset : 1; bool allow_modeset : 1;
bool legacy_cursor_update : 1;
struct drm_plane **planes; struct drm_plane **planes;
struct drm_plane_state **plane_states; struct drm_plane_state **plane_states;
struct drm_crtc **crtcs; struct drm_crtc **crtcs;
...@@ -1117,6 +1121,7 @@ struct drm_mode_config { ...@@ -1117,6 +1121,7 @@ struct drm_mode_config {
struct drm_property *prop_crtc_h; struct drm_property *prop_crtc_h;
struct drm_property *prop_fb_id; struct drm_property *prop_fb_id;
struct drm_property *prop_crtc_id; struct drm_property *prop_crtc_id;
struct drm_property *prop_active;
/* DVI-I properties */ /* DVI-I properties */
struct drm_property *dvi_i_subconnector_property; struct drm_property *dvi_i_subconnector_property;
...@@ -1349,6 +1354,8 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, ...@@ -1349,6 +1354,8 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
int64_t min, int64_t max); int64_t min, int64_t max);
struct drm_property *drm_property_create_object(struct drm_device *dev, struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name, uint32_t type); int flags, const char *name, uint32_t type);
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
const char *name);
extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
extern int drm_property_add_enum(struct drm_property *property, int index, extern int drm_property_add_enum(struct drm_property *property, int index,
uint64_t value, const char *name); uint64_t value, const char *name);
......
...@@ -58,11 +58,19 @@ enum mode_set_atomic { ...@@ -58,11 +58,19 @@ enum mode_set_atomic {
* @mode_set_base_atomic: non-blocking mode set (used for kgdb support) * @mode_set_base_atomic: non-blocking mode set (used for kgdb support)
* @load_lut: load color palette * @load_lut: load color palette
* @disable: disable CRTC when no longer in use * @disable: disable CRTC when no longer in use
* @enable: enable CRTC
* @atomic_check: check for validity of an atomic state * @atomic_check: check for validity of an atomic state
* @atomic_begin: begin atomic update * @atomic_begin: begin atomic update
* @atomic_flush: flush atomic update * @atomic_flush: flush atomic update
* *
* The helper operations are called by the mid-layer CRTC helper. * The helper operations are called by the mid-layer CRTC helper.
*
* Note that with atomic helpers @dpms, @prepare and @commit hooks are
* deprecated. Used @enable and @disable instead exclusively.
*
* With legacy crtc helpers there's a big semantic difference between @disable
* and the other hooks: @disable also needs to release any resources acquired in
* @mode_set (like shared PLLs).
*/ */
struct drm_crtc_helper_funcs { struct drm_crtc_helper_funcs {
/* /*
...@@ -93,8 +101,8 @@ struct drm_crtc_helper_funcs { ...@@ -93,8 +101,8 @@ struct drm_crtc_helper_funcs {
/* reload the current crtc LUT */ /* reload the current crtc LUT */
void (*load_lut)(struct drm_crtc *crtc); void (*load_lut)(struct drm_crtc *crtc);
/* disable crtc when not in use - more explicit than dpms off */
void (*disable)(struct drm_crtc *crtc); void (*disable)(struct drm_crtc *crtc);
void (*enable)(struct drm_crtc *crtc);
/* atomic helpers */ /* atomic helpers */
int (*atomic_check)(struct drm_crtc *crtc, int (*atomic_check)(struct drm_crtc *crtc,
...@@ -115,9 +123,17 @@ struct drm_crtc_helper_funcs { ...@@ -115,9 +123,17 @@ struct drm_crtc_helper_funcs {
* @get_crtc: return CRTC that the encoder is currently attached to * @get_crtc: return CRTC that the encoder is currently attached to
* @detect: connection status detection * @detect: connection status detection
* @disable: disable encoder when not in use (overrides DPMS off) * @disable: disable encoder when not in use (overrides DPMS off)
* @enable: enable encoder
* @atomic_check: check for validity of an atomic update * @atomic_check: check for validity of an atomic update
* *
* The helper operations are called by the mid-layer CRTC helper. * The helper operations are called by the mid-layer CRTC helper.
*
* Note that with atomic helpers @dpms, @prepare and @commit hooks are
* deprecated. Used @enable and @disable instead exclusively.
*
* With legacy crtc helpers there's a big semantic difference between @disable
* and the other hooks: @disable also needs to release any resources acquired in
* @mode_set (like shared PLLs).
*/ */
struct drm_encoder_helper_funcs { struct drm_encoder_helper_funcs {
void (*dpms)(struct drm_encoder *encoder, int mode); void (*dpms)(struct drm_encoder *encoder, int mode);
...@@ -136,9 +152,10 @@ struct drm_encoder_helper_funcs { ...@@ -136,9 +152,10 @@ struct drm_encoder_helper_funcs {
/* detect for DAC style encoders */ /* detect for DAC style encoders */
enum drm_connector_status (*detect)(struct drm_encoder *encoder, enum drm_connector_status (*detect)(struct drm_encoder *encoder,
struct drm_connector *connector); struct drm_connector *connector);
/* disable encoder when not in use - more explicit than dpms off */
void (*disable)(struct drm_encoder *encoder); void (*disable)(struct drm_encoder *encoder);
void (*enable)(struct drm_encoder *encoder);
/* atomic helpers */ /* atomic helpers */
int (*atomic_check)(struct drm_encoder *encoder, int (*atomic_check)(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state, struct drm_crtc_state *crtc_state,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment