提交 9c37bf2d 编写于 作者: D Dave Airlie

Merge tag 'topic/drm-misc-2015-05-19' of git://anongit.freedesktop.org/drm-intel into drm-next

Scattering of random drm core patches. Bunch of atomic prep work too, but
the final bits for blob properties, atomic modesets and lifting the
experimental tag on the atomic ioctl are still blocked on Daniel Stone
finalizing and testing the weston support for it. I hope that we can get
it all ready for 4.2 though.

* tag 'topic/drm-misc-2015-05-19' of git://anongit.freedesktop.org/drm-intel: (22 commits)
  drm/atomic: Allow drivers to subclass drm_atomic_state, v3
  drm/atomic: remove duplicated assignment of old_plane_state
  drm/dp: Fix comment in DP helper
  drm/atomic: add drm_atomic_get_existing_*_state helpers
  drm/core: get rid of -Iinclude/drm
  drm/i915: get rid of -Iinclude/drm
  drm/atomic-helpers: Export drm_atomic_helper_update_legacy_modeset_state
  drm/atomic-helpers: Update vblank timestamping constants
  drm/sysfs: remove unnecessary connector type checks
  drm/sysfs: split DVI-I and TV-out attributes
  drm/sysfs: make optional attribute groups per connector type
  drm/sysfs: add a helper for extracting connector type from kobject
  drm/edid: Add CEA modes before inferred modes
  drm/prime: Allow internal imports without import_sg_table
  drm: Add reference counting to blob properties
  drm: Introduce blob_lock
  drm: Introduce helper for replacing blob properties
  drm: Don't leak path blob property when updating
  drm/atomic: Don't open-code CRTC state destroy
  drm/edid: Add DMT modes with ID > 0x50
  ...
