From 3f61ba72bb19d7fc92fcaf9be0ee90c9bebd79ad Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Fri, 22 Jan 2016 05:09:08 +0000 Subject: [PATCH] i915-4.4 set active connector and mode from command line. git-svn-id: svn://kolibrios.org@6088 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/video/drm/drm_atomic_helper.c | 2 +- drivers/video/drm/drm_crtc.c | 3 - drivers/video/drm/drm_dp_helper.c | 10 +- drivers/video/drm/drm_dp_mst_topology.c | 3 +- drivers/video/drm/drm_fb_helper.c | 5 +- drivers/video/drm/drm_gem.c | 8 +- drivers/video/drm/drm_irq.c | 306 +++++++++++++++++- drivers/video/drm/drm_mipi_dsi.c | 2 +- drivers/video/drm/drm_modes.c | 208 ++++++++++++ drivers/video/drm/drm_probe_helper.c | 1 + drivers/video/drm/i915/i915.asm | 63 ++-- drivers/video/drm/i915/i915_cmd_parser.c | 2 +- drivers/video/drm/i915/i915_dma.c | 18 +- drivers/video/drm/i915/i915_drv.h | 4 + drivers/video/drm/i915/i915_gem.c | 33 +- drivers/video/drm/i915/i915_gem_fence.c | 2 +- drivers/video/drm/i915/i915_irq.c | 18 +- drivers/video/drm/i915/i915_params.c | 5 +- drivers/video/drm/i915/intel_display.c | 16 +- drivers/video/drm/i915/intel_fbdev.c | 2 +- drivers/video/drm/i915/intel_lrc.c | 2 +- drivers/video/drm/i915/intel_panel.c | 2 +- drivers/video/drm/i915/intel_sprite.c | 1 - drivers/video/drm/i915/kms_display.c | 391 +++++++++++++++++++---- drivers/video/drm/i915/main.c | 343 +++++++++----------- drivers/video/drm/i915/utils.c | 182 +++++++++++ 26 files changed, 1268 insertions(+), 364 deletions(-) diff --git a/drivers/video/drm/drm_atomic_helper.c b/drivers/video/drm/drm_atomic_helper.c index 0809657391..e5aec45bf9 100644 --- a/drivers/video/drm/drm_atomic_helper.c +++ b/drivers/video/drm/drm_atomic_helper.c @@ -1065,7 +1065,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, drm_atomic_helper_commit_modeset_enables(dev, state); -// drm_atomic_helper_wait_for_vblanks(dev, state); + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); diff --git a/drivers/video/drm/drm_crtc.c b/drivers/video/drm/drm_crtc.c index 3c103ddaa7..7e0811397f 100644 --- a/drivers/video/drm/drm_crtc.c +++ b/drivers/video/drm/drm_crtc.c @@ -818,8 +818,6 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector) struct drm_cmdline_mode *mode = &connector->cmdline_mode; char *option = NULL; - return; -#if 0 if (fb_get_options(connector->name, &option)) return; @@ -855,7 +853,6 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector) mode->rb ? " reduced blanking" : "", mode->margins ? " with margins" : "", mode->interlace ? " interlaced" : ""); -#endif } /** diff --git a/drivers/video/drm/drm_dp_helper.c b/drivers/video/drm/drm_dp_helper.c index 9d2e8943fc..4b825c3f8b 100644 --- a/drivers/video/drm/drm_dp_helper.c +++ b/drivers/video/drm/drm_dp_helper.c @@ -23,7 +23,7 @@ #include #include //#include -//#include +#include #include #include #include @@ -215,7 +215,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, return -EIO; case DP_AUX_NATIVE_REPLY_DEFER: - usleep(500); + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); break; } } @@ -349,7 +349,7 @@ int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink * Control Field" (register 0x600). */ - usleep(2000); + usleep_range(1000, 2000); return 0; } @@ -578,7 +578,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) * For now just defer for long enough to hopefully be * safe for all use-cases. */ - usleep_range(500, 600); + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); continue; default: @@ -610,7 +610,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) aux->i2c_defer_count++; if (defer_i2c < 7) defer_i2c++; - usleep_range(400, 500); + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); drm_dp_i2c_msg_write_status_update(msg); continue; diff --git a/drivers/video/drm/drm_dp_mst_topology.c b/drivers/video/drm/drm_dp_mst_topology.c index c8e7d1f265..8cbd03e59b 100644 --- a/drivers/video/drm/drm_dp_mst_topology.c +++ b/drivers/video/drm/drm_dp_mst_topology.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2651,7 +2652,7 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, INIT_LIST_HEAD(&mgr->destroy_connector_list); INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work); INIT_WORK(&mgr->tx_work, drm_dp_tx_work); -// init_waitqueue_head(&mgr->tx_waitq); + init_waitqueue_head(&mgr->tx_waitq); mgr->dev = dev; mgr->aux = aux; mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; diff --git a/drivers/video/drm/drm_fb_helper.c b/drivers/video/drm/drm_fb_helper.c index 74277849be..f82054ac85 100644 --- a/drivers/video/drm/drm_fb_helper.c +++ b/drivers/video/drm/drm_fb_helper.c @@ -1324,11 +1324,9 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f struct drm_display_mode *mode; bool prefer_non_interlace; - return NULL; -#if 0 cmdline_mode = &fb_helper_conn->connector->cmdline_mode; if (cmdline_mode->specified == false) - return NULL; + return NULL; /* attempt to find a matching mode in the list of modes * we have gotten so far, if not add a CVT mode that conforms @@ -1369,7 +1367,6 @@ create_mode: cmdline_mode); list_add(&mode->head, &fb_helper_conn->connector->modes); return mode; -#endif } EXPORT_SYMBOL(drm_pick_cmdline_mode); diff --git a/drivers/video/drm/drm_gem.c b/drivers/video/drm/drm_gem.c index 8964a8aefa..afea62280a 100644 --- a/drivers/video/drm/drm_gem.c +++ b/drivers/video/drm/drm_gem.c @@ -253,7 +253,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, filp); - drm_gem_object_handle_unreference_unlocked(obj); + drm_gem_object_handle_unreference_unlocked(obj); return 0; } @@ -264,7 +264,7 @@ EXPORT_SYMBOL(drm_gem_handle_delete); * @file: drm file-private structure to remove the dumb handle from * @dev: corresponding drm_device * @handle: the dumb handle to remove - * + * * This implements the ->dumb_destroy kms driver callback for drivers which use * gem to manage their backing storage. */ @@ -751,10 +751,6 @@ void drm_gem_vm_open(struct vm_area_struct *vma) struct drm_gem_object *obj = vma->vm_private_data; drm_gem_object_reference(obj); - - mutex_lock(&obj->dev->struct_mutex); - drm_vm_open_locked(obj->dev, vma); - mutex_unlock(&obj->dev->struct_mutex); } EXPORT_SYMBOL(drm_gem_vm_open); diff --git a/drivers/video/drm/drm_irq.c b/drivers/video/drm/drm_irq.c index 65eaba286f..3cce9291b6 100644 --- a/drivers/video/drm/drm_irq.c +++ b/drivers/video/drm/drm_irq.c @@ -370,8 +370,8 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) vblank->dev = dev; vblank->pipe = i; init_waitqueue_head(&vblank->queue); -// setup_timer(&vblank->disable_timer, vblank_disable_fn, -// (unsigned long)vblank); + setup_timer(&vblank->disable_timer, vblank_disable_fn, + (unsigned long)vblank); } DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); @@ -829,6 +829,140 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, return cur_vblank; } EXPORT_SYMBOL(drm_vblank_count_and_time); + +/** + * drm_crtc_vblank_count_and_time - retrieve "cooked" vblank counter value + * and the system timestamp corresponding to that vblank counter value + * @crtc: which counter to retrieve + * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. + * + * Fetches the "cooked" vblank count value that represents the number of + * vblank events since the system was booted, including lost events due to + * modesetting activity. Returns corresponding system timestamp of the time + * of the vblank interval that corresponds to the current vblank counter value. + * + * This is the native KMS version of drm_vblank_count_and_time(). + */ +u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, + struct timeval *vblanktime) +{ + return drm_vblank_count_and_time(crtc->dev, drm_crtc_index(crtc), + vblanktime); +} +EXPORT_SYMBOL(drm_crtc_vblank_count_and_time); + +static void send_vblank_event(struct drm_device *dev, + struct drm_pending_vblank_event *e, + unsigned long seq, struct timeval *now) +{ + assert_spin_locked(&dev->event_lock); + + e->event.sequence = seq; + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_add_tail(&e->base.link, + &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); +} + +/** + * drm_arm_vblank_event - arm vblank event after pageflip + * @dev: DRM device + * @pipe: CRTC index + * @e: the event to prepare to send + * + * A lot of drivers need to generate vblank events for the very next vblank + * interrupt. For example when the page flip interrupt happens when the page + * flip gets armed, but not when it actually executes within the next vblank + * period. This helper function implements exactly the required vblank arming + * behaviour. + * + * Caller must hold event lock. Caller must also hold a vblank reference for + * the event @e, which will be dropped when the next vblank arrives. + * + * This is the legacy version of drm_crtc_arm_vblank_event(). + */ +void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe, + struct drm_pending_vblank_event *e) +{ + assert_spin_locked(&dev->event_lock); + + e->pipe = pipe; + e->event.sequence = drm_vblank_count(dev, pipe); + list_add_tail(&e->base.link, &dev->vblank_event_list); +} +EXPORT_SYMBOL(drm_arm_vblank_event); + +/** + * drm_crtc_arm_vblank_event - arm vblank event after pageflip + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * A lot of drivers need to generate vblank events for the very next vblank + * interrupt. For example when the page flip interrupt happens when the page + * flip gets armed, but not when it actually executes within the next vblank + * period. This helper function implements exactly the required vblank arming + * behaviour. + * + * Caller must hold event lock. Caller must also hold a vblank reference for + * the event @e, which will be dropped when the next vblank arrives. + * + * This is the native KMS version of drm_arm_vblank_event(). + */ +void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) +{ + drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e); +} +EXPORT_SYMBOL(drm_crtc_arm_vblank_event); + +/** + * drm_send_vblank_event - helper to send vblank event after pageflip + * @dev: DRM device + * @pipe: CRTC index + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + * + * This is the legacy version of drm_crtc_send_vblank_event(). + */ +void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe, + struct drm_pending_vblank_event *e) +{ + struct timeval now; + unsigned int seq; + + if (dev->num_crtcs > 0) { + seq = drm_vblank_count_and_time(dev, pipe, &now); + } else { + seq = 0; + + now = get_drm_timestamp(); + } + e->pipe = pipe; + send_vblank_event(dev, e, seq, &now); +} +EXPORT_SYMBOL(drm_send_vblank_event); + +/** + * drm_crtc_send_vblank_event - helper to send vblank event after pageflip + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + * + * This is the native KMS version of drm_send_vblank_event(). + */ +void drm_crtc_send_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) +{ + drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e); +} +EXPORT_SYMBOL(drm_crtc_send_vblank_event); + /** * drm_vblank_enable - enable the vblank interrupt on a CRTC * @dev: DRM device @@ -952,11 +1086,8 @@ void drm_vblank_put(struct drm_device *dev, unsigned int pipe) if (atomic_dec_and_test(&vblank->refcount)) { if (drm_vblank_offdelay == 0) return; - else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) + else vblank_disable_fn((unsigned long)vblank); - else - mod_timer(&vblank->disable_timer, - jiffies + ((drm_vblank_offdelay * HZ)/1000)); } } EXPORT_SYMBOL(drm_vblank_put); @@ -987,24 +1118,26 @@ EXPORT_SYMBOL(drm_crtc_vblank_put); */ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) { -#if 0 + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; int ret; u32 last; - ret = drm_vblank_get(dev, crtc); - if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret)) + if (WARN_ON(pipe >= dev->num_crtcs)) return; - last = drm_vblank_count(dev, crtc); + ret = drm_vblank_get(dev, pipe); + if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", pipe, ret)) + return; - ret = wait_event_timeout(dev->vblank[crtc].queue, - last != drm_vblank_count(dev, crtc), + last = drm_vblank_count(dev, pipe); + + ret = wait_event_timeout(vblank->queue, + last != drm_vblank_count(dev, pipe), msecs_to_jiffies(100)); - WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc); + WARN(ret == 0, "vblank wait timed out on crtc %i\n", pipe); - drm_vblank_put(dev, crtc); -#endif + drm_vblank_put(dev, pipe); } EXPORT_SYMBOL(drm_wait_one_vblank); @@ -1044,7 +1177,39 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe) unsigned long irqflags; unsigned int seq; + if (WARN_ON(pipe >= dev->num_crtcs)) + return; + spin_lock_irqsave(&dev->event_lock, irqflags); + + spin_lock(&dev->vbl_lock); + vblank_disable_and_save(dev, pipe); + wake_up(&vblank->queue); + + /* + * Prevent subsequent drm_vblank_get() from re-enabling + * the vblank interrupt by bumping the refcount. + */ + if (!vblank->inmodeset) { + atomic_inc(&vblank->refcount); + vblank->inmodeset = 1; + } + spin_unlock(&dev->vbl_lock); + + /* Send any queued vblank events, lest the natives grow disquiet */ + seq = drm_vblank_count_and_time(dev, pipe, &now); + + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != pipe) + continue; + DRM_DEBUG("Sending premature vblank event on disable: " + "wanted %d, current %d\n", + e->event.sequence, seq); + list_del(&e->base.link); + drm_vblank_put(dev, pipe); + send_vblank_event(dev, e, seq, &now); + } + spin_unlock_irqrestore(&dev->event_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); @@ -1116,8 +1281,6 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; - dbgprintf("%s pipe %d dev->num_crtcs %d\n", pipe,dev->num_crtcs);\ - if (WARN_ON(pipe >= dev->num_crtcs)) return; @@ -1240,6 +1403,115 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) } EXPORT_SYMBOL(drm_vblank_post_modeset); +static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) +{ + struct drm_pending_vblank_event *e, *t; + struct timeval now; + unsigned int seq; + + assert_spin_locked(&dev->event_lock); + + seq = drm_vblank_count_and_time(dev, pipe, &now); + + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != pipe) + continue; + if ((seq - e->event.sequence) > (1<<23)) + continue; + + DRM_DEBUG("vblank event on %d, current %d\n", + e->event.sequence, seq); + + list_del(&e->base.link); + drm_vblank_put(dev, pipe); + send_vblank_event(dev, e, seq, &now); + } + +} + +/** + * drm_handle_vblank - handle a vblank event + * @dev: DRM device + * @pipe: index of CRTC where this event occurred + * + * Drivers should call this routine in their vblank interrupt handlers to + * update the vblank counter and send any signals that may be pending. + * + * This is the legacy version of drm_crtc_handle_vblank(). + */ +bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) +{ + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + unsigned long irqflags; + + if (WARN_ON_ONCE(!dev->num_crtcs)) + return false; + + if (WARN_ON(pipe >= dev->num_crtcs)) + return false; + + spin_lock_irqsave(&dev->event_lock, irqflags); + + /* Need timestamp lock to prevent concurrent execution with + * vblank enable/disable, as this would cause inconsistent + * or corrupted timestamps and vblank counts. + */ + spin_lock(&dev->vblank_time_lock); + + /* Vblank irq handling disabled. Nothing to do. */ + if (!vblank->enabled) { + spin_unlock(&dev->vblank_time_lock); + spin_unlock_irqrestore(&dev->event_lock, irqflags); + return false; + } + + drm_update_vblank_count(dev, pipe, DRM_CALLED_FROM_VBLIRQ); + + spin_unlock(&dev->vblank_time_lock); + + wake_up(&vblank->queue); + drm_handle_vblank_events(dev, pipe); + + spin_unlock_irqrestore(&dev->event_lock, irqflags); + + return true; +} +EXPORT_SYMBOL(drm_handle_vblank); + +/** + * drm_crtc_handle_vblank - handle a vblank event + * @crtc: where this event occurred + * + * Drivers should call this routine in their vblank interrupt handlers to + * update the vblank counter and send any signals that may be pending. + * + * This is the native KMS version of drm_handle_vblank(). + * + * Returns: + * True if the event was successfully handled, false on failure. + */ +bool drm_crtc_handle_vblank(struct drm_crtc *crtc) +{ + return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_handle_vblank); + +/** + * drm_vblank_no_hw_counter - "No hw counter" implementation of .get_vblank_counter() + * @dev: DRM device + * @pipe: CRTC for which to read the counter + * + * Drivers can plug this into the .get_vblank_counter() function if + * there is no useable hardware frame counter available. + * + * Returns: + * 0 + */ +u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) +{ + return 0; +} +EXPORT_SYMBOL(drm_vblank_no_hw_counter); u64 div64_u64(u64 dividend, u64 divisor) { diff --git a/drivers/video/drm/drm_mipi_dsi.c b/drivers/video/drm/drm_mipi_dsi.c index b1e3581278..b8a73a5985 100644 --- a/drivers/video/drm/drm_mipi_dsi.c +++ b/drivers/video/drm/drm_mipi_dsi.c @@ -32,7 +32,7 @@ #include //#include #include -//#include +#include #include