mirror of https://gitee.com/openkylin/linux.git
Merge tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel into drm-next
So small drm stuff all over for 3.18. Biggest one is the cmdline parsing from Chris with a few fixes from me to make it work for stupid kernel configs. Plus the atomic prep series. Tested for more than a week in -nightly and Ville/Imre indeed discovered some fun which is now fixed (and i915 vblank patches postponed since the fixups need this branch plus drm-intel-next merged together). * tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel: drm: Use the type of the array element when reallocating drm: Don't return 0 for a value used as a denominator drm: Docbook fixes drm/irq: Implement a generic vblank_wait function drm: Add a plane->reset hook drm: trylock modest locking for fbdev panics drm: Move ->old_fb from crtc to plane drm: Handle legacy per-crtc locking with full acquire ctx drm: Move modeset_lock_all helpers to drm_modeset_lock.[hc] drm: Add drm_plane/connector_index drm: idiot-proof vblank drm: Warn when leaking flip events on close drm: Perform cmdline mode parsing during connector initialisation video/fbdev: Always built-in video= cmdline parsing drm: Don't grab an fb reference for the idr
This commit is contained in:
commit
c0ee755fc5
|
@ -8,6 +8,7 @@ menuconfig DRM
|
|||
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
|
||||
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA
|
||||
select HDMI
|
||||
select FB_CMDLINE
|
||||
select I2C
|
||||
select I2C_ALGOBIT
|
||||
select DMA_SHARED_BUFFER
|
||||
|
|
|
@ -45,101 +45,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
|
|||
struct drm_mode_fb_cmd2 *r,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/**
|
||||
* drm_modeset_lock_all - take all modeset locks
|
||||
* @dev: drm device
|
||||
*
|
||||
* This function takes all modeset locks, suitable where a more fine-grained
|
||||
* scheme isn't (yet) implemented. Locks must be dropped with
|
||||
* drm_modeset_unlock_all.
|
||||
*/
|
||||
void drm_modeset_lock_all(struct drm_device *dev)
|
||||
{
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_modeset_acquire_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (WARN_ON(!ctx))
|
||||
return;
|
||||
|
||||
mutex_lock(&config->mutex);
|
||||
|
||||
drm_modeset_acquire_init(ctx, 0);
|
||||
|
||||
retry:
|
||||
ret = drm_modeset_lock(&config->connection_mutex, ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
ret = drm_modeset_lock_all_crtcs(dev, ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
WARN_ON(config->acquire_ctx);
|
||||
|
||||
/* now we hold the locks, so now that it is safe, stash the
|
||||
* ctx for drm_modeset_unlock_all():
|
||||
*/
|
||||
config->acquire_ctx = ctx;
|
||||
|
||||
drm_warn_on_modeset_not_all_locked(dev);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(ctx);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_lock_all);
|
||||
|
||||
/**
|
||||
* drm_modeset_unlock_all - drop all modeset locks
|
||||
* @dev: device
|
||||
*
|
||||
* This function drop all modeset locks taken by drm_modeset_lock_all.
|
||||
*/
|
||||
void drm_modeset_unlock_all(struct drm_device *dev)
|
||||
{
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
|
||||
|
||||
if (WARN_ON(!ctx))
|
||||
return;
|
||||
|
||||
config->acquire_ctx = NULL;
|
||||
drm_modeset_drop_locks(ctx);
|
||||
drm_modeset_acquire_fini(ctx);
|
||||
|
||||
kfree(ctx);
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_unlock_all);
|
||||
|
||||
/**
|
||||
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
|
||||
* @dev: device
|
||||
*
|
||||
* Useful as a debug assert.
|
||||
*/
|
||||
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
/* Locking is currently fubar in the panic handler. */
|
||||
if (oops_in_progress)
|
||||
return;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
|
||||
|
||||
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
|
||||
|
||||
/* Avoid boilerplate. I'm tired of typing. */
|
||||
#define DRM_ENUM_NAME_FN(fnname, list) \
|
||||
const char *fnname(int val) \
|
||||
|
@ -515,9 +420,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Grab the idr reference. */
|
||||
drm_framebuffer_reference(fb);
|
||||
|
||||
dev->mode_config.num_fb++;
|
||||
list_add(&fb->head, &dev->mode_config.fb_list);
|
||||
out:
|
||||
|
@ -527,10 +429,34 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_framebuffer_init);
|
||||
|
||||
/* dev->mode_config.fb_lock must be held! */
|
||||
static void __drm_framebuffer_unregister(struct drm_device *dev,
|
||||
struct drm_framebuffer *fb)
|
||||
{
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
|
||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
|
||||
fb->base.id = 0;
|
||||
}
|
||||
|
||||
static void drm_framebuffer_free(struct kref *kref)
|
||||
{
|
||||
struct drm_framebuffer *fb =
|
||||
container_of(kref, struct drm_framebuffer, refcount);
|
||||
struct drm_device *dev = fb->dev;
|
||||
|
||||
/*
|
||||
* The lookup idr holds a weak reference, which has not necessarily been
|
||||
* removed at this point. Check for that.
|
||||
*/
|
||||
mutex_lock(&dev->mode_config.fb_lock);
|
||||
if (fb->base.id) {
|
||||
/* Mark fb as reaped and drop idr ref. */
|
||||
__drm_framebuffer_unregister(dev, fb);
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.fb_lock);
|
||||
|
||||
fb->funcs->destroy(fb);
|
||||
}
|
||||
|
||||
|
@ -567,8 +493,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
|
|||
|
||||
mutex_lock(&dev->mode_config.fb_lock);
|
||||
fb = __drm_framebuffer_lookup(dev, id);
|
||||
if (fb)
|
||||
drm_framebuffer_reference(fb);
|
||||
if (fb) {
|
||||
if (!kref_get_unless_zero(&fb->refcount))
|
||||
fb = NULL;
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.fb_lock);
|
||||
|
||||
return fb;
|
||||
|
@ -612,19 +540,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
|
|||
kref_put(&fb->refcount, drm_framebuffer_free_bug);
|
||||
}
|
||||
|
||||
/* dev->mode_config.fb_lock must be held! */
|
||||
static void __drm_framebuffer_unregister(struct drm_device *dev,
|
||||
struct drm_framebuffer *fb)
|
||||
{
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
|
||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
|
||||
fb->base.id = 0;
|
||||
|
||||
__drm_framebuffer_unreference(fb);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
|
||||
* @fb: fb to unregister
|
||||
|
@ -852,6 +767,59 @@ static void drm_mode_remove(struct drm_connector *connector,
|
|||
drm_mode_destroy(connector->dev, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_connector_get_cmdline_mode - reads the user's cmdline mode
|
||||
* @connector: connector to quwery
|
||||
* @mode: returned mode
|
||||
*
|
||||
* The kernel supports per-connector configration of its consoles through
|
||||
* use of the video= parameter. This function parses that option and
|
||||
* extracts the user's specified mode (or enable/disable status) for a
|
||||
* particular connector. This is typically only used during the early fbdev
|
||||
* setup.
|
||||
*/
|
||||
static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_cmdline_mode *mode = &connector->cmdline_mode;
|
||||
char *option = NULL;
|
||||
|
||||
if (fb_get_options(connector->name, &option))
|
||||
return;
|
||||
|
||||
if (!drm_mode_parse_command_line_for_connector(option,
|
||||
connector,
|
||||
mode))
|
||||
return;
|
||||
|
||||
if (mode->force) {
|
||||
const char *s;
|
||||
|
||||
switch (mode->force) {
|
||||
case DRM_FORCE_OFF:
|
||||
s = "OFF";
|
||||
break;
|
||||
case DRM_FORCE_ON_DIGITAL:
|
||||
s = "ON - dig";
|
||||
break;
|
||||
default:
|
||||
case DRM_FORCE_ON:
|
||||
s = "ON";
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_INFO("forcing %s connector %s\n", connector->name, s);
|
||||
connector->force = mode->force;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
|
||||
connector->name,
|
||||
mode->xres, mode->yres,
|
||||
mode->refresh_specified ? mode->refresh : 60,
|
||||
mode->rb ? " reduced blanking" : "",
|
||||
mode->margins ? " with margins" : "",
|
||||
mode->interlace ? " interlaced" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_connector_init - Init a preallocated connector
|
||||
* @dev: DRM device
|
||||
|
@ -904,6 +872,8 @@ int drm_connector_init(struct drm_device *dev,
|
|||
connector->edid_blob_ptr = NULL;
|
||||
connector->status = connector_status_unknown;
|
||||
|
||||
drm_connector_get_cmdline_mode(connector);
|
||||
|
||||
list_add_tail(&connector->head, &dev->mode_config.connector_list);
|
||||
dev->mode_config.num_connector++;
|
||||
|
||||
|
@ -956,6 +926,29 @@ void drm_connector_cleanup(struct drm_connector *connector)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_connector_cleanup);
|
||||
|
||||
/**
|
||||
* drm_connector_index - find the index of a registered connector
|
||||
* @connector: connector to find index for
|
||||
*
|
||||
* Given a registered connector, return the index of that connector within a DRM
|
||||
* device's list of connectors.
|
||||
*/
|
||||
unsigned int drm_connector_index(struct drm_connector *connector)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
struct drm_connector *tmp;
|
||||
|
||||
list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
|
||||
if (tmp == connector)
|
||||
return index;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_index);
|
||||
|
||||
/**
|
||||
* drm_connector_register - register a connector
|
||||
* @connector: the connector to register
|
||||
|
@ -1260,6 +1253,29 @@ void drm_plane_cleanup(struct drm_plane *plane)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_plane_cleanup);
|
||||
|
||||
/**
|
||||
* drm_plane_index - find the index of a registered plane
|
||||
* @plane: plane to find index for
|
||||
*
|
||||
* Given a registered plane, return the index of that CRTC within a DRM
|
||||
* device's list of planes.
|
||||
*/
|
||||
unsigned int drm_plane_index(struct drm_plane *plane)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
struct drm_plane *tmp;
|
||||
|
||||
list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) {
|
||||
if (tmp == plane)
|
||||
return index;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
BUG();
|
||||
}
|
||||
EXPORT_SYMBOL(drm_plane_index);
|
||||
|
||||
/**
|
||||
* drm_plane_force_disable - Forcibly disable a plane
|
||||
* @plane: plane to disable
|
||||
|
@ -1271,19 +1287,21 @@ EXPORT_SYMBOL(drm_plane_cleanup);
|
|||
*/
|
||||
void drm_plane_force_disable(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_framebuffer *old_fb = plane->fb;
|
||||
int ret;
|
||||
|
||||
if (!old_fb)
|
||||
if (!plane->fb)
|
||||
return;
|
||||
|
||||
plane->old_fb = plane->fb;
|
||||
ret = plane->funcs->disable_plane(plane);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to disable plane with busy fb\n");
|
||||
plane->old_fb = NULL;
|
||||
return;
|
||||
}
|
||||
/* disconnect the plane from the fb and crtc: */
|
||||
__drm_framebuffer_unreference(old_fb);
|
||||
__drm_framebuffer_unreference(plane->old_fb);
|
||||
plane->old_fb = NULL;
|
||||
plane->fb = NULL;
|
||||
plane->crtc = NULL;
|
||||
}
|
||||
|
@ -2259,23 +2277,21 @@ static int setplane_internal(struct drm_plane *plane,
|
|||
uint32_t src_w, uint32_t src_h)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_framebuffer *old_fb = NULL;
|
||||
int ret = 0;
|
||||
unsigned int fb_width, fb_height;
|
||||
int i;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
/* No fb means shut it down */
|
||||
if (!fb) {
|
||||
drm_modeset_lock_all(dev);
|
||||
old_fb = plane->fb;
|
||||
plane->old_fb = plane->fb;
|
||||
ret = plane->funcs->disable_plane(plane);
|
||||
if (!ret) {
|
||||
plane->crtc = NULL;
|
||||
plane->fb = NULL;
|
||||
} else {
|
||||
old_fb = NULL;
|
||||
plane->old_fb = NULL;
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -2315,8 +2331,7 @@ static int setplane_internal(struct drm_plane *plane,
|
|||
goto out;
|
||||
}
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
old_fb = plane->fb;
|
||||
plane->old_fb = plane->fb;
|
||||
ret = plane->funcs->update_plane(plane, crtc, fb,
|
||||
crtc_x, crtc_y, crtc_w, crtc_h,
|
||||
src_x, src_y, src_w, src_h);
|
||||
|
@ -2325,15 +2340,16 @@ static int setplane_internal(struct drm_plane *plane,
|
|||
plane->fb = fb;
|
||||
fb = NULL;
|
||||
} else {
|
||||
old_fb = NULL;
|
||||
plane->old_fb = NULL;
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
out:
|
||||
if (fb)
|
||||
drm_framebuffer_unreference(fb);
|
||||
if (old_fb)
|
||||
drm_framebuffer_unreference(old_fb);
|
||||
if (plane->old_fb)
|
||||
drm_framebuffer_unreference(plane->old_fb);
|
||||
plane->old_fb = NULL;
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -2440,7 +2456,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
|
|||
* crtcs. Atomic modeset will have saner semantics ...
|
||||
*/
|
||||
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
|
||||
tmp->old_fb = tmp->primary->fb;
|
||||
tmp->primary->old_fb = tmp->primary->fb;
|
||||
|
||||
fb = set->fb;
|
||||
|
||||
|
@ -2453,8 +2469,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
|
|||
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
|
||||
if (tmp->primary->fb)
|
||||
drm_framebuffer_reference(tmp->primary->fb);
|
||||
if (tmp->old_fb)
|
||||
drm_framebuffer_unreference(tmp->old_fb);
|
||||
if (tmp->primary->old_fb)
|
||||
drm_framebuffer_unreference(tmp->primary->old_fb);
|
||||
tmp->primary->old_fb = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -2785,7 +2802,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|||
if (crtc->cursor)
|
||||
return drm_mode_cursor_universal(crtc, req, file_priv);
|
||||
|
||||
drm_modeset_lock(&crtc->mutex, NULL);
|
||||
drm_modeset_lock_crtc(crtc);
|
||||
if (req->flags & DRM_MODE_CURSOR_BO) {
|
||||
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
|
||||
ret = -ENXIO;
|
||||
|
@ -2809,7 +2826,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|||
}
|
||||
}
|
||||
out:
|
||||
drm_modeset_unlock(&crtc->mutex);
|
||||
drm_modeset_unlock_crtc(crtc);
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -3495,9 +3512,10 @@ EXPORT_SYMBOL(drm_property_create_enum);
|
|||
* @flags: flags specifying the property type
|
||||
* @name: name of the property
|
||||
* @props: enumeration lists with property bitflags
|
||||
* @num_values: number of pre-defined values
|
||||
* @num_props: size of the @props array
|
||||
* @supported_bits: bitmask of all supported enumeration values
|
||||
*
|
||||
* This creates a new generic drm property which can then be attached to a drm
|
||||
* This creates a new bitmask 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.
|
||||
*
|
||||
|
@ -4529,7 +4547,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
{
|
||||
struct drm_mode_crtc_page_flip *page_flip = data;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_framebuffer *fb = NULL, *old_fb = NULL;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
struct drm_pending_vblank_event *e = NULL;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
@ -4545,7 +4563,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
if (!crtc)
|
||||
return -ENOENT;
|
||||
|
||||
drm_modeset_lock(&crtc->mutex, NULL);
|
||||
drm_modeset_lock_crtc(crtc);
|
||||
if (crtc->primary->fb == NULL) {
|
||||
/* The framebuffer is currently unbound, presumably
|
||||
* due to a hotplug event, that userspace has not
|
||||
|
@ -4601,7 +4619,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
(void (*) (struct drm_pending_event *)) kfree;
|
||||
}
|
||||
|
||||
old_fb = crtc->primary->fb;
|
||||
crtc->primary->old_fb = crtc->primary->fb;
|
||||
ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
|
||||
if (ret) {
|
||||
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
|
@ -4611,7 +4629,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
kfree(e);
|
||||
}
|
||||
/* Keep the old fb, don't unref it. */
|
||||
old_fb = NULL;
|
||||
crtc->primary->old_fb = NULL;
|
||||
} else {
|
||||
/*
|
||||
* Warn if the driver hasn't properly updated the crtc->fb
|
||||
|
@ -4627,9 +4645,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
out:
|
||||
if (fb)
|
||||
drm_framebuffer_unreference(fb);
|
||||
if (old_fb)
|
||||
drm_framebuffer_unreference(old_fb);
|
||||
drm_modeset_unlock(&crtc->mutex);
|
||||
if (crtc->primary->old_fb)
|
||||
drm_framebuffer_unreference(crtc->primary->old_fb);
|
||||
crtc->primary->old_fb = NULL;
|
||||
drm_modeset_unlock_crtc(crtc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -4645,9 +4664,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
void drm_mode_config_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_plane *plane;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
|
||||
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
|
||||
if (plane->funcs->reset)
|
||||
plane->funcs->reset(plane);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
if (crtc->funcs->reset)
|
||||
crtc->funcs->reset(crtc);
|
||||
|
|
|
@ -1772,7 +1772,7 @@ static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count)
|
|||
case DP_LINK_BW_5_4:
|
||||
return 10 * dp_link_count;
|
||||
}
|
||||
return 0;
|
||||
BUG();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2071,6 +2071,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
|
|||
* drm_dp_mst_hpd_irq() - MST hotplug IRQ notify
|
||||
* @mgr: manager to notify irq for.
|
||||
* @esi: 4 bytes from SINK_COUNT_ESI
|
||||
* @handled: whether the hpd interrupt was consumed or not
|
||||
*
|
||||
* This should be called from the driver when it detects a short IRQ,
|
||||
* along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The
|
||||
|
|
|
@ -3433,10 +3433,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
|
|||
/**
|
||||
* drm_assign_hdmi_deep_color_info - detect whether monitor supports
|
||||
* hdmi deep color modes and update drm_display_info if so.
|
||||
*
|
||||
* @edid: monitor EDID information
|
||||
* @info: Updated with maximum supported deep color bpc and color format
|
||||
* if deep color supported.
|
||||
* @connector: DRM connector, used only for debug output
|
||||
*
|
||||
* Parse the CEA extension according to CEA-861-B.
|
||||
* Return true if HDMI deep color supported, false if not or unknown.
|
||||
|
|
|
@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
|
|||
|
||||
WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
|
||||
if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) {
|
||||
temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL);
|
||||
temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL);
|
||||
if (!temp)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
|
||||
|
||||
static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
struct drm_fb_helper_connector *fb_helper_conn;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
struct drm_cmdline_mode *mode;
|
||||
struct drm_connector *connector;
|
||||
char *option = NULL;
|
||||
|
||||
fb_helper_conn = fb_helper->connector_info[i];
|
||||
connector = fb_helper_conn->connector;
|
||||
mode = &fb_helper_conn->cmdline_mode;
|
||||
|
||||
/* do something on return - turn off connector maybe */
|
||||
if (fb_get_options(connector->name, &option))
|
||||
continue;
|
||||
|
||||
if (drm_mode_parse_command_line_for_connector(option,
|
||||
connector,
|
||||
mode)) {
|
||||
if (mode->force) {
|
||||
const char *s;
|
||||
switch (mode->force) {
|
||||
case DRM_FORCE_OFF:
|
||||
s = "OFF";
|
||||
break;
|
||||
case DRM_FORCE_ON_DIGITAL:
|
||||
s = "ON - dig";
|
||||
break;
|
||||
default:
|
||||
case DRM_FORCE_ON:
|
||||
s = "ON";
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_INFO("forcing %s connector %s\n",
|
||||
connector->name, s);
|
||||
connector->force = mode->force;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
|
||||
connector->name,
|
||||
mode->xres, mode->yres,
|
||||
mode->refresh_specified ? mode->refresh : 60,
|
||||
mode->rb ? " reduced blanking" : "",
|
||||
mode->margins ? " with margins" : "",
|
||||
mode->interlace ? " interlaced" : "");
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
|
||||
{
|
||||
uint16_t *r_base, *g_base, *b_base;
|
||||
|
@ -419,11 +365,11 @@ static bool drm_fb_helper_force_kernel_mode(void)
|
|||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
continue;
|
||||
|
||||
/* NOTE: we use lockless flag below to avoid grabbing other
|
||||
* modeset locks. So just trylock the underlying mutex
|
||||
* directly:
|
||||
/*
|
||||
* NOTE: Use trylock mode to avoid deadlocks and sleeping in
|
||||
* panic context.
|
||||
*/
|
||||
if (!mutex_trylock(&dev->mode_config.mutex)) {
|
||||
if (__drm_modeset_lock_all(dev, true) != 0) {
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
@ -432,7 +378,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
|
|||
if (ret)
|
||||
error = true;
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -1013,7 +959,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
|
||||
struct drm_cmdline_mode *cmdline_mode;
|
||||
|
||||
cmdline_mode = &fb_helper_conn->cmdline_mode;
|
||||
cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
|
||||
|
||||
if (cmdline_mode->bpp_specified) {
|
||||
switch (cmdline_mode->bpp) {
|
||||
|
@ -1260,9 +1206,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode);
|
|||
|
||||
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
|
||||
{
|
||||
struct drm_cmdline_mode *cmdline_mode;
|
||||
cmdline_mode = &fb_connector->cmdline_mode;
|
||||
return cmdline_mode->specified;
|
||||
return fb_connector->connector->cmdline_mode.specified;
|
||||
}
|
||||
|
||||
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
|
||||
|
@ -1272,7 +1216,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
|
|||
struct drm_display_mode *mode = NULL;
|
||||
bool prefer_non_interlace;
|
||||
|
||||
cmdline_mode = &fb_helper_conn->cmdline_mode;
|
||||
cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
|
||||
if (cmdline_mode->specified == false)
|
||||
return mode;
|
||||
|
||||
|
@ -1657,8 +1601,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
|
|||
struct drm_device *dev = fb_helper->dev;
|
||||
int count = 0;
|
||||
|
||||
drm_fb_helper_parse_command_line(fb_helper);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
count = drm_fb_helper_probe_connector_modes(fb_helper,
|
||||
dev->mode_config.max_width,
|
||||
|
|
|
@ -464,6 +464,8 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
if (drm_core_check_feature(dev, DRIVER_PRIME))
|
||||
drm_prime_destroy_file_private(&file_priv->prime);
|
||||
|
||||
WARN_ON(!list_empty(&file_priv->event_list));
|
||||
|
||||
put_pid(file_priv->pid);
|
||||
kfree(file_priv);
|
||||
|
||||
|
|
|
@ -720,6 +720,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
|
|||
*/
|
||||
u32 drm_vblank_count(struct drm_device *dev, int crtc)
|
||||
{
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return 0;
|
||||
return atomic_read(&dev->vblank[crtc].count);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_vblank_count);
|
||||
|
@ -742,6 +744,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
|
|||
{
|
||||
u32 cur_vblank;
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return 0;
|
||||
|
||||
/* Read timestamp from slot of _vblank_time ringbuffer
|
||||
* that corresponds to current vblank count. Retry if
|
||||
* count has incremented during readout. This works like
|
||||
|
@ -917,6 +922,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
|
|||
unsigned long irqflags;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
/* Going from 0->1 means we have to enable interrupts again */
|
||||
if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
|
||||
|
@ -965,6 +973,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
|
|||
{
|
||||
BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return;
|
||||
|
||||
/* Last user schedules interrupt disable */
|
||||
if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
|
||||
(drm_vblank_offdelay > 0))
|
||||
|
@ -988,6 +999,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_put);
|
||||
|
||||
/**
|
||||
* drm_wait_one_vblank - wait for one vblank
|
||||
* @dev: DRM device
|
||||
* @crtc: crtc index
|
||||
*
|
||||
* This waits for one vblank to pass on @crtc, using the irq driver interfaces.
|
||||
* It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
|
||||
* due to lack of driver support or because the crtc is off.
|
||||
*/
|
||||
void drm_wait_one_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
int ret;
|
||||
u32 last;
|
||||
|
||||
ret = drm_vblank_get(dev, crtc);
|
||||
if (WARN_ON(ret))
|
||||
return;
|
||||
|
||||
last = drm_vblank_count(dev, crtc);
|
||||
|
||||
ret = wait_event_timeout(dev->vblank[crtc].queue,
|
||||
last != drm_vblank_count(dev, crtc),
|
||||
msecs_to_jiffies(100));
|
||||
|
||||
WARN_ON(ret == 0);
|
||||
|
||||
drm_vblank_put(dev, crtc);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_wait_one_vblank);
|
||||
|
||||
/**
|
||||
* drm_crtc_wait_one_vblank - wait for one vblank
|
||||
* @crtc: DRM crtc
|
||||
*
|
||||
* This waits for one vblank to pass on @crtc, using the irq driver interfaces.
|
||||
* It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
|
||||
* due to lack of driver support or because the crtc is off.
|
||||
*/
|
||||
void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
|
||||
|
||||
/**
|
||||
* drm_vblank_off - disable vblank events on a CRTC
|
||||
* @dev: DRM device
|
||||
|
@ -1009,6 +1064,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
|
|||
unsigned long irqflags;
|
||||
unsigned int seq;
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
vblank_disable_and_save(dev, crtc);
|
||||
wake_up(&dev->vblank[crtc].queue);
|
||||
|
@ -1068,6 +1126,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc)
|
|||
{
|
||||
unsigned long irqflags;
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
/* re-enable interrupts if there's are users left */
|
||||
if (atomic_read(&dev->vblank[crtc].refcount) != 0)
|
||||
|
@ -1121,6 +1182,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
|
|||
/* vblank is not initialized (IRQ not installed ?), or has been freed */
|
||||
if (!dev->num_crtcs)
|
||||
return;
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return;
|
||||
|
||||
/*
|
||||
* To avoid all the problems that might happen if interrupts
|
||||
* were enabled/disabled around or between these calls, we just
|
||||
|
@ -1429,6 +1494,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
|
|||
if (!dev->num_crtcs)
|
||||
return false;
|
||||
|
||||
if (WARN_ON(crtc >= dev->num_crtcs))
|
||||
return false;
|
||||
|
||||
/* Need timestamp lock to prevent concurrent execution with
|
||||
* vblank enable/disable, as this would cause inconsistent
|
||||
* or corrupted timestamps and vblank counts.
|
||||
|
|
|
@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
|
|||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_USERDEF;
|
||||
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
|
||||
return mode;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,212 @@
|
|||
*/
|
||||
|
||||
|
||||
/**
|
||||
* __drm_modeset_lock_all - internal helper to grab all modeset locks
|
||||
* @dev: DRM device
|
||||
* @trylock: trylock mode for atomic contexts
|
||||
*
|
||||
* This is a special version of drm_modeset_lock_all() which can also be used in
|
||||
* atomic contexts. Then @trylock must be set to true.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or negative error code on failure.
|
||||
*/
|
||||
int __drm_modeset_lock_all(struct drm_device *dev,
|
||||
bool trylock)
|
||||
{
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_modeset_acquire_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx),
|
||||
trylock ? GFP_ATOMIC : GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
if (trylock) {
|
||||
if (!mutex_trylock(&config->mutex))
|
||||
return -EBUSY;
|
||||
} else {
|
||||
mutex_lock(&config->mutex);
|
||||
}
|
||||
|
||||
drm_modeset_acquire_init(ctx, 0);
|
||||
ctx->trylock_only = trylock;
|
||||
|
||||
retry:
|
||||
ret = drm_modeset_lock(&config->connection_mutex, ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
ret = drm_modeset_lock_all_crtcs(dev, ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
WARN_ON(config->acquire_ctx);
|
||||
|
||||
/* now we hold the locks, so now that it is safe, stash the
|
||||
* ctx for drm_modeset_unlock_all():
|
||||
*/
|
||||
config->acquire_ctx = ctx;
|
||||
|
||||
drm_warn_on_modeset_not_all_locked(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(ctx);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_modeset_lock_all);
|
||||
|
||||
/**
|
||||
* drm_modeset_lock_all - take all modeset locks
|
||||
* @dev: drm device
|
||||
*
|
||||
* This function takes all modeset locks, suitable where a more fine-grained
|
||||
* scheme isn't (yet) implemented. Locks must be dropped with
|
||||
* drm_modeset_unlock_all.
|
||||
*/
|
||||
void drm_modeset_lock_all(struct drm_device *dev)
|
||||
{
|
||||
WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_lock_all);
|
||||
|
||||
/**
|
||||
* drm_modeset_unlock_all - drop all modeset locks
|
||||
* @dev: device
|
||||
*
|
||||
* This function drop all modeset locks taken by drm_modeset_lock_all.
|
||||
*/
|
||||
void drm_modeset_unlock_all(struct drm_device *dev)
|
||||
{
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
|
||||
|
||||
if (WARN_ON(!ctx))
|
||||
return;
|
||||
|
||||
config->acquire_ctx = NULL;
|
||||
drm_modeset_drop_locks(ctx);
|
||||
drm_modeset_acquire_fini(ctx);
|
||||
|
||||
kfree(ctx);
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_unlock_all);
|
||||
|
||||
/**
|
||||
* drm_modeset_lock_crtc - lock crtc with hidden acquire ctx
|
||||
* @crtc: drm crtc
|
||||
*
|
||||
* This function locks the given crtc using a hidden acquire context. This is
|
||||
* necessary so that drivers internally using the atomic interfaces can grab
|
||||
* further locks with the lock acquire context.
|
||||
*/
|
||||
void drm_modeset_lock_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_modeset_acquire_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (WARN_ON(!ctx))
|
||||
return;
|
||||
|
||||
drm_modeset_acquire_init(ctx, 0);
|
||||
|
||||
retry:
|
||||
ret = drm_modeset_lock(&crtc->mutex, ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
WARN_ON(crtc->acquire_ctx);
|
||||
|
||||
/* now we hold the locks, so now that it is safe, stash the
|
||||
* ctx for drm_modeset_unlock_crtc():
|
||||
*/
|
||||
crtc->acquire_ctx = ctx;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(ctx);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_lock_crtc);
|
||||
|
||||
/**
|
||||
* drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls
|
||||
* @crtc: drm crtc
|
||||
*
|
||||
* Legacy ioctl operations like cursor updates or page flips only have per-crtc
|
||||
* locking, and store the acquire ctx in the corresponding crtc. All other
|
||||
* legacy operations take all locks and use a global acquire context. This
|
||||
* function grabs the right one.
|
||||
*/
|
||||
struct drm_modeset_acquire_ctx *
|
||||
drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc)
|
||||
{
|
||||
if (crtc->acquire_ctx)
|
||||
return crtc->acquire_ctx;
|
||||
|
||||
WARN_ON(!crtc->dev->mode_config.acquire_ctx);
|
||||
|
||||
return crtc->dev->mode_config.acquire_ctx;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx);
|
||||
|
||||
/**
|
||||
* drm_modeset_unlock_crtc - drop crtc lock
|
||||
* @crtc: drm crtc
|
||||
*
|
||||
* This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other
|
||||
* locks acquired through the hidden context.
|
||||
*/
|
||||
void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx;
|
||||
|
||||
if (WARN_ON(!ctx))
|
||||
return;
|
||||
|
||||
crtc->acquire_ctx = NULL;
|
||||
drm_modeset_drop_locks(ctx);
|
||||
drm_modeset_acquire_fini(ctx);
|
||||
|
||||
kfree(ctx);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_modeset_unlock_crtc);
|
||||
|
||||
/**
|
||||
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
|
||||
* @dev: device
|
||||
*
|
||||
* Useful as a debug assert.
|
||||
*/
|
||||
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
/* Locking is currently fubar in the panic handler. */
|
||||
if (oops_in_progress)
|
||||
return;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
|
||||
|
||||
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
|
||||
|
||||
/**
|
||||
* drm_modeset_acquire_init - initialize acquire context
|
||||
* @ctx: the acquire context
|
||||
|
@ -108,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
|
|||
|
||||
WARN_ON(ctx->contended);
|
||||
|
||||
if (interruptible && slow) {
|
||||
if (ctx->trylock_only) {
|
||||
if (!ww_mutex_trylock(&lock->mutex))
|
||||
return -EBUSY;
|
||||
else
|
||||
return 0;
|
||||
} else if (interruptible && slow) {
|
||||
ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
|
||||
} else if (interruptible) {
|
||||
ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
|
||||
|
|
|
@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
|
|||
return;
|
||||
}
|
||||
|
||||
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
if (!connector->cmdline_mode.specified)
|
||||
return 0;
|
||||
|
||||
mode = drm_mode_create_from_cmdline_mode(connector->dev,
|
||||
&connector->cmdline_mode);
|
||||
if (mode == NULL)
|
||||
return 0;
|
||||
|
||||
drm_mode_probed_add(connector, mode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector,
|
||||
uint32_t maxX, uint32_t maxY, bool merge_type_bits)
|
||||
{
|
||||
|
@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
|
|||
|
||||
if (count == 0 && connector->status == connector_status_connected)
|
||||
count = drm_add_modes_noedid(connector, 1024, 768);
|
||||
count += drm_helper_probe_add_cmdline_mode(connector);
|
||||
if (count == 0)
|
||||
goto prune;
|
||||
|
||||
|
|
|
@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
|
|||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct mga_device *mdev = (struct mga_device*)dev->dev_private;
|
||||
struct mga_fbdev *mfbdev = mdev->mfbdev;
|
||||
struct drm_fb_helper *fb_helper = &mfbdev->helper;
|
||||
struct drm_fb_helper_connector *fb_helper_conn = NULL;
|
||||
int bpp = 32;
|
||||
int i = 0;
|
||||
|
||||
if (IS_G200_SE(mdev)) {
|
||||
if (mdev->unique_rev_id == 0x01) {
|
||||
|
@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
|
|||
}
|
||||
|
||||
/* Validate the mode input by the user */
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
if (fb_helper->connector_info[i]->connector == connector) {
|
||||
/* Found the helper for this connector */
|
||||
fb_helper_conn = fb_helper->connector_info[i];
|
||||
if (fb_helper_conn->cmdline_mode.specified) {
|
||||
if (fb_helper_conn->cmdline_mode.bpp_specified) {
|
||||
bpp = fb_helper_conn->cmdline_mode.bpp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connector->cmdline_mode.specified) {
|
||||
if (connector->cmdline_mode.bpp_specified)
|
||||
bpp = connector->cmdline_mode.bpp;
|
||||
}
|
||||
|
||||
if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) {
|
||||
if (fb_helper_conn)
|
||||
fb_helper_conn->cmdline_mode.specified = false;
|
||||
if (connector->cmdline_mode.specified)
|
||||
connector->cmdline_mode.specified = false;
|
||||
return MODE_BAD;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
menuconfig FB
|
||||
tristate "Support for frame buffer devices"
|
||||
select FB_CMDLINE
|
||||
---help---
|
||||
The frame buffer device provides an abstraction for the graphics
|
||||
hardware. It represents the frame buffer of some video hardware and
|
||||
|
@ -52,6 +53,9 @@ config FIRMWARE_EDID
|
|||
combination with certain motherboards and monitors are known to
|
||||
suffer from this problem.
|
||||
|
||||
config FB_CMDLINE
|
||||
bool
|
||||
|
||||
config FB_DDC
|
||||
tristate
|
||||
depends on FB
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
obj-y += fb_notify.o
|
||||
obj-$(CONFIG_FB_CMDLINE) += fb_cmdline.o
|
||||
obj-$(CONFIG_FB) += fb.o
|
||||
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
|
||||
modedb.o fbcvt.o
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* linux/drivers/video/fb_cmdline.c
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corp
|
||||
* Copyright (C) 1994 Martin Schaller
|
||||
*
|
||||
* 2001 - Documented with DocBook
|
||||
* - Brad Douglas <brad@neruo.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Authors:
|
||||
* Vetter <danie.vetter@ffwll.ch>
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
static char *video_options[FB_MAX] __read_mostly;
|
||||
static int ofonly __read_mostly;
|
||||
|
||||
const char *fb_mode_option;
|
||||
EXPORT_SYMBOL_GPL(fb_mode_option);
|
||||
|
||||
/**
|
||||
* fb_get_options - get kernel boot parameters
|
||||
* @name: framebuffer name as it would appear in
|
||||
* the boot parameter line
|
||||
* (video=<name>:<options>)
|
||||
* @option: the option will be stored here
|
||||
*
|
||||
* NOTE: Needed to maintain backwards compatibility
|
||||
*/
|
||||
int fb_get_options(const char *name, char **option)
|
||||
{
|
||||
char *opt, *options = NULL;
|
||||
int retval = 0;
|
||||
int name_len = strlen(name), i;
|
||||
|
||||
if (name_len && ofonly && strncmp(name, "offb", 4))
|
||||
retval = 1;
|
||||
|
||||
if (name_len && !retval) {
|
||||
for (i = 0; i < FB_MAX; i++) {
|
||||
if (video_options[i] == NULL)
|
||||
continue;
|
||||
if (!video_options[i][0])
|
||||
continue;
|
||||
opt = video_options[i];
|
||||
if (!strncmp(name, opt, name_len) &&
|
||||
opt[name_len] == ':')
|
||||
options = opt + name_len + 1;
|
||||
}
|
||||
}
|
||||
/* No match, pass global option */
|
||||
if (!options && option && fb_mode_option)
|
||||
options = kstrdup(fb_mode_option, GFP_KERNEL);
|
||||
if (options && !strncmp(options, "off", 3))
|
||||
retval = 1;
|
||||
|
||||
if (option)
|
||||
*option = options;
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_get_options);
|
||||
|
||||
/**
|
||||
* video_setup - process command line options
|
||||
* @options: string of options
|
||||
*
|
||||
* Process command line options for frame buffer subsystem.
|
||||
*
|
||||
* NOTE: This function is a __setup and __init function.
|
||||
* It only stores the options. Drivers have to call
|
||||
* fb_get_options() as necessary.
|
||||
*
|
||||
* Returns zero.
|
||||
*
|
||||
*/
|
||||
static int __init video_setup(char *options)
|
||||
{
|
||||
int i, global = 0;
|
||||
|
||||
if (!options || !*options)
|
||||
global = 1;
|
||||
|
||||
if (!global && !strncmp(options, "ofonly", 6)) {
|
||||
ofonly = 1;
|
||||
global = 1;
|
||||
}
|
||||
|
||||
if (!global && !strchr(options, ':')) {
|
||||
fb_mode_option = options;
|
||||
global = 1;
|
||||
}
|
||||
|
||||
if (!global) {
|
||||
for (i = 0; i < FB_MAX; i++) {
|
||||
if (video_options[i] == NULL) {
|
||||
video_options[i] = options;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("video=", video_setup);
|
|
@ -1908,96 +1908,4 @@ int fb_new_modelist(struct fb_info *info)
|
|||
return err;
|
||||
}
|
||||
|
||||
static char *video_options[FB_MAX] __read_mostly;
|
||||
static int ofonly __read_mostly;
|
||||
|
||||
/**
|
||||
* fb_get_options - get kernel boot parameters
|
||||
* @name: framebuffer name as it would appear in
|
||||
* the boot parameter line
|
||||
* (video=<name>:<options>)
|
||||
* @option: the option will be stored here
|
||||
*
|
||||
* NOTE: Needed to maintain backwards compatibility
|
||||
*/
|
||||
int fb_get_options(const char *name, char **option)
|
||||
{
|
||||
char *opt, *options = NULL;
|
||||
int retval = 0;
|
||||
int name_len = strlen(name), i;
|
||||
|
||||
if (name_len && ofonly && strncmp(name, "offb", 4))
|
||||
retval = 1;
|
||||
|
||||
if (name_len && !retval) {
|
||||
for (i = 0; i < FB_MAX; i++) {
|
||||
if (video_options[i] == NULL)
|
||||
continue;
|
||||
if (!video_options[i][0])
|
||||
continue;
|
||||
opt = video_options[i];
|
||||
if (!strncmp(name, opt, name_len) &&
|
||||
opt[name_len] == ':')
|
||||
options = opt + name_len + 1;
|
||||
}
|
||||
}
|
||||
/* No match, pass global option */
|
||||
if (!options && option && fb_mode_option)
|
||||
options = kstrdup(fb_mode_option, GFP_KERNEL);
|
||||
if (options && !strncmp(options, "off", 3))
|
||||
retval = 1;
|
||||
|
||||
if (option)
|
||||
*option = options;
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_get_options);
|
||||
|
||||
#ifndef MODULE
|
||||
/**
|
||||
* video_setup - process command line options
|
||||
* @options: string of options
|
||||
*
|
||||
* Process command line options for frame buffer subsystem.
|
||||
*
|
||||
* NOTE: This function is a __setup and __init function.
|
||||
* It only stores the options. Drivers have to call
|
||||
* fb_get_options() as necessary.
|
||||
*
|
||||
* Returns zero.
|
||||
*
|
||||
*/
|
||||
static int __init video_setup(char *options)
|
||||
{
|
||||
int i, global = 0;
|
||||
|
||||
if (!options || !*options)
|
||||
global = 1;
|
||||
|
||||
if (!global && !strncmp(options, "ofonly", 6)) {
|
||||
ofonly = 1;
|
||||
global = 1;
|
||||
}
|
||||
|
||||
if (!global && !strchr(options, ':')) {
|
||||
fb_mode_option = options;
|
||||
global = 1;
|
||||
}
|
||||
|
||||
if (!global) {
|
||||
for (i = 0; i < FB_MAX; i++) {
|
||||
if (video_options[i] == NULL) {
|
||||
video_options[i] = options;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("video=", video_setup);
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
#define DPRINTK(fmt, args...)
|
||||
#endif
|
||||
|
||||
const char *fb_mode_option;
|
||||
EXPORT_SYMBOL_GPL(fb_mode_option);
|
||||
|
||||
/*
|
||||
* Standard video mode definitions (taken from XFree86)
|
||||
*/
|
||||
|
|
|
@ -1294,6 +1294,8 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc);
|
|||
extern void drm_vblank_put(struct drm_device *dev, int crtc);
|
||||
extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
|
||||
extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
|
||||
extern void drm_wait_one_vblank(struct drm_device *dev, int crtc);
|
||||
extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
|
||||
extern void drm_vblank_off(struct drm_device *dev, int crtc);
|
||||
extern void drm_vblank_on(struct drm_device *dev, int crtc);
|
||||
extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
|
||||
|
|
|
@ -218,10 +218,6 @@ struct drm_property {
|
|||
struct list_head enum_blob_list;
|
||||
};
|
||||
|
||||
void drm_modeset_lock_all(struct drm_device *dev);
|
||||
void drm_modeset_unlock_all(struct drm_device *dev);
|
||||
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
|
||||
|
||||
struct drm_crtc;
|
||||
struct drm_connector;
|
||||
struct drm_encoder;
|
||||
|
@ -345,10 +341,6 @@ struct drm_crtc {
|
|||
int cursor_x;
|
||||
int cursor_y;
|
||||
|
||||
/* Temporary tracking of the old fb while a modeset is ongoing. Used
|
||||
* by drm_mode_set_config_internal to implement correct refcounting. */
|
||||
struct drm_framebuffer *old_fb;
|
||||
|
||||
bool enabled;
|
||||
|
||||
/* Requested mode from modesetting. */
|
||||
|
@ -375,6 +367,12 @@ struct drm_crtc {
|
|||
void *helper_private;
|
||||
|
||||
struct drm_object_properties properties;
|
||||
|
||||
/*
|
||||
* For legacy crtc ioctls so that atomic drivers can get at the locking
|
||||
* acquire context.
|
||||
*/
|
||||
struct drm_modeset_acquire_ctx *acquire_ctx;
|
||||
};
|
||||
|
||||
|
||||
|
@ -548,6 +546,7 @@ struct drm_connector {
|
|||
void *helper_private;
|
||||
|
||||
/* forced on connector */
|
||||
struct drm_cmdline_mode cmdline_mode;
|
||||
enum drm_connector_force force;
|
||||
bool override_edid;
|
||||
uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
|
||||
|
@ -582,6 +581,7 @@ struct drm_plane_funcs {
|
|||
uint32_t src_w, uint32_t src_h);
|
||||
int (*disable_plane)(struct drm_plane *plane);
|
||||
void (*destroy)(struct drm_plane *plane);
|
||||
void (*reset)(struct drm_plane *plane);
|
||||
|
||||
int (*set_property)(struct drm_plane *plane,
|
||||
struct drm_property *property, uint64_t val);
|
||||
|
@ -620,6 +620,10 @@ struct drm_plane {
|
|||
struct drm_crtc *crtc;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
/* Temporary tracking of the old fb while a modeset is ongoing. Used
|
||||
* by drm_mode_set_config_internal to implement correct refcounting. */
|
||||
struct drm_framebuffer *old_fb;
|
||||
|
||||
const struct drm_plane_funcs *funcs;
|
||||
|
||||
struct drm_object_properties properties;
|
||||
|
@ -903,6 +907,7 @@ int drm_connector_register(struct drm_connector *connector);
|
|||
void drm_connector_unregister(struct drm_connector *connector);
|
||||
|
||||
extern void drm_connector_cleanup(struct drm_connector *connector);
|
||||
extern unsigned int drm_connector_index(struct drm_connector *connector);
|
||||
/* helper to unplug all connectors from sysfs for device */
|
||||
extern void drm_connector_unplug_all(struct drm_device *dev);
|
||||
|
||||
|
@ -942,6 +947,7 @@ extern int drm_plane_init(struct drm_device *dev,
|
|||
const uint32_t *formats, uint32_t format_count,
|
||||
bool is_primary);
|
||||
extern void drm_plane_cleanup(struct drm_plane *plane);
|
||||
extern unsigned int drm_plane_index(struct drm_plane *plane);
|
||||
extern void drm_plane_force_disable(struct drm_plane *plane);
|
||||
extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
|
||||
int x, int y,
|
||||
|
|
|
@ -77,7 +77,6 @@ struct drm_fb_helper_funcs {
|
|||
|
||||
struct drm_fb_helper_connector {
|
||||
struct drm_connector *connector;
|
||||
struct drm_cmdline_mode cmdline_mode;
|
||||
};
|
||||
|
||||
struct drm_fb_helper {
|
||||
|
|
|
@ -53,6 +53,11 @@ struct drm_modeset_acquire_ctx {
|
|||
* list of held locks (drm_modeset_lock)
|
||||
*/
|
||||
struct list_head locked;
|
||||
|
||||
/**
|
||||
* Trylock mode, use only for panic handlers!
|
||||
*/
|
||||
bool trylock_only;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -120,6 +125,17 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock,
|
|||
void drm_modeset_unlock(struct drm_modeset_lock *lock);
|
||||
|
||||
struct drm_device;
|
||||
struct drm_crtc;
|
||||
|
||||
void drm_modeset_lock_all(struct drm_device *dev);
|
||||
int __drm_modeset_lock_all(struct drm_device *dev, bool trylock);
|
||||
void drm_modeset_unlock_all(struct drm_device *dev);
|
||||
void drm_modeset_lock_crtc(struct drm_crtc *crtc);
|
||||
void drm_modeset_unlock_crtc(struct drm_crtc *crtc);
|
||||
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
|
||||
struct drm_modeset_acquire_ctx *
|
||||
drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc);
|
||||
|
||||
int drm_modeset_lock_all_crtcs(struct drm_device *dev,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
|
||||
|
|
Loading…
Reference in New Issue