......@@ -2,8 +2,6 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm
drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_context.o drm_dma.o \
drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
......
......@@ -30,7 +30,15 @@
#include <drm/drm_atomic.h>
#include <drm/drm_plane_helper.h>
static void kfree_state(struct drm_atomic_state *state)
/**
* drm_atomic_state_default_release -
* release memory initialized by drm_atomic_state_init
* @state: atomic state
*
* Free all the memory allocated by drm_atomic_state_init.
* This is useful for drivers that subclass the atomic state.
*/
void drm_atomic_state_default_release(struct drm_atomic_state *state)
{
kfree(state->connectors);
kfree(state->connector_states);
......@@ -38,24 +46,20 @@ static void kfree_state(struct drm_atomic_state *state)
kfree(state->crtc_states);
kfree(state->planes);
kfree(state->plane_states);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_state_default_release);
/**
* drm_atomic_state_alloc - allocate atomic state
* drm_atomic_state_init - init new atomic state
* @dev: DRM device
* @state: atomic state
*
* This allocates an empty atomic state to track updates.
* Default implementation for filling in a new atomic state.
* This is useful for drivers that subclass the atomic state.
*/
struct drm_atomic_state *
drm_atomic_state_alloc(struct drm_device *dev)
int
drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
{
struct drm_atomic_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
/* TODO legacy paths should maybe do a better job about
* setting this appropriately?
*/
......@@ -92,31 +96,50 @@ drm_atomic_state_alloc(struct drm_device *dev)
state->dev = dev;
DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state);
DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
return state;
return 0;
fail:
kfree_state(state);
drm_atomic_state_default_release(state);
return -ENOMEM;
}
EXPORT_SYMBOL(drm_atomic_state_init);
/**
* drm_atomic_state_alloc - allocate atomic state
* @dev: DRM device
*
* This allocates an empty atomic state to track updates.
*/
struct drm_atomic_state *
drm_atomic_state_alloc(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_atomic_state *state;
return NULL;
if (!config->funcs->atomic_state_alloc) {
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
if (drm_atomic_state_init(dev, state) < 0) {
kfree(state);
return NULL;
}
return state;
}
return config->funcs->atomic_state_alloc(dev);
}
EXPORT_SYMBOL(drm_atomic_state_alloc);
/**
* drm_atomic_state_clear - clear state object
* drm_atomic_state_default_clear - clear base atomic state
* @state: atomic state
*
* When the w/w mutex algorithm detects a deadlock we need to back off and drop
* all locks. So someone else could sneak in and change the current modeset
* configuration. Which means that all the state assembled in @state is no
* longer an atomic update to the current state, but to some arbitrary earlier
* state. Which could break assumptions the driver's ->atomic_check likely
* relies on.
*
* Hence we must clear all cached state and completely start over, using this
* function.
* Default implementation for clearing atomic state.
* This is useful for drivers that subclass the atomic state.
*/
void drm_atomic_state_clear(struct drm_atomic_state *state)
void drm_atomic_state_default_clear(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
......@@ -162,6 +185,32 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
state->plane_states[i] = NULL;
}
}
EXPORT_SYMBOL(drm_atomic_state_default_clear);
/**
* drm_atomic_state_clear - clear state object
* @state: atomic state
*
* When the w/w mutex algorithm detects a deadlock we need to back off and drop
* all locks. So someone else could sneak in and change the current modeset
* configuration. Which means that all the state assembled in @state is no
* longer an atomic update to the current state, but to some arbitrary earlier
* state. Which could break assumptions the driver's ->atomic_check likely
* relies on.
*
* Hence we must clear all cached state and completely start over, using this
* function.
*/
void drm_atomic_state_clear(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
if (config->funcs->atomic_state_clear)
config->funcs->atomic_state_clear(state);
else
drm_atomic_state_default_clear(state);
}
EXPORT_SYMBOL(drm_atomic_state_clear);
/**
......@@ -173,14 +222,25 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
*/
void drm_atomic_state_free(struct drm_atomic_state *state)
{
struct drm_device *dev;
struct drm_mode_config *config;
if (!state)
return;
dev = state->dev;
config = &dev->mode_config;
drm_atomic_state_clear(state);
DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
kfree_state(state);
if (config->funcs->atomic_state_free) {
config->funcs->atomic_state_free(state);
} else {
drm_atomic_state_default_release(state);
kfree(state);
}
}
EXPORT_SYMBOL(drm_atomic_state_free);
......@@ -203,13 +263,12 @@ struct drm_crtc_state *
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
int ret, index;
int ret, index = drm_crtc_index(crtc);
struct drm_crtc_state *crtc_state;
index = drm_crtc_index(crtc);
if (state->crtc_states[index])
return state->crtc_states[index];
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
if (crtc_state)
return crtc_state;
ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
if (ret)
......@@ -337,13 +396,12 @@ struct drm_plane_state *
drm_atomic_get_plane_state(struct drm_atomic_state *state,
struct drm_plane *plane)
{
int ret, index;
int ret, index = drm_plane_index(plane);
struct drm_plane_state *plane_state;
index = drm_plane_index(plane);
if (state->plane_states[index])
return state->plane_states[index];
plane_state = drm_atomic_get_existing_plane_state(state, plane);
if (plane_state)
return plane_state;
ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
if (ret)
......
......@@ -624,8 +624,22 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
}
}
static void
set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
/**
* drm_atomic_helper_update_legacy_modeset_state - update legacy modeset state
* @dev: DRM device
* @old_state: atomic state object with old state structures
*
* This function updates all the various legacy modeset state pointers in
* connectors, encoders and crtcs. It also updates the timestamping constants
* used for precise vblank timestamps by calling
* drm_calc_timestamping_constants().
*
* Drivers can use this for building their own atomic commit if they don't have
* a pure helper-based modeset implementation.
*/
void
drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
struct drm_connector *connector;
struct drm_connector_state *old_conn_state;
......@@ -662,8 +676,13 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
crtc->enabled = crtc->state->enable;
crtc->x = crtc->primary->state->src_x >> 16;
crtc->y = crtc->primary->state->src_y >> 16;
if (crtc->state->enable)
drm_calc_timestamping_constants(crtc,
&crtc->state->adjusted_mode);
}
}
EXPORT_SYMBOL(drm_atomic_helper_update_legacy_modeset_state);
static void
crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
......@@ -742,7 +761,9 @@ void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
disable_outputs(dev, old_state);
set_routing_links(dev, old_state);
drm_atomic_helper_update_legacy_modeset_state(dev, old_state);
crtc_set_mode(dev, old_state);
}
EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
......@@ -1135,8 +1156,6 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
if (!funcs)
continue;
old_plane_state = old_state->plane_states[i];
/*
* Special-case disabling the plane if drivers support it.
*/
......
......@@ -352,7 +352,9 @@ static struct drm_mode_object *_object_find(struct drm_device *dev,
if (obj && obj->id != id)
obj = NULL;
/* don't leak out unref'd fb's */
if (obj && (obj->type == DRM_MODE_OBJECT_FB))
if (obj &&
(obj->type == DRM_MODE_OBJECT_FB ||
obj->type == DRM_MODE_OBJECT_BLOB))
obj = NULL;
mutex_unlock(&dev->mode_config.idr_mutex);
......@@ -377,7 +379,7 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
/* Framebuffers are reference counted and need their own lookup
* function.*/
WARN_ON(type == DRM_MODE_OBJECT_FB);
WARN_ON(type == DRM_MODE_OBJECT_FB || type == DRM_MODE_OBJECT_BLOB);
obj = _object_find(dev, id, type);
return obj;
}
......@@ -4225,7 +4227,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
return ret;
}
static struct drm_property_blob *
struct drm_property_blob *
drm_property_create_blob(struct drm_device *dev, size_t length,
const void *data)
{
......@@ -4239,28 +4241,237 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
if (!blob)
return NULL;
blob->length = length;
blob->dev = dev;
memcpy(blob->data, data, length);
mutex_lock(&dev->mode_config.blob_lock);
ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
if (ret) {
kfree(blob);
mutex_unlock(&dev->mode_config.blob_lock);
return NULL;
}
blob->length = length;
memcpy(blob->data, data, length);
kref_init(&blob->refcount);
list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
mutex_unlock(&dev->mode_config.blob_lock);
return blob;
}
EXPORT_SYMBOL(drm_property_create_blob);
static void drm_property_destroy_blob(struct drm_device *dev,
struct drm_property_blob *blob)
/**
* drm_property_free_blob - Blob property destructor
*
* Internal free function for blob properties; must not be used directly.
*
* @param kref Reference
*/
static void drm_property_free_blob(struct kref *kref)
{
drm_mode_object_put(dev, &blob->base);
struct drm_property_blob *blob =
container_of(kref, struct drm_property_blob, refcount);
WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock));
list_del(&blob->head);
drm_mode_object_put(blob->dev, &blob->base);
kfree(blob);
}
/**
* drm_property_unreference_blob - Unreference a blob property
*
* Drop a reference on a blob property. May free the object.
*
* @param blob Pointer to blob property
*/
void drm_property_unreference_blob(struct drm_property_blob *blob)
{
struct drm_device *dev;
if (!blob)
return;
dev = blob->dev;
DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
if (kref_put_mutex(&blob->refcount, drm_property_free_blob,
&dev->mode_config.blob_lock))
mutex_unlock(&dev->mode_config.blob_lock);
else
might_lock(&dev->mode_config.blob_lock);
}
EXPORT_SYMBOL(drm_property_unreference_blob);
/**
* drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held
*
* Drop a reference on a blob property. May free the object. This must be
* called with blob_lock held.
*
* @param dev Device the blob was created on
* @param blob Pointer to blob property
*/
static void drm_property_unreference_blob_locked(struct drm_property_blob *blob)
{
if (!blob)
return;
DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
kref_put(&blob->refcount, drm_property_free_blob);
}
/**
* drm_property_reference_blob - Take a reference on an existing property
*
* Take a new reference on an existing blob property.
*
* @param blob Pointer to blob property
*/
struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob)
{
DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
kref_get(&blob->refcount);
return blob;
}
EXPORT_SYMBOL(drm_property_reference_blob);
/*
* Like drm_property_lookup_blob, but does not return an additional reference.
* Must be called with blob_lock held.
*/
static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev,
uint32_t id)
{
struct drm_mode_object *obj = NULL;
struct drm_property_blob *blob;
WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock));
mutex_lock(&dev->mode_config.idr_mutex);
obj = idr_find(&dev->mode_config.crtc_idr, id);
if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id))
blob = NULL;
else
blob = obj_to_blob(obj);
mutex_unlock(&dev->mode_config.idr_mutex);
return blob;
}
/**
* drm_property_lookup_blob - look up a blob property and take a reference
* @dev: drm device
* @id: id of the blob property
*
* If successful, this takes an additional reference to the blob property.
* callers need to make sure to eventually unreference the returned property
* again, using @drm_property_unreference_blob.
*/
struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
uint32_t id)
{
struct drm_property_blob *blob;
mutex_lock(&dev->mode_config.blob_lock);
blob = __drm_property_lookup_blob(dev, id);
if (blob) {
if (!kref_get_unless_zero(&blob->refcount))
blob = NULL;
}
mutex_unlock(&dev->mode_config.blob_lock);
return blob;
}
EXPORT_SYMBOL(drm_property_lookup_blob);
/**
* drm_property_replace_global_blob - atomically replace existing blob property
* @dev: drm device
* @replace: location of blob property pointer to be replaced
* @length: length of data for new blob, or 0 for no data
* @data: content for new blob, or NULL for no data
* @obj_holds_id: optional object for property holding blob ID
* @prop_holds_id: optional property holding blob ID
* @return 0 on success or error on failure
*
* This function will atomically replace a global property in the blob list,
* optionally updating a property which holds the ID of that property. It is
* guaranteed to be atomic: no caller will be allowed to see intermediate
* results, and either the entire operation will succeed and clean up the
* previous property, or it will fail and the state will be unchanged.
*
* If length is 0 or data is NULL, no new blob will be created, and the holding
* property, if specified, will be set to 0.
*
* Access to the replace pointer is assumed to be protected by the caller, e.g.
* by holding the relevant modesetting object lock for its parent.
*
* For example, a drm_connector has a 'PATH' property, which contains the ID
* of a blob property with the value of the MST path information. Calling this
* function with replace pointing to the connector's path_blob_ptr, length and
* data set for the new path information, obj_holds_id set to the connector's
* base object, and prop_holds_id set to the path property name, will perform
* a completely atomic update. The access to path_blob_ptr is protected by the
* caller holding a lock on the connector.
*/
static int drm_property_replace_global_blob(struct drm_device *dev,
struct drm_property_blob **replace,
size_t length,
const void *data,
struct drm_mode_object *obj_holds_id,
struct drm_property *prop_holds_id)
{
struct drm_property_blob *new_blob = NULL;
struct drm_property_blob *old_blob = NULL;
int ret;
WARN_ON(replace == NULL);
old_blob = *replace;
if (length && data) {
new_blob = drm_property_create_blob(dev, length, data);
if (!new_blob)
return -EINVAL;
}
/* This does not need to be synchronised with blob_lock, as the
* get_properties ioctl locks all modesetting objects, and
* obj_holds_id must be locked before calling here, so we cannot
* have its value out of sync with the list membership modified
* below under blob_lock. */
if (obj_holds_id) {
ret = drm_object_property_set_value(obj_holds_id,
prop_holds_id,
new_blob ?
new_blob->base.id : 0);
if (ret != 0)
goto err_created;
}
if (old_blob)
drm_property_unreference_blob(old_blob);
*replace = new_blob;
return 0;
err_created:
drm_property_unreference_blob(new_blob);
return ret;
}
/**
* drm_mode_getblob_ioctl - get the contents of a blob property value
* @dev: DRM device
......@@ -4287,7 +4498,8 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
return -EINVAL;
drm_modeset_lock_all(dev);
blob = drm_property_blob_find(dev, out_resp->blob_id);
mutex_lock(&dev->mode_config.blob_lock);
blob = __drm_property_lookup_blob(dev, out_resp->blob_id);
if (!blob) {
ret = -ENOENT;
goto done;
......@@ -4303,6 +4515,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
out_resp->length = blob->length;
done:
mutex_unlock(&dev->mode_config.blob_lock);
drm_modeset_unlock_all(dev);
return ret;
}
......@@ -4310,7 +4523,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
/**
* drm_mode_connector_set_path_property - set tile property on connector
* @connector: connector to set property on.
* @path: path to use for property.
* @path: path to use for property; must not be NULL.
*
* This creates a property to expose to userspace to specify a
* connector path. This is mainly used for DisplayPort MST where
......@@ -4324,17 +4537,14 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector,
const char *path)
{
struct drm_device *dev = connector->dev;
size_t size = strlen(path) + 1;
int ret;
connector->path_blob_ptr = drm_property_create_blob(connector->dev,
size, path);
if (!connector->path_blob_ptr)
return -EINVAL;
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.path_property,
connector->path_blob_ptr->base.id);
ret = drm_property_replace_global_blob(dev,
&connector->path_blob_ptr,
strlen(path) + 1,
path,
&connector->base,
dev->mode_config.path_property);
return ret;
}
EXPORT_SYMBOL(drm_mode_connector_set_path_property);
......@@ -4353,16 +4563,16 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property);
int drm_mode_connector_set_tile_property(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
int ret, size;
char tile[256];
if (connector->tile_blob_ptr)
drm_property_destroy_blob(dev, connector->tile_blob_ptr);
int ret;
if (!connector->has_tile) {
connector->tile_blob_ptr = NULL;
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.tile_property, 0);
ret = drm_property_replace_global_blob(dev,
&connector->tile_blob_ptr,
0,
NULL,
&connector->base,
dev->mode_config.tile_property);
return ret;
}
......@@ -4371,16 +4581,13 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector)
connector->num_h_tile, connector->num_v_tile,
connector->tile_h_loc, connector->tile_v_loc,
connector->tile_h_size, connector->tile_v_size);
size = strlen(tile) + 1;
connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
size, tile);
if (!connector->tile_blob_ptr)
return -EINVAL;
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.tile_property,
connector->tile_blob_ptr->base.id);
ret = drm_property_replace_global_blob(dev,
&connector->tile_blob_ptr,
strlen(tile) + 1,
tile,
&connector->base,
dev->mode_config.tile_property);
return ret;
}
EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
......@@ -4400,33 +4607,22 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
const struct edid *edid)
{
struct drm_device *dev = connector->dev;
size_t size;
size_t size = 0;
int ret;
/* ignore requests to set edid when overridden */
if (connector->override_edid)
return 0;
if (connector->edid_blob_ptr)
drm_property_destroy_blob(dev, connector->edid_blob_ptr);
/* Delete edid, when there is none. */
if (!edid) {
connector->edid_blob_ptr = NULL;
ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
return ret;
}
size = EDID_LENGTH * (1 + edid->extensions);
connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
size, edid);
if (!connector->edid_blob_ptr)
return -EINVAL;
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.edid_property,
connector->edid_blob_ptr->base.id);
if (edid)
size = EDID_LENGTH + (1 + edid->extensions);
ret = drm_property_replace_global_blob(dev,
&connector->edid_blob_ptr,
size,
edid,
&connector->base,
dev->mode_config.edid_property);
return ret;
}
EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
......@@ -4467,8 +4663,18 @@ bool drm_property_change_valid_get(struct drm_property *property,
valid_mask |= (1ULL << property->values[i]);
return !(value & ~valid_mask);
} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
/* Only the driver knows */
return true;
struct drm_property_blob *blob;
if (value == 0)
return true;
blob = drm_property_lookup_blob(property->dev, value);
if (blob) {
*ref = &blob->base;
return true;
} else {
return false;
}
} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
/* a zero value for an object property translates to null: */
if (value == 0)
......@@ -5453,6 +5659,7 @@ void drm_mode_config_init(struct drm_device *dev)
drm_modeset_lock_init(&dev->mode_config.connection_mutex);
mutex_init(&dev->mode_config.idr_mutex);
mutex_init(&dev->mode_config.fb_lock);
mutex_init(&dev->mode_config.blob_lock);
INIT_LIST_HEAD(&dev->mode_config.fb_list);
INIT_LIST_HEAD(&dev->mode_config.crtc_list);
INIT_LIST_HEAD(&dev->mode_config.connector_list);
......@@ -5517,7 +5724,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
head) {
drm_property_destroy_blob(dev, blob);
drm_property_unreference_blob(blob);
}
/*
......
......@@ -959,7 +959,12 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
if (crtc_funcs->atomic_check) {
ret = crtc_funcs->atomic_check(crtc, crtc_state);
if (ret) {
kfree(crtc_state);
if (crtc->funcs->atomic_destroy_state) {
crtc->funcs->atomic_destroy_state(crtc,
crtc_state);
} else {
kfree(crtc_state);
}
return ret;
}
......
......@@ -146,327 +146,359 @@ static struct edid_quirk {
* This table is copied from xfree86/modes/xf86EdidModes.c.
*/
static const struct drm_display_mode drm_dmt_modes[] = {
/* 640x350@85Hz */
/* 0x01 - 640x350@85Hz */
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
736, 832, 0, 350, 382, 385, 445, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 640x400@85Hz */
/* 0x02 - 640x400@85Hz */
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
736, 832, 0, 400, 401, 404, 445, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 720x400@85Hz */
/* 0x03 - 720x400@85Hz */
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
828, 936, 0, 400, 401, 404, 446, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 640x480@60Hz */
/* 0x04 - 640x480@60Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 489, 492, 525, 0,
752, 800, 0, 480, 490, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 640x480@72Hz */
/* 0x05 - 640x480@72Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
704, 832, 0, 480, 489, 492, 520, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 640x480@75Hz */
/* 0x06 - 640x480@75Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
720, 840, 0, 480, 481, 484, 500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 640x480@85Hz */
/* 0x07 - 640x480@85Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
752, 832, 0, 480, 481, 484, 509, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 800x600@56Hz */
/* 0x08 - 800x600@56Hz */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
896, 1024, 0, 600, 601, 603, 625, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 800x600@60Hz */
/* 0x09 - 800x600@60Hz */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
968, 1056, 0, 600, 601, 605, 628, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 800x600@72Hz */
/* 0x0a - 800x600@72Hz */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
976, 1040, 0, 600, 637, 643, 666, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 800x600@75Hz */
/* 0x0b - 800x600@75Hz */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
896, 1056, 0, 600, 601, 604, 625, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 800x600@85Hz */
/* 0x0c - 800x600@85Hz */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
896, 1048, 0, 600, 601, 604, 631, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 800x600@120Hz RB */
/* 0x0d - 800x600@120Hz RB */
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848,
880, 960, 0, 600, 603, 607, 636, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 848x480@60Hz */
/* 0x0e - 848x480@60Hz */
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
976, 1088, 0, 480, 486, 494, 517, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1024x768@43Hz, interlace */
/* 0x0f - 1024x768@43Hz, interlace */
{ DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
1208, 1264, 0, 768, 768, 772, 817, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE) },
/* 1024x768@60Hz */
DRM_MODE_FLAG_INTERLACE) },
/* 0x10 - 1024x768@60Hz */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1184, 1344, 0, 768, 771, 777, 806, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1024x768@70Hz */
/* 0x11 - 1024x768@70Hz */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
1184, 1328, 0, 768, 771, 777, 806, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1024x768@75Hz */
/* 0x12 - 1024x768@75Hz */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
1136, 1312, 0, 768, 769, 772, 800, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1024x768@85Hz */
/* 0x13 - 1024x768@85Hz */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
1168, 1376, 0, 768, 769, 772, 808, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1024x768@120Hz RB */
/* 0x14 - 1024x768@120Hz RB */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072,
1104, 1184, 0, 768, 771, 775, 813, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1152x864@75Hz */
/* 0x15 - 1152x864@75Hz */
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
1344, 1600, 0, 864, 865, 868, 900, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x768@60Hz RB */
/* 0x55 - 1280x720@60Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x16 - 1280x768@60Hz RB */
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328,
1360, 1440, 0, 768, 771, 778, 790, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x768@60Hz */
/* 0x17 - 1280x768@60Hz */
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
1472, 1664, 0, 768, 771, 778, 798, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x768@75Hz */
/* 0x18 - 1280x768@75Hz */
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
1488, 1696, 0, 768, 771, 778, 805, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x768@85Hz */
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x19 - 1280x768@85Hz */
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
1496, 1712, 0, 768, 771, 778, 809, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x768@120Hz RB */
/* 0x1a - 1280x768@120Hz RB */
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328,
1360, 1440, 0, 768, 771, 778, 813, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x800@60Hz RB */
/* 0x1b - 1280x800@60Hz RB */
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328,
1360, 1440, 0, 800, 803, 809, 823, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x800@60Hz */
/* 0x1c - 1280x800@60Hz */
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
1480, 1680, 0, 800, 803, 809, 831, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x800@75Hz */
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x1d - 1280x800@75Hz */
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
1488, 1696, 0, 800, 803, 809, 838, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x800@85Hz */
/* 0x1e - 1280x800@85Hz */
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
1496, 1712, 0, 800, 803, 809, 843, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x800@120Hz RB */
/* 0x1f - 1280x800@120Hz RB */
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328,
1360, 1440, 0, 800, 803, 809, 847, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x960@60Hz */
/* 0x20 - 1280x960@60Hz */
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
1488, 1800, 0, 960, 961, 964, 1000, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x960@85Hz */
/* 0x21 - 1280x960@85Hz */
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
1504, 1728, 0, 960, 961, 964, 1011, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x960@120Hz RB */
/* 0x22 - 1280x960@120Hz RB */
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328,
1360, 1440, 0, 960, 963, 967, 1017, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x1024@60Hz */
/* 0x23 - 1280x1024@60Hz */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x1024@75Hz */
/* 0x24 - 1280x1024@75Hz */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x1024@85Hz */
/* 0x25 - 1280x1024@85Hz */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1280x1024@120Hz RB */
/* 0x26 - 1280x1024@120Hz RB */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328,
1360, 1440, 0, 1024, 1027, 1034, 1084, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1360x768@60Hz */
/* 0x27 - 1360x768@60Hz */
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
1536, 1792, 0, 768, 771, 777, 795, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1360x768@120Hz RB */
/* 0x28 - 1360x768@120Hz RB */
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408,
1440, 1520, 0, 768, 771, 776, 813, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1400x1050@60Hz RB */
/* 0x51 - 1366x768@60Hz */
{ DRM_MODE("1366x768", DRM_MODE_TYPE_DRIVER, 85500, 1366, 1436,
1579, 1792, 0, 768, 771, 774, 798, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x56 - 1366x768@60Hz */
{ DRM_MODE("1366x768", DRM_MODE_TYPE_DRIVER, 72000, 1366, 1380,
1436, 1500, 0, 768, 769, 772, 800, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x29 - 1400x1050@60Hz RB */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448,
1480, 1560, 0, 1050, 1053, 1057, 1080, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1400x1050@60Hz */
/* 0x2a - 1400x1050@60Hz */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1400x1050@75Hz */
/* 0x2b - 1400x1050@75Hz */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1400x1050@85Hz */
/* 0x2c - 1400x1050@85Hz */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1400x1050@120Hz RB */
/* 0x2d - 1400x1050@120Hz RB */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448,
1480, 1560, 0, 1050, 1053, 1057, 1112, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1440x900@60Hz RB */
/* 0x2e - 1440x900@60Hz RB */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488,
1520, 1600, 0, 900, 903, 909, 926, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1440x900@60Hz */
/* 0x2f - 1440x900@60Hz */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
1672, 1904, 0, 900, 903, 909, 934, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1440x900@75Hz */
/* 0x30 - 1440x900@75Hz */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
1688, 1936, 0, 900, 903, 909, 942, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1440x900@85Hz */
/* 0x31 - 1440x900@85Hz */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
1696, 1952, 0, 900, 903, 909, 948, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1440x900@120Hz RB */
/* 0x32 - 1440x900@120Hz RB */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488,
1520, 1600, 0, 900, 903, 909, 953, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1600x1200@60Hz */
/* 0x53 - 1600x900@60Hz */
{ DRM_MODE("1600x900", DRM_MODE_TYPE_DRIVER, 108000, 1600, 1624,
1704, 1800, 0, 900, 901, 904, 1000, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x33 - 1600x1200@60Hz */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1600x1200@65Hz */
/* 0x34 - 1600x1200@65Hz */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1600x1200@70Hz */
/* 0x35 - 1600x1200@70Hz */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1600x1200@75Hz */
/* 0x36 - 1600x1200@75Hz */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1600x1200@85Hz */
/* 0x37 - 1600x1200@85Hz */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1600x1200@120Hz RB */
/* 0x38 - 1600x1200@120Hz RB */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648,
1680, 1760, 0, 1200, 1203, 1207, 1271, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1680x1050@60Hz RB */
/* 0x39 - 1680x1050@60Hz RB */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728,
1760, 1840, 0, 1050, 1053, 1059, 1080, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1680x1050@60Hz */
/* 0x3a - 1680x1050@60Hz */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1680x1050@75Hz */
/* 0x3b - 1680x1050@75Hz */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1680x1050@85Hz */
/* 0x3c - 1680x1050@85Hz */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1680x1050@120Hz RB */
/* 0x3d - 1680x1050@120Hz RB */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728,
1760, 1840, 0, 1050, 1053, 1059, 1112, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1792x1344@60Hz */
/* 0x3e - 1792x1344@60Hz */
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1792x1344@75Hz */
/* 0x3f - 1792x1344@75Hz */
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1792x1344@120Hz RB */
/* 0x40 - 1792x1344@120Hz RB */
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840,
1872, 1952, 0, 1344, 1347, 1351, 1423, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1856x1392@60Hz */
/* 0x41 - 1856x1392@60Hz */
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1856x1392@75Hz */
/* 0x42 - 1856x1392@75Hz */
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
2208, 2560, 0, 1392, 1393, 1396, 1500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1856x1392@120Hz RB */
/* 0x43 - 1856x1392@120Hz RB */
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904,
1936, 2016, 0, 1392, 1395, 1399, 1474, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1920x1200@60Hz RB */
/* 0x52 - 1920x1080@60Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 0x44 - 1920x1200@60Hz RB */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968,
2000, 2080, 0, 1200, 1203, 1209, 1235, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1920x1200@60Hz */
/* 0x45 - 1920x1200@60Hz */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1920x1200@75Hz */
/* 0x46 - 1920x1200@75Hz */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1920x1200@85Hz */
/* 0x47 - 1920x1200@85Hz */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1920x1200@120Hz RB */
/* 0x48 - 1920x1200@120Hz RB */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968,
2000, 2080, 0, 1200, 1203, 1209, 1271, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1920x1440@60Hz */
/* 0x49 - 1920x1440@60Hz */
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1920x1440@75Hz */
/* 0x4a - 1920x1440@75Hz */
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1920x1440@120Hz RB */
/* 0x4b - 1920x1440@120Hz RB */
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968,
2000, 2080, 0, 1440, 1443, 1447, 1525, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 2560x1600@60Hz RB */
/* 0x54 - 2048x1152@60Hz */
{ DRM_MODE("2048x1152", DRM_MODE_TYPE_DRIVER, 162000, 2048, 2074,
2154, 2250, 0, 1152, 1153, 1156, 1200, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 0x4c - 2560x1600@60Hz RB */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608,
2640, 2720, 0, 1600, 1603, 1609, 1646, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 2560x1600@60Hz */
/* 0x4d - 2560x1600@60Hz */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 2560x1600@75HZ */
/* 0x4e - 2560x1600@75Hz */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 2560x1600@85HZ */
/* 0x4f - 2560x1600@85Hz */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 2560x1600@120Hz RB */
/* 0x50 - 2560x1600@120Hz RB */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608,
2640, 2720, 0, 1600, 1603, 1609, 1694, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 0x57 - 4096x2160@60Hz RB */
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 556744, 4096, 4104,
4136, 4176, 0, 2160, 2208, 2216, 2222, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 0x58 - 4096x2160@59.94Hz RB */
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 556188, 4096, 4104,
4136, 4176, 0, 2160, 2208, 2216, 2222, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
};
/*
......@@ -3732,10 +3764,10 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
num_modes += add_cvt_modes(connector, edid);
num_modes += add_standard_modes(connector, edid);
num_modes += add_established_modes(connector, edid);
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
num_modes += add_inferred_modes(connector, edid);
num_modes += add_cea_modes(connector, edid);
num_modes += add_alternate_cea_modes(connector, edid);
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
num_modes += add_inferred_modes(connector, edid);
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks);
......
......@@ -21,8 +21,8 @@
* SOFTWARE.
*/
#include "drmP.h"
#include "drm_flip_work.h"
#include <drm/drmP.h>
#include <drm/drm_flip_work.h>
/**
* drm_flip_work_allocate_task - allocate a flip-work task
......
......@@ -502,9 +502,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
struct drm_gem_object *obj;
int ret;
if (!dev->driver->gem_prime_import_sg_table)
return ERR_PTR(-EINVAL);
if (dma_buf->ops == &drm_gem_prime_dmabuf_ops) {
obj = dma_buf->priv;
if (obj->dev == dev) {
......@@ -517,6 +514,9 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
}
}
if (!dev->driver->gem_prime_import_sg_table)
return ERR_PTR(-EINVAL);
attach = dma_buf_attach(dma_buf, dev->dev);
if (IS_ERR(attach))
return ERR_CAST(attach);
......
......@@ -302,35 +302,43 @@ static ssize_t modes_show(struct device *device,
return written;
}
static ssize_t subconnector_show(struct device *device,
struct device_attribute *attr,
char *buf)
static ssize_t tv_subconnector_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_device *dev = connector->dev;
struct drm_property *prop = NULL;
struct drm_property *prop;
uint64_t subconnector;
int is_tv = 0;
int ret;
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_DVII:
prop = dev->mode_config.dvi_i_subconnector_property;
break;
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Component:
case DRM_MODE_CONNECTOR_TV:
prop = dev->mode_config.tv_subconnector_property;
is_tv = 1;
break;
default:
DRM_ERROR("Wrong connector type for this property\n");
return 0;
prop = dev->mode_config.tv_subconnector_property;
if (!prop) {
DRM_ERROR("Unable to find subconnector property\n");
return 0;
}
ret = drm_object_property_get_value(&connector->base, prop, &subconnector);
if (ret)
return 0;
return snprintf(buf, PAGE_SIZE, "%s",
drm_get_tv_subconnector_name((int)subconnector));
}
static ssize_t tv_select_subconnector_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_device *dev = connector->dev;
struct drm_property *prop;
uint64_t subconnector;
int ret;
prop = dev->mode_config.tv_select_subconnector_property;
if (!prop) {
DRM_ERROR("Unable to find subconnector property\n");
DRM_ERROR("Unable to find select subconnector property\n");
return 0;
}
......@@ -338,38 +346,45 @@ static ssize_t subconnector_show(struct device *device,
if (ret)
return 0;
return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
drm_get_tv_subconnector_name((int)subconnector) :
drm_get_dvi_i_subconnector_name((int)subconnector));
return snprintf(buf, PAGE_SIZE, "%s",
drm_get_tv_select_name((int)subconnector));
}
static ssize_t select_subconnector_show(struct device *device,
struct device_attribute *attr,
char *buf)
static ssize_t dvii_subconnector_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_device *dev = connector->dev;
struct drm_property *prop = NULL;
struct drm_property *prop;
uint64_t subconnector;
int is_tv = 0;
int ret;
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_DVII:
prop = dev->mode_config.dvi_i_select_subconnector_property;
break;
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Component:
case DRM_MODE_CONNECTOR_TV:
prop = dev->mode_config.tv_select_subconnector_property;
is_tv = 1;
break;
default:
DRM_ERROR("Wrong connector type for this property\n");
return 0;
prop = dev->mode_config.dvi_i_subconnector_property;
if (!prop) {
DRM_ERROR("Unable to find subconnector property\n");
return 0;
}
ret = drm_object_property_get_value(&connector->base, prop, &subconnector);
if (ret)
return 0;
return snprintf(buf, PAGE_SIZE, "%s",
drm_get_dvi_i_subconnector_name((int)subconnector));
}
static ssize_t dvii_select_subconnector_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_device *dev = connector->dev;
struct drm_property *prop;
uint64_t subconnector;
int ret;
prop = dev->mode_config.dvi_i_select_subconnector_property;
if (!prop) {
DRM_ERROR("Unable to find select subconnector property\n");
return 0;
......@@ -379,8 +394,7 @@ static ssize_t select_subconnector_show(struct device *device,
if (ret)
return 0;
return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
drm_get_tv_select_name((int)subconnector) :
return snprintf(buf, PAGE_SIZE, "%s",
drm_get_dvi_i_select_name((int)subconnector));
}
......@@ -397,28 +411,44 @@ static struct attribute *connector_dev_attrs[] = {
NULL
};
/* These attributes are for both DVI-I connectors and all types of tv-out. */
static DEVICE_ATTR_RO(subconnector);
static DEVICE_ATTR_RO(select_subconnector);
static DEVICE_ATTR_RO(tv_subconnector);
static DEVICE_ATTR_RO(tv_select_subconnector);
static struct attribute *connector_opt_dev_attrs[] = {
&dev_attr_subconnector.attr,
&dev_attr_select_subconnector.attr,
static struct attribute *connector_tv_dev_attrs[] = {
&dev_attr_tv_subconnector.attr,
&dev_attr_tv_select_subconnector.attr,
NULL
};
static umode_t connector_opt_dev_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
static DEVICE_ATTR_RO(dvii_subconnector);
static DEVICE_ATTR_RO(dvii_select_subconnector);
static struct attribute *connector_dvii_dev_attrs[] = {
&dev_attr_dvii_subconnector.attr,
&dev_attr_dvii_select_subconnector.attr,
NULL
};
/* Connector type related helpers */
static int kobj_connector_type(struct kobject *kobj)
{
struct device *dev = kobj_to_dev(kobj);
struct drm_connector *connector = to_drm_connector(dev);
/*
* In the long run it maybe a good idea to make one set of
* optionals per connector type.
*/
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_DVII:
return connector->connector_type;
}
static umode_t connector_is_dvii(struct kobject *kobj,
struct attribute *attr, int idx)
{
return kobj_connector_type(kobj) == DRM_MODE_CONNECTOR_DVII ?
attr->mode : 0;
}
static umode_t connector_is_tv(struct kobject *kobj,
struct attribute *attr, int idx)
{
switch (kobj_connector_type(kobj)) {
case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Component:
......@@ -446,14 +476,20 @@ static const struct attribute_group connector_dev_group = {
.bin_attrs = connector_bin_attrs,
};
static const struct attribute_group connector_opt_dev_group = {
.attrs = connector_opt_dev_attrs,
.is_visible = connector_opt_dev_is_visible,
static const struct attribute_group connector_tv_dev_group = {
.attrs = connector_tv_dev_attrs,
.is_visible = connector_is_tv,
};
static const struct attribute_group connector_dvii_dev_group = {
.attrs = connector_dvii_dev_attrs,
.is_visible = connector_is_dvii,
};
static const struct attribute_group *connector_dev_groups[] = {
&connector_dev_group,
&connector_opt_dev_group,
&connector_tv_dev_group,
&connector_dvii_dev_group,
NULL
};
......
......@@ -2,8 +2,6 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm
# Please keep these build lists sorted!
# core driver code
......
......@@ -22,8 +22,8 @@
*
*/
#include "drmP.h"
#include "i915_drm.h"
#include <drm/drmP.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "i915_trace.h"
#include "intel_drv.h"
......
......@@ -35,6 +35,11 @@ drm_atomic_state_alloc(struct drm_device *dev);
void drm_atomic_state_clear(struct drm_atomic_state *state);
void drm_atomic_state_free(struct drm_atomic_state *state);
int __must_check
drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state);
void drm_atomic_state_default_clear(struct drm_atomic_state *state);
void drm_atomic_state_default_release(struct drm_atomic_state *state);
struct drm_crtc_state * __must_check
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc);
......@@ -54,6 +59,56 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
struct drm_connector_state *state, struct drm_property *property,
uint64_t val);
/**
* drm_atomic_get_existing_crtc_state - get crtc state, if it exists
* @state: global atomic state object
* @crtc: crtc to grab
*
* This function returns the crtc state for the given crtc, or NULL
* if the crtc is not part of the global atomic state.
*/
static inline struct drm_crtc_state *
drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
return state->crtc_states[drm_crtc_index(crtc)];
}
/**
* drm_atomic_get_existing_plane_state - get plane state, if it exists
* @state: global atomic state object
* @plane: plane to grab
*
* This function returns the plane state for the given plane, or NULL
* if the plane is not part of the global atomic state.
*/
static inline struct drm_plane_state *
drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
struct drm_plane *plane)
{
return state->plane_states[drm_plane_index(plane)];
}
/**
* drm_atomic_get_existing_connector_state - get connector state, if it exists
* @state: global atomic state object
* @connector: connector to grab
*
* This function returns the connector state for the given connector,
* or NULL if the connector is not part of the global atomic state.
*/
static inline struct drm_connector_state *
drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
struct drm_connector *connector)
{
int index = drm_connector_index(connector);
if (index >= state->num_connector)
return NULL;
return state->connector_states[index];
}
int __must_check
drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
struct drm_crtc *crtc);
......
......@@ -43,6 +43,10 @@ int drm_atomic_helper_commit(struct drm_device *dev,
void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
struct drm_atomic_state *old_state);
void
drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
struct drm_atomic_state *old_state);
void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
struct drm_atomic_state *state);
void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
......
......@@ -216,6 +216,8 @@ struct drm_framebuffer {
struct drm_property_blob {
struct drm_mode_object base;
struct drm_device *dev;
struct kref refcount;
struct list_head head;
size_t length;
unsigned char data[];
......@@ -983,6 +985,9 @@ struct drm_mode_set {
* @atomic_check: check whether a given atomic state update is possible
* @atomic_commit: commit an atomic state update previously verified with
* atomic_check()
* @atomic_state_alloc: allocate a new atomic state
* @atomic_state_clear: clear the atomic state
* @atomic_state_free: free the atomic state
*
* Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
* involve drivers.
......@@ -998,6 +1003,9 @@ struct drm_mode_config_funcs {
int (*atomic_commit)(struct drm_device *dev,
struct drm_atomic_state *a,
bool async);
struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev);
void (*atomic_state_clear)(struct drm_atomic_state *state);
void (*atomic_state_free)(struct drm_atomic_state *state);
};
/**
......@@ -1054,6 +1062,7 @@ struct drm_mode_group {
* @poll_running: track polling status for this device
* @output_poll_work: delayed work for polling in process context
* @property_blob_list: list of all the blob property objects
* @blob_lock: mutex for blob property allocation and management
* @*_property: core property tracking
* @preferred_depth: preferred RBG pixel depth, used by fb helpers
* @prefer_shadow: hint to userspace to prefer shadow-fb rendering
......@@ -1109,6 +1118,8 @@ struct drm_mode_config {
bool delayed_event;
struct delayed_work output_poll_work;
struct mutex blob_lock;
/* pointers to standard properties */
struct list_head property_blob_list;
struct drm_property *edid_property;
......@@ -1369,6 +1380,13 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name, uint32_t type);
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
const char *name);
struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
size_t length,
const void *data);
struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
uint32_t id);
struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob);
void drm_property_unreference_blob(struct drm_property_blob *blob);
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,
uint64_t value, const char *name);
......@@ -1533,14 +1551,6 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev,
return mo ? obj_to_property(mo) : NULL;
}
static inline struct drm_property_blob *
drm_property_blob_find(struct drm_device *dev, uint32_t id)
{
struct drm_mode_object *mo;
mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB);
return mo ? obj_to_blob(mo) : NULL;
}
/* Plane list iterator for legacy (overlay only) planes. */
#define drm_for_each_legacy_plane(plane, planelist) \
list_for_each_entry(plane, planelist, head) \
......
......@@ -679,9 +679,9 @@ struct drm_dp_aux_msg {
* An AUX channel can also be used to transport I2C messages to a sink. A
* typical application of that is to access an EDID that's present in the
* sink device. The .transfer() function can also be used to execute such
* transactions. The drm_dp_aux_register_i2c_bus() function registers an
* I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
* should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
* transactions. The drm_dp_aux_register() function registers an I2C
* adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
* should call drm_dp_aux_unregister() to remove the I2C adapter.
* The I2C adapter uses long transfers by default; if a partial response is
* received, the adapter will drop down to the size given by the partial
* response for this transaction only.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册