162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * drm_irq.c IRQ and vblank support 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * \author Rickard E. (Rik) Faith <faith@valinux.com> 562306a36Sopenharmony_ci * \author Gareth Hughes <gareth@valinux.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 862306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 962306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 1062306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1162306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1262306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next 1562306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 1662306a36Sopenharmony_ci * Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2262306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2362306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2462306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/export.h> 2862306a36Sopenharmony_ci#include <linux/kthread.h> 2962306a36Sopenharmony_ci#include <linux/moduleparam.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <drm/drm_crtc.h> 3262306a36Sopenharmony_ci#include <drm/drm_drv.h> 3362306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 3462306a36Sopenharmony_ci#include <drm/drm_managed.h> 3562306a36Sopenharmony_ci#include <drm/drm_modeset_helper_vtables.h> 3662306a36Sopenharmony_ci#include <drm/drm_print.h> 3762306a36Sopenharmony_ci#include <drm/drm_vblank.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "drm_internal.h" 4062306a36Sopenharmony_ci#include "drm_trace.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/** 4362306a36Sopenharmony_ci * DOC: vblank handling 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * From the computer's perspective, every time the monitor displays 4662306a36Sopenharmony_ci * a new frame the scanout engine has "scanned out" the display image 4762306a36Sopenharmony_ci * from top to bottom, one row of pixels at a time. The current row 4862306a36Sopenharmony_ci * of pixels is referred to as the current scanline. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * In addition to the display's visible area, there's usually a couple of 5162306a36Sopenharmony_ci * extra scanlines which aren't actually displayed on the screen. 5262306a36Sopenharmony_ci * These extra scanlines don't contain image data and are occasionally used 5362306a36Sopenharmony_ci * for features like audio and infoframes. The region made up of these 5462306a36Sopenharmony_ci * scanlines is referred to as the vertical blanking region, or vblank for 5562306a36Sopenharmony_ci * short. 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * For historical reference, the vertical blanking period was designed to 5862306a36Sopenharmony_ci * give the electron gun (on CRTs) enough time to move back to the top of 5962306a36Sopenharmony_ci * the screen to start scanning out the next frame. Similar for horizontal 6062306a36Sopenharmony_ci * blanking periods. They were designed to give the electron gun enough 6162306a36Sopenharmony_ci * time to move back to the other side of the screen to start scanning the 6262306a36Sopenharmony_ci * next scanline. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * :: 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * physical → ⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽ 6862306a36Sopenharmony_ci * top of | | 6962306a36Sopenharmony_ci * display | | 7062306a36Sopenharmony_ci * | New frame | 7162306a36Sopenharmony_ci * | | 7262306a36Sopenharmony_ci * |↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓| 7362306a36Sopenharmony_ci * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| ← Scanline, 7462306a36Sopenharmony_ci * |↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓| updates the 7562306a36Sopenharmony_ci * | | frame as it 7662306a36Sopenharmony_ci * | | travels down 7762306a36Sopenharmony_ci * | | ("scan out") 7862306a36Sopenharmony_ci * | Old frame | 7962306a36Sopenharmony_ci * | | 8062306a36Sopenharmony_ci * | | 8162306a36Sopenharmony_ci * | | 8262306a36Sopenharmony_ci * | | physical 8362306a36Sopenharmony_ci * | | bottom of 8462306a36Sopenharmony_ci * vertical |⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽| ← display 8562306a36Sopenharmony_ci * blanking ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆ 8662306a36Sopenharmony_ci * region → ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆ 8762306a36Sopenharmony_ci * ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆ 8862306a36Sopenharmony_ci * start of → ⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽ 8962306a36Sopenharmony_ci * new frame 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * "Physical top of display" is the reference point for the high-precision/ 9262306a36Sopenharmony_ci * corrected timestamp. 9362306a36Sopenharmony_ci * 9462306a36Sopenharmony_ci * On a lot of display hardware, programming needs to take effect during the 9562306a36Sopenharmony_ci * vertical blanking period so that settings like gamma, the image buffer 9662306a36Sopenharmony_ci * buffer to be scanned out, etc. can safely be changed without showing 9762306a36Sopenharmony_ci * any visual artifacts on the screen. In some unforgiving hardware, some of 9862306a36Sopenharmony_ci * this programming has to both start and end in the same vblank. To help 9962306a36Sopenharmony_ci * with the timing of the hardware programming, an interrupt is usually 10062306a36Sopenharmony_ci * available to notify the driver when it can start the updating of registers. 10162306a36Sopenharmony_ci * The interrupt is in this context named the vblank interrupt. 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * The vblank interrupt may be fired at different points depending on the 10462306a36Sopenharmony_ci * hardware. Some hardware implementations will fire the interrupt when the 10562306a36Sopenharmony_ci * new frame start, other implementations will fire the interrupt at different 10662306a36Sopenharmony_ci * points in time. 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * Vertical blanking plays a major role in graphics rendering. To achieve 10962306a36Sopenharmony_ci * tear-free display, users must synchronize page flips and/or rendering to 11062306a36Sopenharmony_ci * vertical blanking. The DRM API offers ioctls to perform page flips 11162306a36Sopenharmony_ci * synchronized to vertical blanking and wait for vertical blanking. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * The DRM core handles most of the vertical blanking management logic, which 11462306a36Sopenharmony_ci * involves filtering out spurious interrupts, keeping race-free blanking 11562306a36Sopenharmony_ci * counters, coping with counter wrap-around and resets and keeping use counts. 11662306a36Sopenharmony_ci * It relies on the driver to generate vertical blanking interrupts and 11762306a36Sopenharmony_ci * optionally provide a hardware vertical blanking counter. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * Drivers must initialize the vertical blanking handling core with a call to 12062306a36Sopenharmony_ci * drm_vblank_init(). Minimally, a driver needs to implement 12162306a36Sopenharmony_ci * &drm_crtc_funcs.enable_vblank and &drm_crtc_funcs.disable_vblank plus call 12262306a36Sopenharmony_ci * drm_crtc_handle_vblank() in its vblank interrupt handler for working vblank 12362306a36Sopenharmony_ci * support. 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * Vertical blanking interrupts can be enabled by the DRM core or by drivers 12662306a36Sopenharmony_ci * themselves (for instance to handle page flipping operations). The DRM core 12762306a36Sopenharmony_ci * maintains a vertical blanking use count to ensure that the interrupts are not 12862306a36Sopenharmony_ci * disabled while a user still needs them. To increment the use count, drivers 12962306a36Sopenharmony_ci * call drm_crtc_vblank_get() and release the vblank reference again with 13062306a36Sopenharmony_ci * drm_crtc_vblank_put(). In between these two calls vblank interrupts are 13162306a36Sopenharmony_ci * guaranteed to be enabled. 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * On many hardware disabling the vblank interrupt cannot be done in a race-free 13462306a36Sopenharmony_ci * manner, see &drm_driver.vblank_disable_immediate and 13562306a36Sopenharmony_ci * &drm_driver.max_vblank_count. In that case the vblank core only disables the 13662306a36Sopenharmony_ci * vblanks after a timer has expired, which can be configured through the 13762306a36Sopenharmony_ci * ``vblankoffdelay`` module parameter. 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Drivers for hardware without support for vertical-blanking interrupts 14062306a36Sopenharmony_ci * must not call drm_vblank_init(). For such drivers, atomic helpers will 14162306a36Sopenharmony_ci * automatically generate fake vblank events as part of the display update. 14262306a36Sopenharmony_ci * This functionality also can be controlled by the driver by enabling and 14362306a36Sopenharmony_ci * disabling struct drm_crtc_state.no_vblank. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* Retry timestamp calculation up to 3 times to satisfy 14762306a36Sopenharmony_ci * drm_timestamp_precision before giving up. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci#define DRM_TIMESTAMP_MAXRETRIES 3 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* Threshold in nanoseconds for detection of redundant 15262306a36Sopenharmony_ci * vblank irq in drm_handle_vblank(). 1 msec should be ok. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic bool 15762306a36Sopenharmony_cidrm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, 15862306a36Sopenharmony_ci ktime_t *tvblank, bool in_vblank_irq); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cimodule_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); 16562306a36Sopenharmony_cimodule_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); 16662306a36Sopenharmony_ciMODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); 16762306a36Sopenharmony_ciMODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void store_vblank(struct drm_device *dev, unsigned int pipe, 17062306a36Sopenharmony_ci u32 vblank_count_inc, 17162306a36Sopenharmony_ci ktime_t t_vblank, u32 last) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci assert_spin_locked(&dev->vblank_time_lock); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci vblank->last = last; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci write_seqlock(&vblank->seqlock); 18062306a36Sopenharmony_ci vblank->time = t_vblank; 18162306a36Sopenharmony_ci atomic64_add(vblank_count_inc, &vblank->count); 18262306a36Sopenharmony_ci write_sequnlock(&vblank->seqlock); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return vblank->max_vblank_count ?: dev->max_vblank_count; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* 19362306a36Sopenharmony_ci * "No hw counter" fallback implementation of .get_vblank_counter() hook, 19462306a36Sopenharmony_ci * if there is no usable hardware frame counter available. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_cistatic u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci drm_WARN_ON_ONCE(dev, drm_max_vblank_count(dev, pipe) != 0); 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 20562306a36Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (drm_WARN_ON(dev, !crtc)) 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (crtc->funcs->get_vblank_counter) 21162306a36Sopenharmony_ci return crtc->funcs->get_vblank_counter(crtc); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci#ifdef CONFIG_DRM_LEGACY 21462306a36Sopenharmony_ci else if (dev->driver->get_vblank_counter) { 21562306a36Sopenharmony_ci return dev->driver->get_vblank_counter(dev, pipe); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci#endif 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return drm_vblank_no_hw_counter(dev, pipe); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * Reset the stored timestamp for the current vblank count to correspond 22462306a36Sopenharmony_ci * to the last vblank occurred. 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Only to be called from drm_crtc_vblank_on(). 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Note: caller must hold &drm_device.vbl_lock since this reads & writes 22962306a36Sopenharmony_ci * device vblank fields. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_cistatic void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u32 cur_vblank; 23462306a36Sopenharmony_ci bool rc; 23562306a36Sopenharmony_ci ktime_t t_vblank; 23662306a36Sopenharmony_ci int count = DRM_TIMESTAMP_MAXRETRIES; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci spin_lock(&dev->vblank_time_lock); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* 24162306a36Sopenharmony_ci * sample the current counter to avoid random jumps 24262306a36Sopenharmony_ci * when drm_vblank_enable() applies the diff 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci do { 24562306a36Sopenharmony_ci cur_vblank = __get_vblank_counter(dev, pipe); 24662306a36Sopenharmony_ci rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); 24762306a36Sopenharmony_ci } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* 25062306a36Sopenharmony_ci * Only reinitialize corresponding vblank timestamp if high-precision query 25162306a36Sopenharmony_ci * available and didn't fail. Otherwise reinitialize delayed at next vblank 25262306a36Sopenharmony_ci * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci if (!rc) 25562306a36Sopenharmony_ci t_vblank = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * +1 to make sure user will never see the same 25962306a36Sopenharmony_ci * vblank counter value before and after a modeset 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci store_vblank(dev, pipe, 1, t_vblank, cur_vblank); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* 26762306a36Sopenharmony_ci * Call back into the driver to update the appropriate vblank counter 26862306a36Sopenharmony_ci * (specified by @pipe). Deal with wraparound, if it occurred, and 26962306a36Sopenharmony_ci * update the last read value so we can deal with wraparound on the next 27062306a36Sopenharmony_ci * call if necessary. 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * Only necessary when going from off->on, to account for frames we 27362306a36Sopenharmony_ci * didn't get an interrupt for. 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * Note: caller must hold &drm_device.vbl_lock since this reads & writes 27662306a36Sopenharmony_ci * device vblank fields. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_cistatic void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, 27962306a36Sopenharmony_ci bool in_vblank_irq) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 28262306a36Sopenharmony_ci u32 cur_vblank, diff; 28362306a36Sopenharmony_ci bool rc; 28462306a36Sopenharmony_ci ktime_t t_vblank; 28562306a36Sopenharmony_ci int count = DRM_TIMESTAMP_MAXRETRIES; 28662306a36Sopenharmony_ci int framedur_ns = vblank->framedur_ns; 28762306a36Sopenharmony_ci u32 max_vblank_count = drm_max_vblank_count(dev, pipe); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * Interrupts were disabled prior to this call, so deal with counter 29162306a36Sopenharmony_ci * wrap if needed. 29262306a36Sopenharmony_ci * NOTE! It's possible we lost a full dev->max_vblank_count + 1 events 29362306a36Sopenharmony_ci * here if the register is small or we had vblank interrupts off for 29462306a36Sopenharmony_ci * a long time. 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * We repeat the hardware vblank counter & timestamp query until 29762306a36Sopenharmony_ci * we get consistent results. This to prevent races between gpu 29862306a36Sopenharmony_ci * updating its hardware counter while we are retrieving the 29962306a36Sopenharmony_ci * corresponding vblank timestamp. 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci do { 30262306a36Sopenharmony_ci cur_vblank = __get_vblank_counter(dev, pipe); 30362306a36Sopenharmony_ci rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); 30462306a36Sopenharmony_ci } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (max_vblank_count) { 30762306a36Sopenharmony_ci /* trust the hw counter when it's around */ 30862306a36Sopenharmony_ci diff = (cur_vblank - vblank->last) & max_vblank_count; 30962306a36Sopenharmony_ci } else if (rc && framedur_ns) { 31062306a36Sopenharmony_ci u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * Figure out how many vblanks we've missed based 31462306a36Sopenharmony_ci * on the difference in the timestamps and the 31562306a36Sopenharmony_ci * frame/field duration. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci drm_dbg_vbl(dev, "crtc %u: Calculating number of vblanks." 31962306a36Sopenharmony_ci " diff_ns = %lld, framedur_ns = %d)\n", 32062306a36Sopenharmony_ci pipe, (long long)diff_ns, framedur_ns); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (diff == 0 && in_vblank_irq) 32562306a36Sopenharmony_ci drm_dbg_vbl(dev, "crtc %u: Redundant vblirq ignored\n", 32662306a36Sopenharmony_ci pipe); 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci /* some kind of default for drivers w/o accurate vbl timestamping */ 32962306a36Sopenharmony_ci diff = in_vblank_irq ? 1 : 0; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset 33462306a36Sopenharmony_ci * interval? If so then vblank irqs keep running and it will likely 33562306a36Sopenharmony_ci * happen that the hardware vblank counter is not trustworthy as it 33662306a36Sopenharmony_ci * might reset at some point in that interval and vblank timestamps 33762306a36Sopenharmony_ci * are not trustworthy either in that interval. Iow. this can result 33862306a36Sopenharmony_ci * in a bogus diff >> 1 which must be avoided as it would cause 33962306a36Sopenharmony_ci * random large forward jumps of the software vblank counter. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci if (diff > 1 && (vblank->inmodeset & 0x2)) { 34262306a36Sopenharmony_ci drm_dbg_vbl(dev, 34362306a36Sopenharmony_ci "clamping vblank bump to 1 on crtc %u: diffr=%u" 34462306a36Sopenharmony_ci " due to pre-modeset.\n", pipe, diff); 34562306a36Sopenharmony_ci diff = 1; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci drm_dbg_vbl(dev, "updating vblank count on crtc %u:" 34962306a36Sopenharmony_ci " current=%llu, diff=%u, hw=%u hw_last=%u\n", 35062306a36Sopenharmony_ci pipe, (unsigned long long)atomic64_read(&vblank->count), 35162306a36Sopenharmony_ci diff, cur_vblank, vblank->last); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (diff == 0) { 35462306a36Sopenharmony_ci drm_WARN_ON_ONCE(dev, cur_vblank != vblank->last); 35562306a36Sopenharmony_ci return; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * Only reinitialize corresponding vblank timestamp if high-precision query 36062306a36Sopenharmony_ci * available and didn't fail, or we were called from the vblank interrupt. 36162306a36Sopenharmony_ci * Otherwise reinitialize delayed at next vblank interrupt and assign 0 36262306a36Sopenharmony_ci * for now, to mark the vblanktimestamp as invalid. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci if (!rc && !in_vblank_irq) 36562306a36Sopenharmony_ci t_vblank = 0; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci store_vblank(dev, pipe, diff, t_vblank, cur_vblank); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ciu64 drm_vblank_count(struct drm_device *dev, unsigned int pipe) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 37362306a36Sopenharmony_ci u64 count; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci count = atomic64_read(&vblank->count); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * This read barrier corresponds to the implicit write barrier of the 38262306a36Sopenharmony_ci * write seqlock in store_vblank(). Note that this is the only place 38362306a36Sopenharmony_ci * where we need an explicit barrier, since all other access goes 38462306a36Sopenharmony_ci * through drm_vblank_count_and_time(), which already has the required 38562306a36Sopenharmony_ci * read barrier curtesy of the read seqlock. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci smp_rmb(); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return count; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/** 39362306a36Sopenharmony_ci * drm_crtc_accurate_vblank_count - retrieve the master vblank counter 39462306a36Sopenharmony_ci * @crtc: which counter to retrieve 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * This function is similar to drm_crtc_vblank_count() but this function 39762306a36Sopenharmony_ci * interpolates to handle a race with vblank interrupts using the high precision 39862306a36Sopenharmony_ci * timestamping support. 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * This is mostly useful for hardware that can obtain the scanout position, but 40162306a36Sopenharmony_ci * doesn't have a hardware frame counter. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ciu64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 40662306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 40762306a36Sopenharmony_ci u64 vblank; 40862306a36Sopenharmony_ci unsigned long flags; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci drm_WARN_ONCE(dev, drm_debug_enabled(DRM_UT_VBL) && 41162306a36Sopenharmony_ci !crtc->funcs->get_vblank_timestamp, 41262306a36Sopenharmony_ci "This function requires support for accurate vblank timestamps."); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci spin_lock_irqsave(&dev->vblank_time_lock, flags); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci drm_update_vblank_count(dev, pipe, false); 41762306a36Sopenharmony_ci vblank = drm_vblank_count(dev, pipe); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vblank_time_lock, flags); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return vblank; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_accurate_vblank_count); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic void __disable_vblank(struct drm_device *dev, unsigned int pipe) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 42862306a36Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (drm_WARN_ON(dev, !crtc)) 43162306a36Sopenharmony_ci return; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (crtc->funcs->disable_vblank) 43462306a36Sopenharmony_ci crtc->funcs->disable_vblank(crtc); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci#ifdef CONFIG_DRM_LEGACY 43762306a36Sopenharmony_ci else { 43862306a36Sopenharmony_ci dev->driver->disable_vblank(dev, pipe); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci#endif 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* 44462306a36Sopenharmony_ci * Disable vblank irq's on crtc, make sure that last vblank count 44562306a36Sopenharmony_ci * of hardware and corresponding consistent software vblank counter 44662306a36Sopenharmony_ci * are preserved, even if there are any spurious vblank irq's after 44762306a36Sopenharmony_ci * disable. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_civoid drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 45262306a36Sopenharmony_ci unsigned long irqflags; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci assert_spin_locked(&dev->vbl_lock); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Prevent vblank irq processing while disabling vblank irqs, 45762306a36Sopenharmony_ci * so no updates of timestamps or count can happen after we've 45862306a36Sopenharmony_ci * disabled. Needed to prevent races in case of delayed irq's. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci spin_lock_irqsave(&dev->vblank_time_lock, irqflags); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * Update vblank count and disable vblank interrupts only if the 46462306a36Sopenharmony_ci * interrupts were enabled. This avoids calling the ->disable_vblank() 46562306a36Sopenharmony_ci * operation in atomic context with the hardware potentially runtime 46662306a36Sopenharmony_ci * suspended. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci if (!vblank->enabled) 46962306a36Sopenharmony_ci goto out; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* 47262306a36Sopenharmony_ci * Update the count and timestamp to maintain the 47362306a36Sopenharmony_ci * appearance that the counter has been ticking all along until 47462306a36Sopenharmony_ci * this time. This makes the count account for the entire time 47562306a36Sopenharmony_ci * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci drm_update_vblank_count(dev, pipe, false); 47862306a36Sopenharmony_ci __disable_vblank(dev, pipe); 47962306a36Sopenharmony_ci vblank->enabled = false; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ciout: 48262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic void vblank_disable_fn(struct timer_list *t) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = from_timer(vblank, t, disable_timer); 48862306a36Sopenharmony_ci struct drm_device *dev = vblank->dev; 48962306a36Sopenharmony_ci unsigned int pipe = vblank->pipe; 49062306a36Sopenharmony_ci unsigned long irqflags; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci spin_lock_irqsave(&dev->vbl_lock, irqflags); 49362306a36Sopenharmony_ci if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) { 49462306a36Sopenharmony_ci drm_dbg_core(dev, "disabling vblank on crtc %u\n", pipe); 49562306a36Sopenharmony_ci drm_vblank_disable_and_save(dev, pipe); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void drm_vblank_init_release(struct drm_device *dev, void *ptr) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = ptr; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci drm_WARN_ON(dev, READ_ONCE(vblank->enabled) && 50562306a36Sopenharmony_ci drm_core_check_feature(dev, DRIVER_MODESET)); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci drm_vblank_destroy_worker(vblank); 50862306a36Sopenharmony_ci del_timer_sync(&vblank->disable_timer); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/** 51262306a36Sopenharmony_ci * drm_vblank_init - initialize vblank support 51362306a36Sopenharmony_ci * @dev: DRM device 51462306a36Sopenharmony_ci * @num_crtcs: number of CRTCs supported by @dev 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * This function initializes vblank support for @num_crtcs display pipelines. 51762306a36Sopenharmony_ci * Cleanup is handled automatically through a cleanup function added with 51862306a36Sopenharmony_ci * drmm_add_action_or_reset(). 51962306a36Sopenharmony_ci * 52062306a36Sopenharmony_ci * Returns: 52162306a36Sopenharmony_ci * Zero on success or a negative error code on failure. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ciint drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci int ret; 52662306a36Sopenharmony_ci unsigned int i; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci spin_lock_init(&dev->vbl_lock); 52962306a36Sopenharmony_ci spin_lock_init(&dev->vblank_time_lock); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci dev->vblank = drmm_kcalloc(dev, num_crtcs, sizeof(*dev->vblank), GFP_KERNEL); 53262306a36Sopenharmony_ci if (!dev->vblank) 53362306a36Sopenharmony_ci return -ENOMEM; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci dev->num_crtcs = num_crtcs; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci for (i = 0; i < num_crtcs; i++) { 53862306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[i]; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci vblank->dev = dev; 54162306a36Sopenharmony_ci vblank->pipe = i; 54262306a36Sopenharmony_ci init_waitqueue_head(&vblank->queue); 54362306a36Sopenharmony_ci timer_setup(&vblank->disable_timer, vblank_disable_fn, 0); 54462306a36Sopenharmony_ci seqlock_init(&vblank->seqlock); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = drmm_add_action_or_reset(dev, drm_vblank_init_release, 54762306a36Sopenharmony_ci vblank); 54862306a36Sopenharmony_ci if (ret) 54962306a36Sopenharmony_ci return ret; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci ret = drm_vblank_worker_init(vblank); 55262306a36Sopenharmony_ci if (ret) 55362306a36Sopenharmony_ci return ret; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_vblank_init); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/** 56162306a36Sopenharmony_ci * drm_dev_has_vblank - test if vblanking has been initialized for 56262306a36Sopenharmony_ci * a device 56362306a36Sopenharmony_ci * @dev: the device 56462306a36Sopenharmony_ci * 56562306a36Sopenharmony_ci * Drivers may call this function to test if vblank support is 56662306a36Sopenharmony_ci * initialized for a device. For most hardware this means that vblanking 56762306a36Sopenharmony_ci * can also be enabled. 56862306a36Sopenharmony_ci * 56962306a36Sopenharmony_ci * Atomic helpers use this function to initialize 57062306a36Sopenharmony_ci * &drm_crtc_state.no_vblank. See also drm_atomic_helper_check_modeset(). 57162306a36Sopenharmony_ci * 57262306a36Sopenharmony_ci * Returns: 57362306a36Sopenharmony_ci * True if vblanking has been initialized for the given device, false 57462306a36Sopenharmony_ci * otherwise. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_cibool drm_dev_has_vblank(const struct drm_device *dev) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci return dev->num_crtcs != 0; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_dev_has_vblank); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci/** 58362306a36Sopenharmony_ci * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC 58462306a36Sopenharmony_ci * @crtc: which CRTC's vblank waitqueue to retrieve 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * This function returns a pointer to the vblank waitqueue for the CRTC. 58762306a36Sopenharmony_ci * Drivers can use this to implement vblank waits using wait_event() and related 58862306a36Sopenharmony_ci * functions. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ciwait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci return &crtc->dev->vblank[drm_crtc_index(crtc)].queue; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_waitqueue); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/** 59862306a36Sopenharmony_ci * drm_calc_timestamping_constants - calculate vblank timestamp constants 59962306a36Sopenharmony_ci * @crtc: drm_crtc whose timestamp constants should be updated. 60062306a36Sopenharmony_ci * @mode: display mode containing the scanout timings 60162306a36Sopenharmony_ci * 60262306a36Sopenharmony_ci * Calculate and store various constants which are later needed by vblank and 60362306a36Sopenharmony_ci * swap-completion timestamping, e.g, by 60462306a36Sopenharmony_ci * drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from 60562306a36Sopenharmony_ci * CRTC's true scanout timing, so they take things like panel scaling or 60662306a36Sopenharmony_ci * other adjustments into account. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_civoid drm_calc_timestamping_constants(struct drm_crtc *crtc, 60962306a36Sopenharmony_ci const struct drm_display_mode *mode) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 61262306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 61362306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 61462306a36Sopenharmony_ci int linedur_ns = 0, framedur_ns = 0; 61562306a36Sopenharmony_ci int dotclock = mode->crtc_clock; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 61862306a36Sopenharmony_ci return; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 62162306a36Sopenharmony_ci return; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* Valid dotclock? */ 62462306a36Sopenharmony_ci if (dotclock > 0) { 62562306a36Sopenharmony_ci int frame_size = mode->crtc_htotal * mode->crtc_vtotal; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* 62862306a36Sopenharmony_ci * Convert scanline length in pixels and video 62962306a36Sopenharmony_ci * dot clock to line duration and frame duration 63062306a36Sopenharmony_ci * in nanoseconds: 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); 63362306a36Sopenharmony_ci framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * Fields of interlaced scanout modes are only half a frame duration. 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 63962306a36Sopenharmony_ci framedur_ns /= 2; 64062306a36Sopenharmony_ci } else { 64162306a36Sopenharmony_ci drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n", 64262306a36Sopenharmony_ci crtc->base.id); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci vblank->linedur_ns = linedur_ns; 64662306a36Sopenharmony_ci vblank->framedur_ns = framedur_ns; 64762306a36Sopenharmony_ci drm_mode_copy(&vblank->hwmode, mode); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci drm_dbg_core(dev, 65062306a36Sopenharmony_ci "crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", 65162306a36Sopenharmony_ci crtc->base.id, mode->crtc_htotal, 65262306a36Sopenharmony_ci mode->crtc_vtotal, mode->crtc_vdisplay); 65362306a36Sopenharmony_ci drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n", 65462306a36Sopenharmony_ci crtc->base.id, dotclock, framedur_ns, linedur_ns); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_calc_timestamping_constants); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci/** 65962306a36Sopenharmony_ci * drm_crtc_vblank_helper_get_vblank_timestamp_internal - precise vblank 66062306a36Sopenharmony_ci * timestamp helper 66162306a36Sopenharmony_ci * @crtc: CRTC whose vblank timestamp to retrieve 66262306a36Sopenharmony_ci * @max_error: Desired maximum allowable error in timestamps (nanosecs) 66362306a36Sopenharmony_ci * On return contains true maximum error of timestamp 66462306a36Sopenharmony_ci * @vblank_time: Pointer to time which should receive the timestamp 66562306a36Sopenharmony_ci * @in_vblank_irq: 66662306a36Sopenharmony_ci * True when called from drm_crtc_handle_vblank(). Some drivers 66762306a36Sopenharmony_ci * need to apply some workarounds for gpu-specific vblank irq quirks 66862306a36Sopenharmony_ci * if flag is set. 66962306a36Sopenharmony_ci * @get_scanout_position: 67062306a36Sopenharmony_ci * Callback function to retrieve the scanout position. See 67162306a36Sopenharmony_ci * @struct drm_crtc_helper_funcs.get_scanout_position. 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * Implements calculation of exact vblank timestamps from given drm_display_mode 67462306a36Sopenharmony_ci * timings and current video scanout position of a CRTC. 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * The current implementation only handles standard video modes. For double scan 67762306a36Sopenharmony_ci * and interlaced modes the driver is supposed to adjust the hardware mode 67862306a36Sopenharmony_ci * (taken from &drm_crtc_state.adjusted mode for atomic modeset drivers) to 67962306a36Sopenharmony_ci * match the scanout position reported. 68062306a36Sopenharmony_ci * 68162306a36Sopenharmony_ci * Note that atomic drivers must call drm_calc_timestamping_constants() before 68262306a36Sopenharmony_ci * enabling a CRTC. The atomic helpers already take care of that in 68362306a36Sopenharmony_ci * drm_atomic_helper_calc_timestamping_constants(). 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * Returns: 68662306a36Sopenharmony_ci * 68762306a36Sopenharmony_ci * Returns true on success, and false on failure, i.e. when no accurate 68862306a36Sopenharmony_ci * timestamp could be acquired. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_cibool 69162306a36Sopenharmony_cidrm_crtc_vblank_helper_get_vblank_timestamp_internal( 69262306a36Sopenharmony_ci struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, 69362306a36Sopenharmony_ci bool in_vblank_irq, 69462306a36Sopenharmony_ci drm_vblank_get_scanout_position_func get_scanout_position) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 69762306a36Sopenharmony_ci unsigned int pipe = crtc->index; 69862306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 69962306a36Sopenharmony_ci struct timespec64 ts_etime, ts_vblank_time; 70062306a36Sopenharmony_ci ktime_t stime, etime; 70162306a36Sopenharmony_ci bool vbl_status; 70262306a36Sopenharmony_ci const struct drm_display_mode *mode; 70362306a36Sopenharmony_ci int vpos, hpos, i; 70462306a36Sopenharmony_ci int delta_ns, duration_ns; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (pipe >= dev->num_crtcs) { 70762306a36Sopenharmony_ci drm_err(dev, "Invalid crtc %u\n", pipe); 70862306a36Sopenharmony_ci return false; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* Scanout position query not supported? Should not happen. */ 71262306a36Sopenharmony_ci if (!get_scanout_position) { 71362306a36Sopenharmony_ci drm_err(dev, "Called from CRTC w/o get_scanout_position()!?\n"); 71462306a36Sopenharmony_ci return false; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (drm_drv_uses_atomic_modeset(dev)) 71862306a36Sopenharmony_ci mode = &vblank->hwmode; 71962306a36Sopenharmony_ci else 72062306a36Sopenharmony_ci mode = &crtc->hwmode; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* If mode timing undefined, just return as no-op: 72362306a36Sopenharmony_ci * Happens during initial modesetting of a crtc. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci if (mode->crtc_clock == 0) { 72662306a36Sopenharmony_ci drm_dbg_core(dev, "crtc %u: Noop due to uninitialized mode.\n", 72762306a36Sopenharmony_ci pipe); 72862306a36Sopenharmony_ci drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev)); 72962306a36Sopenharmony_ci return false; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Get current scanout position with system timestamp. 73362306a36Sopenharmony_ci * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times 73462306a36Sopenharmony_ci * if single query takes longer than max_error nanoseconds. 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * This guarantees a tight bound on maximum error if 73762306a36Sopenharmony_ci * code gets preempted or delayed for some reason. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { 74062306a36Sopenharmony_ci /* 74162306a36Sopenharmony_ci * Get vertical and horizontal scanout position vpos, hpos, 74262306a36Sopenharmony_ci * and bounding timestamps stime, etime, pre/post query. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci vbl_status = get_scanout_position(crtc, in_vblank_irq, 74562306a36Sopenharmony_ci &vpos, &hpos, 74662306a36Sopenharmony_ci &stime, &etime, 74762306a36Sopenharmony_ci mode); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* Return as no-op if scanout query unsupported or failed. */ 75062306a36Sopenharmony_ci if (!vbl_status) { 75162306a36Sopenharmony_ci drm_dbg_core(dev, 75262306a36Sopenharmony_ci "crtc %u : scanoutpos query failed.\n", 75362306a36Sopenharmony_ci pipe); 75462306a36Sopenharmony_ci return false; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* Compute uncertainty in timestamp of scanout position query. */ 75862306a36Sopenharmony_ci duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* Accept result with < max_error nsecs timing uncertainty. */ 76162306a36Sopenharmony_ci if (duration_ns <= *max_error) 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Noisy system timing? */ 76662306a36Sopenharmony_ci if (i == DRM_TIMESTAMP_MAXRETRIES) { 76762306a36Sopenharmony_ci drm_dbg_core(dev, 76862306a36Sopenharmony_ci "crtc %u: Noisy timestamp %d us > %d us [%d reps].\n", 76962306a36Sopenharmony_ci pipe, duration_ns / 1000, *max_error / 1000, i); 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Return upper bound of timestamp precision error. */ 77362306a36Sopenharmony_ci *max_error = duration_ns; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* Convert scanout position into elapsed time at raw_time query 77662306a36Sopenharmony_ci * since start of scanout at first display scanline. delta_ns 77762306a36Sopenharmony_ci * can be negative if start of scanout hasn't happened yet. 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_ci delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos), 78062306a36Sopenharmony_ci mode->crtc_clock); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* Subtract time delta from raw timestamp to get final 78362306a36Sopenharmony_ci * vblank_time timestamp for end of vblank. 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_ci *vblank_time = ktime_sub_ns(etime, delta_ns); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (!drm_debug_enabled(DRM_UT_VBL)) 78862306a36Sopenharmony_ci return true; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci ts_etime = ktime_to_timespec64(etime); 79162306a36Sopenharmony_ci ts_vblank_time = ktime_to_timespec64(*vblank_time); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci drm_dbg_vbl(dev, 79462306a36Sopenharmony_ci "crtc %u : v p(%d,%d)@ %lld.%06ld -> %lld.%06ld [e %d us, %d rep]\n", 79562306a36Sopenharmony_ci pipe, hpos, vpos, 79662306a36Sopenharmony_ci (u64)ts_etime.tv_sec, ts_etime.tv_nsec / 1000, 79762306a36Sopenharmony_ci (u64)ts_vblank_time.tv_sec, ts_vblank_time.tv_nsec / 1000, 79862306a36Sopenharmony_ci duration_ns / 1000, i); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci return true; 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_internal); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/** 80562306a36Sopenharmony_ci * drm_crtc_vblank_helper_get_vblank_timestamp - precise vblank timestamp 80662306a36Sopenharmony_ci * helper 80762306a36Sopenharmony_ci * @crtc: CRTC whose vblank timestamp to retrieve 80862306a36Sopenharmony_ci * @max_error: Desired maximum allowable error in timestamps (nanosecs) 80962306a36Sopenharmony_ci * On return contains true maximum error of timestamp 81062306a36Sopenharmony_ci * @vblank_time: Pointer to time which should receive the timestamp 81162306a36Sopenharmony_ci * @in_vblank_irq: 81262306a36Sopenharmony_ci * True when called from drm_crtc_handle_vblank(). Some drivers 81362306a36Sopenharmony_ci * need to apply some workarounds for gpu-specific vblank irq quirks 81462306a36Sopenharmony_ci * if flag is set. 81562306a36Sopenharmony_ci * 81662306a36Sopenharmony_ci * Implements calculation of exact vblank timestamps from given drm_display_mode 81762306a36Sopenharmony_ci * timings and current video scanout position of a CRTC. This can be directly 81862306a36Sopenharmony_ci * used as the &drm_crtc_funcs.get_vblank_timestamp implementation of a kms 81962306a36Sopenharmony_ci * driver if &drm_crtc_helper_funcs.get_scanout_position is implemented. 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * The current implementation only handles standard video modes. For double scan 82262306a36Sopenharmony_ci * and interlaced modes the driver is supposed to adjust the hardware mode 82362306a36Sopenharmony_ci * (taken from &drm_crtc_state.adjusted mode for atomic modeset drivers) to 82462306a36Sopenharmony_ci * match the scanout position reported. 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * Note that atomic drivers must call drm_calc_timestamping_constants() before 82762306a36Sopenharmony_ci * enabling a CRTC. The atomic helpers already take care of that in 82862306a36Sopenharmony_ci * drm_atomic_helper_calc_timestamping_constants(). 82962306a36Sopenharmony_ci * 83062306a36Sopenharmony_ci * Returns: 83162306a36Sopenharmony_ci * 83262306a36Sopenharmony_ci * Returns true on success, and false on failure, i.e. when no accurate 83362306a36Sopenharmony_ci * timestamp could be acquired. 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_cibool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc, 83662306a36Sopenharmony_ci int *max_error, 83762306a36Sopenharmony_ci ktime_t *vblank_time, 83862306a36Sopenharmony_ci bool in_vblank_irq) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci return drm_crtc_vblank_helper_get_vblank_timestamp_internal( 84162306a36Sopenharmony_ci crtc, max_error, vblank_time, in_vblank_irq, 84262306a36Sopenharmony_ci crtc->helper_private->get_scanout_position); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/** 84762306a36Sopenharmony_ci * drm_crtc_get_last_vbltimestamp - retrieve raw timestamp for the most 84862306a36Sopenharmony_ci * recent vblank interval 84962306a36Sopenharmony_ci * @crtc: CRTC whose vblank timestamp to retrieve 85062306a36Sopenharmony_ci * @tvblank: Pointer to target time which should receive the timestamp 85162306a36Sopenharmony_ci * @in_vblank_irq: 85262306a36Sopenharmony_ci * True when called from drm_crtc_handle_vblank(). Some drivers 85362306a36Sopenharmony_ci * need to apply some workarounds for gpu-specific vblank irq quirks 85462306a36Sopenharmony_ci * if flag is set. 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * Fetches the system timestamp corresponding to the time of the most recent 85762306a36Sopenharmony_ci * vblank interval on specified CRTC. May call into kms-driver to 85862306a36Sopenharmony_ci * compute the timestamp with a high-precision GPU specific method. 85962306a36Sopenharmony_ci * 86062306a36Sopenharmony_ci * Returns zero if timestamp originates from uncorrected do_gettimeofday() 86162306a36Sopenharmony_ci * call, i.e., it isn't very precisely locked to the true vblank. 86262306a36Sopenharmony_ci * 86362306a36Sopenharmony_ci * Returns: 86462306a36Sopenharmony_ci * True if timestamp is considered to be very precise, false otherwise. 86562306a36Sopenharmony_ci */ 86662306a36Sopenharmony_cistatic bool 86762306a36Sopenharmony_cidrm_crtc_get_last_vbltimestamp(struct drm_crtc *crtc, ktime_t *tvblank, 86862306a36Sopenharmony_ci bool in_vblank_irq) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci bool ret = false; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci /* Define requested maximum error on timestamps (nanoseconds). */ 87362306a36Sopenharmony_ci int max_error = (int) drm_timestamp_precision * 1000; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Query driver if possible and precision timestamping enabled. */ 87662306a36Sopenharmony_ci if (crtc && crtc->funcs->get_vblank_timestamp && max_error > 0) { 87762306a36Sopenharmony_ci ret = crtc->funcs->get_vblank_timestamp(crtc, &max_error, 87862306a36Sopenharmony_ci tvblank, in_vblank_irq); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* GPU high precision timestamp query unsupported or failed. 88262306a36Sopenharmony_ci * Return current monotonic/gettimeofday timestamp as best estimate. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci if (!ret) 88562306a36Sopenharmony_ci *tvblank = ktime_get(); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic bool 89162306a36Sopenharmony_cidrm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, 89262306a36Sopenharmony_ci ktime_t *tvblank, bool in_vblank_irq) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return drm_crtc_get_last_vbltimestamp(crtc, tvblank, in_vblank_irq); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci/** 90062306a36Sopenharmony_ci * drm_crtc_vblank_count - retrieve "cooked" vblank counter value 90162306a36Sopenharmony_ci * @crtc: which counter to retrieve 90262306a36Sopenharmony_ci * 90362306a36Sopenharmony_ci * Fetches the "cooked" vblank count value that represents the number of 90462306a36Sopenharmony_ci * vblank events since the system was booted, including lost events due to 90562306a36Sopenharmony_ci * modesetting activity. Note that this timer isn't correct against a racing 90662306a36Sopenharmony_ci * vblank interrupt (since it only reports the software vblank counter), see 90762306a36Sopenharmony_ci * drm_crtc_accurate_vblank_count() for such use-cases. 90862306a36Sopenharmony_ci * 90962306a36Sopenharmony_ci * Note that for a given vblank counter value drm_crtc_handle_vblank() 91062306a36Sopenharmony_ci * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() 91162306a36Sopenharmony_ci * provide a barrier: Any writes done before calling 91262306a36Sopenharmony_ci * drm_crtc_handle_vblank() will be visible to callers of the later 91362306a36Sopenharmony_ci * functions, if the vblank count is the same or a later one. 91462306a36Sopenharmony_ci * 91562306a36Sopenharmony_ci * See also &drm_vblank_crtc.count. 91662306a36Sopenharmony_ci * 91762306a36Sopenharmony_ci * Returns: 91862306a36Sopenharmony_ci * The software vblank counter. 91962306a36Sopenharmony_ci */ 92062306a36Sopenharmony_ciu64 drm_crtc_vblank_count(struct drm_crtc *crtc) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci return drm_vblank_count(crtc->dev, drm_crtc_index(crtc)); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_count); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci/** 92762306a36Sopenharmony_ci * drm_vblank_count_and_time - retrieve "cooked" vblank counter value and the 92862306a36Sopenharmony_ci * system timestamp corresponding to that vblank counter value. 92962306a36Sopenharmony_ci * @dev: DRM device 93062306a36Sopenharmony_ci * @pipe: index of CRTC whose counter to retrieve 93162306a36Sopenharmony_ci * @vblanktime: Pointer to ktime_t to receive the vblank timestamp. 93262306a36Sopenharmony_ci * 93362306a36Sopenharmony_ci * Fetches the "cooked" vblank count value that represents the number of 93462306a36Sopenharmony_ci * vblank events since the system was booted, including lost events due to 93562306a36Sopenharmony_ci * modesetting activity. Returns corresponding system timestamp of the time 93662306a36Sopenharmony_ci * of the vblank interval that corresponds to the current vblank counter value. 93762306a36Sopenharmony_ci * 93862306a36Sopenharmony_ci * This is the legacy version of drm_crtc_vblank_count_and_time(). 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_cistatic u64 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, 94162306a36Sopenharmony_ci ktime_t *vblanktime) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 94462306a36Sopenharmony_ci u64 vblank_count; 94562306a36Sopenharmony_ci unsigned int seq; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) { 94862306a36Sopenharmony_ci *vblanktime = 0; 94962306a36Sopenharmony_ci return 0; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci do { 95362306a36Sopenharmony_ci seq = read_seqbegin(&vblank->seqlock); 95462306a36Sopenharmony_ci vblank_count = atomic64_read(&vblank->count); 95562306a36Sopenharmony_ci *vblanktime = vblank->time; 95662306a36Sopenharmony_ci } while (read_seqretry(&vblank->seqlock, seq)); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return vblank_count; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci/** 96262306a36Sopenharmony_ci * drm_crtc_vblank_count_and_time - retrieve "cooked" vblank counter value 96362306a36Sopenharmony_ci * and the system timestamp corresponding to that vblank counter value 96462306a36Sopenharmony_ci * @crtc: which counter to retrieve 96562306a36Sopenharmony_ci * @vblanktime: Pointer to time to receive the vblank timestamp. 96662306a36Sopenharmony_ci * 96762306a36Sopenharmony_ci * Fetches the "cooked" vblank count value that represents the number of 96862306a36Sopenharmony_ci * vblank events since the system was booted, including lost events due to 96962306a36Sopenharmony_ci * modesetting activity. Returns corresponding system timestamp of the time 97062306a36Sopenharmony_ci * of the vblank interval that corresponds to the current vblank counter value. 97162306a36Sopenharmony_ci * 97262306a36Sopenharmony_ci * Note that for a given vblank counter value drm_crtc_handle_vblank() 97362306a36Sopenharmony_ci * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() 97462306a36Sopenharmony_ci * provide a barrier: Any writes done before calling 97562306a36Sopenharmony_ci * drm_crtc_handle_vblank() will be visible to callers of the later 97662306a36Sopenharmony_ci * functions, if the vblank count is the same or a later one. 97762306a36Sopenharmony_ci * 97862306a36Sopenharmony_ci * See also &drm_vblank_crtc.count. 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ciu64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, 98162306a36Sopenharmony_ci ktime_t *vblanktime) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci return drm_vblank_count_and_time(crtc->dev, drm_crtc_index(crtc), 98462306a36Sopenharmony_ci vblanktime); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_count_and_time); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci/** 98962306a36Sopenharmony_ci * drm_crtc_next_vblank_start - calculate the time of the next vblank 99062306a36Sopenharmony_ci * @crtc: the crtc for which to calculate next vblank time 99162306a36Sopenharmony_ci * @vblanktime: pointer to time to receive the next vblank timestamp. 99262306a36Sopenharmony_ci * 99362306a36Sopenharmony_ci * Calculate the expected time of the start of the next vblank period, 99462306a36Sopenharmony_ci * based on time of previous vblank and frame duration 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ciint drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 99962306a36Sopenharmony_ci struct drm_vblank_crtc *vblank; 100062306a36Sopenharmony_ci struct drm_display_mode *mode; 100162306a36Sopenharmony_ci u64 vblank_start; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (!drm_dev_has_vblank(crtc->dev)) 100462306a36Sopenharmony_ci return -EINVAL; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci vblank = &crtc->dev->vblank[pipe]; 100762306a36Sopenharmony_ci mode = &vblank->hwmode; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!vblank->framedur_ns || !vblank->linedur_ns) 101062306a36Sopenharmony_ci return -EINVAL; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (!drm_crtc_get_last_vbltimestamp(crtc, vblanktime, false)) 101362306a36Sopenharmony_ci return -EINVAL; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci vblank_start = DIV_ROUND_DOWN_ULL( 101662306a36Sopenharmony_ci (u64)vblank->framedur_ns * mode->crtc_vblank_start, 101762306a36Sopenharmony_ci mode->crtc_vtotal); 101862306a36Sopenharmony_ci *vblanktime = ktime_add(*vblanktime, ns_to_ktime(vblank_start)); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci return 0; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_next_vblank_start); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic void send_vblank_event(struct drm_device *dev, 102562306a36Sopenharmony_ci struct drm_pending_vblank_event *e, 102662306a36Sopenharmony_ci u64 seq, ktime_t now) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct timespec64 tv; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci switch (e->event.base.type) { 103162306a36Sopenharmony_ci case DRM_EVENT_VBLANK: 103262306a36Sopenharmony_ci case DRM_EVENT_FLIP_COMPLETE: 103362306a36Sopenharmony_ci tv = ktime_to_timespec64(now); 103462306a36Sopenharmony_ci e->event.vbl.sequence = seq; 103562306a36Sopenharmony_ci /* 103662306a36Sopenharmony_ci * e->event is a user space structure, with hardcoded unsigned 103762306a36Sopenharmony_ci * 32-bit seconds/microseconds. This is safe as we always use 103862306a36Sopenharmony_ci * monotonic timestamps since linux-4.15 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci e->event.vbl.tv_sec = tv.tv_sec; 104162306a36Sopenharmony_ci e->event.vbl.tv_usec = tv.tv_nsec / 1000; 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case DRM_EVENT_CRTC_SEQUENCE: 104462306a36Sopenharmony_ci if (seq) 104562306a36Sopenharmony_ci e->event.seq.sequence = seq; 104662306a36Sopenharmony_ci e->event.seq.time_ns = ktime_to_ns(now); 104762306a36Sopenharmony_ci break; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci trace_drm_vblank_event_delivered(e->base.file_priv, e->pipe, seq); 105062306a36Sopenharmony_ci /* 105162306a36Sopenharmony_ci * Use the same timestamp for any associated fence signal to avoid 105262306a36Sopenharmony_ci * mismatch in timestamps for vsync & fence events triggered by the 105362306a36Sopenharmony_ci * same HW event. Frameworks like SurfaceFlinger in Android expects the 105462306a36Sopenharmony_ci * retire-fence timestamp to match exactly with HW vsync as it uses it 105562306a36Sopenharmony_ci * for its software vsync modeling. 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_ci drm_send_event_timestamp_locked(dev, &e->base, now); 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci/** 106162306a36Sopenharmony_ci * drm_crtc_arm_vblank_event - arm vblank event after pageflip 106262306a36Sopenharmony_ci * @crtc: the source CRTC of the vblank event 106362306a36Sopenharmony_ci * @e: the event to send 106462306a36Sopenharmony_ci * 106562306a36Sopenharmony_ci * A lot of drivers need to generate vblank events for the very next vblank 106662306a36Sopenharmony_ci * interrupt. For example when the page flip interrupt happens when the page 106762306a36Sopenharmony_ci * flip gets armed, but not when it actually executes within the next vblank 106862306a36Sopenharmony_ci * period. This helper function implements exactly the required vblank arming 106962306a36Sopenharmony_ci * behaviour. 107062306a36Sopenharmony_ci * 107162306a36Sopenharmony_ci * NOTE: Drivers using this to send out the &drm_crtc_state.event as part of an 107262306a36Sopenharmony_ci * atomic commit must ensure that the next vblank happens at exactly the same 107362306a36Sopenharmony_ci * time as the atomic commit is committed to the hardware. This function itself 107462306a36Sopenharmony_ci * does **not** protect against the next vblank interrupt racing with either this 107562306a36Sopenharmony_ci * function call or the atomic commit operation. A possible sequence could be: 107662306a36Sopenharmony_ci * 107762306a36Sopenharmony_ci * 1. Driver commits new hardware state into vblank-synchronized registers. 107862306a36Sopenharmony_ci * 2. A vblank happens, committing the hardware state. Also the corresponding 107962306a36Sopenharmony_ci * vblank interrupt is fired off and fully processed by the interrupt 108062306a36Sopenharmony_ci * handler. 108162306a36Sopenharmony_ci * 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event(). 108262306a36Sopenharmony_ci * 4. The event is only send out for the next vblank, which is wrong. 108362306a36Sopenharmony_ci * 108462306a36Sopenharmony_ci * An equivalent race can happen when the driver calls 108562306a36Sopenharmony_ci * drm_crtc_arm_vblank_event() before writing out the new hardware state. 108662306a36Sopenharmony_ci * 108762306a36Sopenharmony_ci * The only way to make this work safely is to prevent the vblank from firing 108862306a36Sopenharmony_ci * (and the hardware from committing anything else) until the entire atomic 108962306a36Sopenharmony_ci * commit sequence has run to completion. If the hardware does not have such a 109062306a36Sopenharmony_ci * feature (e.g. using a "go" bit), then it is unsafe to use this functions. 109162306a36Sopenharmony_ci * Instead drivers need to manually send out the event from their interrupt 109262306a36Sopenharmony_ci * handler by calling drm_crtc_send_vblank_event() and make sure that there's no 109362306a36Sopenharmony_ci * possible race with the hardware committing the atomic update. 109462306a36Sopenharmony_ci * 109562306a36Sopenharmony_ci * Caller must hold a vblank reference for the event @e acquired by a 109662306a36Sopenharmony_ci * drm_crtc_vblank_get(), which will be dropped when the next vblank arrives. 109762306a36Sopenharmony_ci */ 109862306a36Sopenharmony_civoid drm_crtc_arm_vblank_event(struct drm_crtc *crtc, 109962306a36Sopenharmony_ci struct drm_pending_vblank_event *e) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 110262306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci assert_spin_locked(&dev->event_lock); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci e->pipe = pipe; 110762306a36Sopenharmony_ci e->sequence = drm_crtc_accurate_vblank_count(crtc) + 1; 110862306a36Sopenharmony_ci list_add_tail(&e->base.link, &dev->vblank_event_list); 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_arm_vblank_event); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci/** 111362306a36Sopenharmony_ci * drm_crtc_send_vblank_event - helper to send vblank event after pageflip 111462306a36Sopenharmony_ci * @crtc: the source CRTC of the vblank event 111562306a36Sopenharmony_ci * @e: the event to send 111662306a36Sopenharmony_ci * 111762306a36Sopenharmony_ci * Updates sequence # and timestamp on event for the most recently processed 111862306a36Sopenharmony_ci * vblank, and sends it to userspace. Caller must hold event lock. 111962306a36Sopenharmony_ci * 112062306a36Sopenharmony_ci * See drm_crtc_arm_vblank_event() for a helper which can be used in certain 112162306a36Sopenharmony_ci * situation, especially to send out events for atomic commit operations. 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_civoid drm_crtc_send_vblank_event(struct drm_crtc *crtc, 112462306a36Sopenharmony_ci struct drm_pending_vblank_event *e) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 112762306a36Sopenharmony_ci u64 seq; 112862306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 112962306a36Sopenharmony_ci ktime_t now; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (drm_dev_has_vblank(dev)) { 113262306a36Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 113362306a36Sopenharmony_ci } else { 113462306a36Sopenharmony_ci seq = 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci now = ktime_get(); 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci e->pipe = pipe; 113962306a36Sopenharmony_ci send_vblank_event(dev, e, seq, now); 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_send_vblank_event); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic int __enable_vblank(struct drm_device *dev, unsigned int pipe) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 114662306a36Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (drm_WARN_ON(dev, !crtc)) 114962306a36Sopenharmony_ci return 0; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci if (crtc->funcs->enable_vblank) 115262306a36Sopenharmony_ci return crtc->funcs->enable_vblank(crtc); 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci#ifdef CONFIG_DRM_LEGACY 115562306a36Sopenharmony_ci else if (dev->driver->enable_vblank) { 115662306a36Sopenharmony_ci return dev->driver->enable_vblank(dev, pipe); 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci#endif 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return -EINVAL; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 116662306a36Sopenharmony_ci int ret = 0; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci assert_spin_locked(&dev->vbl_lock); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci spin_lock(&dev->vblank_time_lock); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (!vblank->enabled) { 117362306a36Sopenharmony_ci /* 117462306a36Sopenharmony_ci * Enable vblank irqs under vblank_time_lock protection. 117562306a36Sopenharmony_ci * All vblank count & timestamp updates are held off 117662306a36Sopenharmony_ci * until we are done reinitializing master counter and 117762306a36Sopenharmony_ci * timestamps. Filtercode in drm_handle_vblank() will 117862306a36Sopenharmony_ci * prevent double-accounting of same vblank interval. 117962306a36Sopenharmony_ci */ 118062306a36Sopenharmony_ci ret = __enable_vblank(dev, pipe); 118162306a36Sopenharmony_ci drm_dbg_core(dev, "enabling vblank on crtc %u, ret: %d\n", 118262306a36Sopenharmony_ci pipe, ret); 118362306a36Sopenharmony_ci if (ret) { 118462306a36Sopenharmony_ci atomic_dec(&vblank->refcount); 118562306a36Sopenharmony_ci } else { 118662306a36Sopenharmony_ci drm_update_vblank_count(dev, pipe, 0); 118762306a36Sopenharmony_ci /* drm_update_vblank_count() includes a wmb so we just 118862306a36Sopenharmony_ci * need to ensure that the compiler emits the write 118962306a36Sopenharmony_ci * to mark the vblank as enabled after the call 119062306a36Sopenharmony_ci * to drm_update_vblank_count(). 119162306a36Sopenharmony_ci */ 119262306a36Sopenharmony_ci WRITE_ONCE(vblank->enabled, true); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return ret; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ciint drm_vblank_get(struct drm_device *dev, unsigned int pipe) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 120462306a36Sopenharmony_ci unsigned long irqflags; 120562306a36Sopenharmony_ci int ret = 0; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 120862306a36Sopenharmony_ci return -EINVAL; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 121162306a36Sopenharmony_ci return -EINVAL; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci spin_lock_irqsave(&dev->vbl_lock, irqflags); 121462306a36Sopenharmony_ci /* Going from 0->1 means we have to enable interrupts again */ 121562306a36Sopenharmony_ci if (atomic_add_return(1, &vblank->refcount) == 1) { 121662306a36Sopenharmony_ci ret = drm_vblank_enable(dev, pipe); 121762306a36Sopenharmony_ci } else { 121862306a36Sopenharmony_ci if (!vblank->enabled) { 121962306a36Sopenharmony_ci atomic_dec(&vblank->refcount); 122062306a36Sopenharmony_ci ret = -EINVAL; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci return ret; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci/** 122962306a36Sopenharmony_ci * drm_crtc_vblank_get - get a reference count on vblank events 123062306a36Sopenharmony_ci * @crtc: which CRTC to own 123162306a36Sopenharmony_ci * 123262306a36Sopenharmony_ci * Acquire a reference count on vblank events to avoid having them disabled 123362306a36Sopenharmony_ci * while in use. 123462306a36Sopenharmony_ci * 123562306a36Sopenharmony_ci * Returns: 123662306a36Sopenharmony_ci * Zero on success or a negative error code on failure. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_ciint drm_crtc_vblank_get(struct drm_crtc *crtc) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci return drm_vblank_get(crtc->dev, drm_crtc_index(crtc)); 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_get); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_civoid drm_vblank_put(struct drm_device *dev, unsigned int pipe) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 124962306a36Sopenharmony_ci return; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (drm_WARN_ON(dev, atomic_read(&vblank->refcount) == 0)) 125262306a36Sopenharmony_ci return; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* Last user schedules interrupt disable */ 125562306a36Sopenharmony_ci if (atomic_dec_and_test(&vblank->refcount)) { 125662306a36Sopenharmony_ci if (drm_vblank_offdelay == 0) 125762306a36Sopenharmony_ci return; 125862306a36Sopenharmony_ci else if (drm_vblank_offdelay < 0) 125962306a36Sopenharmony_ci vblank_disable_fn(&vblank->disable_timer); 126062306a36Sopenharmony_ci else if (!dev->vblank_disable_immediate) 126162306a36Sopenharmony_ci mod_timer(&vblank->disable_timer, 126262306a36Sopenharmony_ci jiffies + ((drm_vblank_offdelay * HZ)/1000)); 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci/** 126762306a36Sopenharmony_ci * drm_crtc_vblank_put - give up ownership of vblank events 126862306a36Sopenharmony_ci * @crtc: which counter to give up 126962306a36Sopenharmony_ci * 127062306a36Sopenharmony_ci * Release ownership of a given vblank counter, turning off interrupts 127162306a36Sopenharmony_ci * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_civoid drm_crtc_vblank_put(struct drm_crtc *crtc) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci drm_vblank_put(crtc->dev, drm_crtc_index(crtc)); 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_put); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci/** 128062306a36Sopenharmony_ci * drm_wait_one_vblank - wait for one vblank 128162306a36Sopenharmony_ci * @dev: DRM device 128262306a36Sopenharmony_ci * @pipe: CRTC index 128362306a36Sopenharmony_ci * 128462306a36Sopenharmony_ci * This waits for one vblank to pass on @pipe, using the irq driver interfaces. 128562306a36Sopenharmony_ci * It is a failure to call this when the vblank irq for @pipe is disabled, e.g. 128662306a36Sopenharmony_ci * due to lack of driver support or because the crtc is off. 128762306a36Sopenharmony_ci * 128862306a36Sopenharmony_ci * This is the legacy version of drm_crtc_wait_one_vblank(). 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_civoid drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 129362306a36Sopenharmony_ci int ret; 129462306a36Sopenharmony_ci u64 last; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 129762306a36Sopenharmony_ci return; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci ret = drm_vblank_get(dev, pipe); 130062306a36Sopenharmony_ci if (drm_WARN(dev, ret, "vblank not available on crtc %i, ret=%i\n", 130162306a36Sopenharmony_ci pipe, ret)) 130262306a36Sopenharmony_ci return; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci last = drm_vblank_count(dev, pipe); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci ret = wait_event_timeout(vblank->queue, 130762306a36Sopenharmony_ci last != drm_vblank_count(dev, pipe), 130862306a36Sopenharmony_ci msecs_to_jiffies(100)); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_wait_one_vblank); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci/** 131762306a36Sopenharmony_ci * drm_crtc_wait_one_vblank - wait for one vblank 131862306a36Sopenharmony_ci * @crtc: DRM crtc 131962306a36Sopenharmony_ci * 132062306a36Sopenharmony_ci * This waits for one vblank to pass on @crtc, using the irq driver interfaces. 132162306a36Sopenharmony_ci * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. 132262306a36Sopenharmony_ci * due to lack of driver support or because the crtc is off. 132362306a36Sopenharmony_ci */ 132462306a36Sopenharmony_civoid drm_crtc_wait_one_vblank(struct drm_crtc *crtc) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_wait_one_vblank); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci/** 133162306a36Sopenharmony_ci * drm_crtc_vblank_off - disable vblank events on a CRTC 133262306a36Sopenharmony_ci * @crtc: CRTC in question 133362306a36Sopenharmony_ci * 133462306a36Sopenharmony_ci * Drivers can use this function to shut down the vblank interrupt handling when 133562306a36Sopenharmony_ci * disabling a crtc. This function ensures that the latest vblank frame count is 133662306a36Sopenharmony_ci * stored so that drm_vblank_on can restore it again. 133762306a36Sopenharmony_ci * 133862306a36Sopenharmony_ci * Drivers must use this function when the hardware vblank counter can get 133962306a36Sopenharmony_ci * reset, e.g. when suspending or disabling the @crtc in general. 134062306a36Sopenharmony_ci */ 134162306a36Sopenharmony_civoid drm_crtc_vblank_off(struct drm_crtc *crtc) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 134462306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 134562306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 134662306a36Sopenharmony_ci struct drm_pending_vblank_event *e, *t; 134762306a36Sopenharmony_ci ktime_t now; 134862306a36Sopenharmony_ci u64 seq; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 135162306a36Sopenharmony_ci return; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci /* 135462306a36Sopenharmony_ci * Grab event_lock early to prevent vblank work from being scheduled 135562306a36Sopenharmony_ci * while we're in the middle of shutting down vblank interrupts 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ci spin_lock_irq(&dev->event_lock); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci spin_lock(&dev->vbl_lock); 136062306a36Sopenharmony_ci drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n", 136162306a36Sopenharmony_ci pipe, vblank->enabled, vblank->inmodeset); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* Avoid redundant vblank disables without previous 136462306a36Sopenharmony_ci * drm_crtc_vblank_on(). */ 136562306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset) 136662306a36Sopenharmony_ci drm_vblank_disable_and_save(dev, pipe); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci wake_up(&vblank->queue); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* 137162306a36Sopenharmony_ci * Prevent subsequent drm_vblank_get() from re-enabling 137262306a36Sopenharmony_ci * the vblank interrupt by bumping the refcount. 137362306a36Sopenharmony_ci */ 137462306a36Sopenharmony_ci if (!vblank->inmodeset) { 137562306a36Sopenharmony_ci atomic_inc(&vblank->refcount); 137662306a36Sopenharmony_ci vblank->inmodeset = 1; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci spin_unlock(&dev->vbl_lock); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci /* Send any queued vblank events, lest the natives grow disquiet */ 138162306a36Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 138462306a36Sopenharmony_ci if (e->pipe != pipe) 138562306a36Sopenharmony_ci continue; 138662306a36Sopenharmony_ci drm_dbg_core(dev, "Sending premature vblank event on disable: " 138762306a36Sopenharmony_ci "wanted %llu, current %llu\n", 138862306a36Sopenharmony_ci e->sequence, seq); 138962306a36Sopenharmony_ci list_del(&e->base.link); 139062306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 139162306a36Sopenharmony_ci send_vblank_event(dev, e, seq, now); 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci /* Cancel any leftover pending vblank work */ 139562306a36Sopenharmony_ci drm_vblank_cancel_pending_works(vblank); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* Will be reset by the modeset helpers when re-enabling the crtc by 140062306a36Sopenharmony_ci * calling drm_calc_timestamping_constants(). */ 140162306a36Sopenharmony_ci vblank->hwmode.crtc_clock = 0; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* Wait for any vblank work that's still executing to finish */ 140462306a36Sopenharmony_ci drm_vblank_flush_worker(vblank); 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_off); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci/** 140962306a36Sopenharmony_ci * drm_crtc_vblank_reset - reset vblank state to off on a CRTC 141062306a36Sopenharmony_ci * @crtc: CRTC in question 141162306a36Sopenharmony_ci * 141262306a36Sopenharmony_ci * Drivers can use this function to reset the vblank state to off at load time. 141362306a36Sopenharmony_ci * Drivers should use this together with the drm_crtc_vblank_off() and 141462306a36Sopenharmony_ci * drm_crtc_vblank_on() functions. The difference compared to 141562306a36Sopenharmony_ci * drm_crtc_vblank_off() is that this function doesn't save the vblank counter 141662306a36Sopenharmony_ci * and hence doesn't need to call any driver hooks. 141762306a36Sopenharmony_ci * 141862306a36Sopenharmony_ci * This is useful for recovering driver state e.g. on driver load, or on resume. 141962306a36Sopenharmony_ci */ 142062306a36Sopenharmony_civoid drm_crtc_vblank_reset(struct drm_crtc *crtc) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 142362306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 142462306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci spin_lock_irq(&dev->vbl_lock); 142762306a36Sopenharmony_ci /* 142862306a36Sopenharmony_ci * Prevent subsequent drm_vblank_get() from enabling the vblank 142962306a36Sopenharmony_ci * interrupt by bumping the refcount. 143062306a36Sopenharmony_ci */ 143162306a36Sopenharmony_ci if (!vblank->inmodeset) { 143262306a36Sopenharmony_ci atomic_inc(&vblank->refcount); 143362306a36Sopenharmony_ci vblank->inmodeset = 1; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci spin_unlock_irq(&dev->vbl_lock); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci drm_WARN_ON(dev, !list_empty(&dev->vblank_event_list)); 143862306a36Sopenharmony_ci drm_WARN_ON(dev, !list_empty(&vblank->pending_work)); 143962306a36Sopenharmony_ci} 144062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_reset); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci/** 144362306a36Sopenharmony_ci * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value 144462306a36Sopenharmony_ci * @crtc: CRTC in question 144562306a36Sopenharmony_ci * @max_vblank_count: max hardware vblank counter value 144662306a36Sopenharmony_ci * 144762306a36Sopenharmony_ci * Update the maximum hardware vblank counter value for @crtc 144862306a36Sopenharmony_ci * at runtime. Useful for hardware where the operation of the 144962306a36Sopenharmony_ci * hardware vblank counter depends on the currently active 145062306a36Sopenharmony_ci * display configuration. 145162306a36Sopenharmony_ci * 145262306a36Sopenharmony_ci * For example, if the hardware vblank counter does not work 145362306a36Sopenharmony_ci * when a specific connector is active the maximum can be set 145462306a36Sopenharmony_ci * to zero. And when that specific connector isn't active the 145562306a36Sopenharmony_ci * maximum can again be set to the appropriate non-zero value. 145662306a36Sopenharmony_ci * 145762306a36Sopenharmony_ci * If used, must be called before drm_vblank_on(). 145862306a36Sopenharmony_ci */ 145962306a36Sopenharmony_civoid drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, 146062306a36Sopenharmony_ci u32 max_vblank_count) 146162306a36Sopenharmony_ci{ 146262306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 146362306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 146462306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci drm_WARN_ON(dev, dev->max_vblank_count); 146762306a36Sopenharmony_ci drm_WARN_ON(dev, !READ_ONCE(vblank->inmodeset)); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci vblank->max_vblank_count = max_vblank_count; 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_set_max_vblank_count); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci/** 147462306a36Sopenharmony_ci * drm_crtc_vblank_on - enable vblank events on a CRTC 147562306a36Sopenharmony_ci * @crtc: CRTC in question 147662306a36Sopenharmony_ci * 147762306a36Sopenharmony_ci * This functions restores the vblank interrupt state captured with 147862306a36Sopenharmony_ci * drm_crtc_vblank_off() again and is generally called when enabling @crtc. Note 147962306a36Sopenharmony_ci * that calls to drm_crtc_vblank_on() and drm_crtc_vblank_off() can be 148062306a36Sopenharmony_ci * unbalanced and so can also be unconditionally called in driver load code to 148162306a36Sopenharmony_ci * reflect the current hardware state of the crtc. 148262306a36Sopenharmony_ci */ 148362306a36Sopenharmony_civoid drm_crtc_vblank_on(struct drm_crtc *crtc) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci struct drm_device *dev = crtc->dev; 148662306a36Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 148762306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 149062306a36Sopenharmony_ci return; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci spin_lock_irq(&dev->vbl_lock); 149362306a36Sopenharmony_ci drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n", 149462306a36Sopenharmony_ci pipe, vblank->enabled, vblank->inmodeset); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Drop our private "prevent drm_vblank_get" refcount */ 149762306a36Sopenharmony_ci if (vblank->inmodeset) { 149862306a36Sopenharmony_ci atomic_dec(&vblank->refcount); 149962306a36Sopenharmony_ci vblank->inmodeset = 0; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci drm_reset_vblank_timestamp(dev, pipe); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci /* 150562306a36Sopenharmony_ci * re-enable interrupts if there are users left, or the 150662306a36Sopenharmony_ci * user wishes vblank interrupts to be enabled all the time. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_ci if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0) 150962306a36Sopenharmony_ci drm_WARN_ON(dev, drm_vblank_enable(dev, pipe)); 151062306a36Sopenharmony_ci spin_unlock_irq(&dev->vbl_lock); 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_on); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_cistatic void drm_vblank_restore(struct drm_device *dev, unsigned int pipe) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci ktime_t t_vblank; 151762306a36Sopenharmony_ci struct drm_vblank_crtc *vblank; 151862306a36Sopenharmony_ci int framedur_ns; 151962306a36Sopenharmony_ci u64 diff_ns; 152062306a36Sopenharmony_ci u32 cur_vblank, diff = 1; 152162306a36Sopenharmony_ci int count = DRM_TIMESTAMP_MAXRETRIES; 152262306a36Sopenharmony_ci u32 max_vblank_count = drm_max_vblank_count(dev, pipe); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 152562306a36Sopenharmony_ci return; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci assert_spin_locked(&dev->vbl_lock); 152862306a36Sopenharmony_ci assert_spin_locked(&dev->vblank_time_lock); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci vblank = &dev->vblank[pipe]; 153162306a36Sopenharmony_ci drm_WARN_ONCE(dev, 153262306a36Sopenharmony_ci drm_debug_enabled(DRM_UT_VBL) && !vblank->framedur_ns, 153362306a36Sopenharmony_ci "Cannot compute missed vblanks without frame duration\n"); 153462306a36Sopenharmony_ci framedur_ns = vblank->framedur_ns; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci do { 153762306a36Sopenharmony_ci cur_vblank = __get_vblank_counter(dev, pipe); 153862306a36Sopenharmony_ci drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); 153962306a36Sopenharmony_ci } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); 154262306a36Sopenharmony_ci if (framedur_ns) 154362306a36Sopenharmony_ci diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci drm_dbg_vbl(dev, 154762306a36Sopenharmony_ci "missed %d vblanks in %lld ns, frame duration=%d ns, hw_diff=%d\n", 154862306a36Sopenharmony_ci diff, diff_ns, framedur_ns, cur_vblank - vblank->last); 154962306a36Sopenharmony_ci vblank->last = (cur_vblank - diff) & max_vblank_count; 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci/** 155362306a36Sopenharmony_ci * drm_crtc_vblank_restore - estimate missed vblanks and update vblank count. 155462306a36Sopenharmony_ci * @crtc: CRTC in question 155562306a36Sopenharmony_ci * 155662306a36Sopenharmony_ci * Power manamement features can cause frame counter resets between vblank 155762306a36Sopenharmony_ci * disable and enable. Drivers can use this function in their 155862306a36Sopenharmony_ci * &drm_crtc_funcs.enable_vblank implementation to estimate missed vblanks since 155962306a36Sopenharmony_ci * the last &drm_crtc_funcs.disable_vblank using timestamps and update the 156062306a36Sopenharmony_ci * vblank counter. 156162306a36Sopenharmony_ci * 156262306a36Sopenharmony_ci * Note that drivers must have race-free high-precision timestamping support, 156362306a36Sopenharmony_ci * i.e. &drm_crtc_funcs.get_vblank_timestamp must be hooked up and 156462306a36Sopenharmony_ci * &drm_driver.vblank_disable_immediate must be set to indicate the 156562306a36Sopenharmony_ci * time-stamping functions are race-free against vblank hardware counter 156662306a36Sopenharmony_ci * increments. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_civoid drm_crtc_vblank_restore(struct drm_crtc *crtc) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci WARN_ON_ONCE(!crtc->funcs->get_vblank_timestamp); 157162306a36Sopenharmony_ci WARN_ON_ONCE(!crtc->dev->vblank_disable_immediate); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci drm_vblank_restore(crtc->dev, drm_crtc_index(crtc)); 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_restore); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic void drm_legacy_vblank_pre_modeset(struct drm_device *dev, 157862306a36Sopenharmony_ci unsigned int pipe) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* vblank is not initialized (IRQ not installed ?), or has been freed */ 158362306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 158462306a36Sopenharmony_ci return; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 158762306a36Sopenharmony_ci return; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* 159062306a36Sopenharmony_ci * To avoid all the problems that might happen if interrupts 159162306a36Sopenharmony_ci * were enabled/disabled around or between these calls, we just 159262306a36Sopenharmony_ci * have the kernel take a reference on the CRTC (just once though 159362306a36Sopenharmony_ci * to avoid corrupting the count if multiple, mismatch calls occur), 159462306a36Sopenharmony_ci * so that interrupts remain enabled in the interim. 159562306a36Sopenharmony_ci */ 159662306a36Sopenharmony_ci if (!vblank->inmodeset) { 159762306a36Sopenharmony_ci vblank->inmodeset = 0x1; 159862306a36Sopenharmony_ci if (drm_vblank_get(dev, pipe) == 0) 159962306a36Sopenharmony_ci vblank->inmodeset |= 0x2; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic void drm_legacy_vblank_post_modeset(struct drm_device *dev, 160462306a36Sopenharmony_ci unsigned int pipe) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci /* vblank is not initialized (IRQ not installed ?), or has been freed */ 160962306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 161062306a36Sopenharmony_ci return; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 161362306a36Sopenharmony_ci return; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci if (vblank->inmodeset) { 161662306a36Sopenharmony_ci spin_lock_irq(&dev->vbl_lock); 161762306a36Sopenharmony_ci drm_reset_vblank_timestamp(dev, pipe); 161862306a36Sopenharmony_ci spin_unlock_irq(&dev->vbl_lock); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (vblank->inmodeset & 0x2) 162162306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci vblank->inmodeset = 0; 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ciint drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, 162862306a36Sopenharmony_ci struct drm_file *file_priv) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci struct drm_modeset_ctl *modeset = data; 163162306a36Sopenharmony_ci unsigned int pipe; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* If drm_vblank_init() hasn't been called yet, just no-op */ 163462306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 163562306a36Sopenharmony_ci return 0; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci /* KMS drivers handle this internally */ 163862306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_LEGACY)) 163962306a36Sopenharmony_ci return 0; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci pipe = modeset->crtc; 164262306a36Sopenharmony_ci if (pipe >= dev->num_crtcs) 164362306a36Sopenharmony_ci return -EINVAL; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci switch (modeset->cmd) { 164662306a36Sopenharmony_ci case _DRM_PRE_MODESET: 164762306a36Sopenharmony_ci drm_legacy_vblank_pre_modeset(dev, pipe); 164862306a36Sopenharmony_ci break; 164962306a36Sopenharmony_ci case _DRM_POST_MODESET: 165062306a36Sopenharmony_ci drm_legacy_vblank_post_modeset(dev, pipe); 165162306a36Sopenharmony_ci break; 165262306a36Sopenharmony_ci default: 165362306a36Sopenharmony_ci return -EINVAL; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci return 0; 165762306a36Sopenharmony_ci} 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cistatic int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, 166062306a36Sopenharmony_ci u64 req_seq, 166162306a36Sopenharmony_ci union drm_wait_vblank *vblwait, 166262306a36Sopenharmony_ci struct drm_file *file_priv) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 166562306a36Sopenharmony_ci struct drm_pending_vblank_event *e; 166662306a36Sopenharmony_ci ktime_t now; 166762306a36Sopenharmony_ci u64 seq; 166862306a36Sopenharmony_ci int ret; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci e = kzalloc(sizeof(*e), GFP_KERNEL); 167162306a36Sopenharmony_ci if (e == NULL) { 167262306a36Sopenharmony_ci ret = -ENOMEM; 167362306a36Sopenharmony_ci goto err_put; 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci e->pipe = pipe; 167762306a36Sopenharmony_ci e->event.base.type = DRM_EVENT_VBLANK; 167862306a36Sopenharmony_ci e->event.base.length = sizeof(e->event.vbl); 167962306a36Sopenharmony_ci e->event.vbl.user_data = vblwait->request.signal; 168062306a36Sopenharmony_ci e->event.vbl.crtc_id = 0; 168162306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 168262306a36Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (crtc) 168562306a36Sopenharmony_ci e->event.vbl.crtc_id = crtc->base.id; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci spin_lock_irq(&dev->event_lock); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci /* 169162306a36Sopenharmony_ci * drm_crtc_vblank_off() might have been called after we called 169262306a36Sopenharmony_ci * drm_vblank_get(). drm_crtc_vblank_off() holds event_lock around the 169362306a36Sopenharmony_ci * vblank disable, so no need for further locking. The reference from 169462306a36Sopenharmony_ci * drm_vblank_get() protects against vblank disable from another source. 169562306a36Sopenharmony_ci */ 169662306a36Sopenharmony_ci if (!READ_ONCE(vblank->enabled)) { 169762306a36Sopenharmony_ci ret = -EINVAL; 169862306a36Sopenharmony_ci goto err_unlock; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci ret = drm_event_reserve_init_locked(dev, file_priv, &e->base, 170262306a36Sopenharmony_ci &e->event.base); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (ret) 170562306a36Sopenharmony_ci goto err_unlock; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci drm_dbg_core(dev, "event on vblank count %llu, current %llu, crtc %u\n", 171062306a36Sopenharmony_ci req_seq, seq, pipe); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci trace_drm_vblank_event_queued(file_priv, pipe, req_seq); 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci e->sequence = req_seq; 171562306a36Sopenharmony_ci if (drm_vblank_passed(seq, req_seq)) { 171662306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 171762306a36Sopenharmony_ci send_vblank_event(dev, e, seq, now); 171862306a36Sopenharmony_ci vblwait->reply.sequence = seq; 171962306a36Sopenharmony_ci } else { 172062306a36Sopenharmony_ci /* drm_handle_vblank_events will call drm_vblank_put */ 172162306a36Sopenharmony_ci list_add_tail(&e->base.link, &dev->vblank_event_list); 172262306a36Sopenharmony_ci vblwait->reply.sequence = req_seq; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci return 0; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_cierr_unlock: 173062306a36Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 173162306a36Sopenharmony_ci kfree(e); 173262306a36Sopenharmony_cierr_put: 173362306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 173462306a36Sopenharmony_ci return ret; 173562306a36Sopenharmony_ci} 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci if (vblwait->request.sequence) 174062306a36Sopenharmony_ci return false; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci return _DRM_VBLANK_RELATIVE == 174362306a36Sopenharmony_ci (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK | 174462306a36Sopenharmony_ci _DRM_VBLANK_EVENT | 174562306a36Sopenharmony_ci _DRM_VBLANK_NEXTONMISS)); 174662306a36Sopenharmony_ci} 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci/* 174962306a36Sopenharmony_ci * Widen a 32-bit param to 64-bits. 175062306a36Sopenharmony_ci * 175162306a36Sopenharmony_ci * \param narrow 32-bit value (missing upper 32 bits) 175262306a36Sopenharmony_ci * \param near 64-bit value that should be 'close' to near 175362306a36Sopenharmony_ci * 175462306a36Sopenharmony_ci * This function returns a 64-bit value using the lower 32-bits from 175562306a36Sopenharmony_ci * 'narrow' and constructing the upper 32-bits so that the result is 175662306a36Sopenharmony_ci * as close as possible to 'near'. 175762306a36Sopenharmony_ci */ 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistatic u64 widen_32_to_64(u32 narrow, u64 near) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci return near + (s32) (narrow - near); 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe, 176562306a36Sopenharmony_ci struct drm_wait_vblank_reply *reply) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci ktime_t now; 176862306a36Sopenharmony_ci struct timespec64 ts; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci /* 177162306a36Sopenharmony_ci * drm_wait_vblank_reply is a UAPI structure that uses 'long' 177262306a36Sopenharmony_ci * to store the seconds. This is safe as we always use monotonic 177362306a36Sopenharmony_ci * timestamps since linux-4.15. 177462306a36Sopenharmony_ci */ 177562306a36Sopenharmony_ci reply->sequence = drm_vblank_count_and_time(dev, pipe, &now); 177662306a36Sopenharmony_ci ts = ktime_to_timespec64(now); 177762306a36Sopenharmony_ci reply->tval_sec = (u32)ts.tv_sec; 177862306a36Sopenharmony_ci reply->tval_usec = ts.tv_nsec / 1000; 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic bool drm_wait_vblank_supported(struct drm_device *dev) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_LEGACY) 178462306a36Sopenharmony_ci if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY))) 178562306a36Sopenharmony_ci return dev->irq_enabled; 178662306a36Sopenharmony_ci#endif 178762306a36Sopenharmony_ci return drm_dev_has_vblank(dev); 178862306a36Sopenharmony_ci} 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ciint drm_wait_vblank_ioctl(struct drm_device *dev, void *data, 179162306a36Sopenharmony_ci struct drm_file *file_priv) 179262306a36Sopenharmony_ci{ 179362306a36Sopenharmony_ci struct drm_crtc *crtc; 179462306a36Sopenharmony_ci struct drm_vblank_crtc *vblank; 179562306a36Sopenharmony_ci union drm_wait_vblank *vblwait = data; 179662306a36Sopenharmony_ci int ret; 179762306a36Sopenharmony_ci u64 req_seq, seq; 179862306a36Sopenharmony_ci unsigned int pipe_index; 179962306a36Sopenharmony_ci unsigned int flags, pipe, high_pipe; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (!drm_wait_vblank_supported(dev)) 180262306a36Sopenharmony_ci return -EOPNOTSUPP; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (vblwait->request.type & _DRM_VBLANK_SIGNAL) 180562306a36Sopenharmony_ci return -EINVAL; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (vblwait->request.type & 180862306a36Sopenharmony_ci ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 180962306a36Sopenharmony_ci _DRM_VBLANK_HIGH_CRTC_MASK)) { 181062306a36Sopenharmony_ci drm_dbg_core(dev, 181162306a36Sopenharmony_ci "Unsupported type value 0x%x, supported mask 0x%x\n", 181262306a36Sopenharmony_ci vblwait->request.type, 181362306a36Sopenharmony_ci (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 181462306a36Sopenharmony_ci _DRM_VBLANK_HIGH_CRTC_MASK)); 181562306a36Sopenharmony_ci return -EINVAL; 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 181962306a36Sopenharmony_ci high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); 182062306a36Sopenharmony_ci if (high_pipe) 182162306a36Sopenharmony_ci pipe_index = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT; 182262306a36Sopenharmony_ci else 182362306a36Sopenharmony_ci pipe_index = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci /* Convert lease-relative crtc index into global crtc index */ 182662306a36Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 182762306a36Sopenharmony_ci pipe = 0; 182862306a36Sopenharmony_ci drm_for_each_crtc(crtc, dev) { 182962306a36Sopenharmony_ci if (drm_lease_held(file_priv, crtc->base.id)) { 183062306a36Sopenharmony_ci if (pipe_index == 0) 183162306a36Sopenharmony_ci break; 183262306a36Sopenharmony_ci pipe_index--; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci pipe++; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci } else { 183762306a36Sopenharmony_ci pipe = pipe_index; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (pipe >= dev->num_crtcs) 184162306a36Sopenharmony_ci return -EINVAL; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci vblank = &dev->vblank[pipe]; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci /* If the counter is currently enabled and accurate, short-circuit 184662306a36Sopenharmony_ci * queries to return the cached timestamp of the last vblank. 184762306a36Sopenharmony_ci */ 184862306a36Sopenharmony_ci if (dev->vblank_disable_immediate && 184962306a36Sopenharmony_ci drm_wait_vblank_is_query(vblwait) && 185062306a36Sopenharmony_ci READ_ONCE(vblank->enabled)) { 185162306a36Sopenharmony_ci drm_wait_vblank_reply(dev, pipe, &vblwait->reply); 185262306a36Sopenharmony_ci return 0; 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci ret = drm_vblank_get(dev, pipe); 185662306a36Sopenharmony_ci if (ret) { 185762306a36Sopenharmony_ci drm_dbg_core(dev, 185862306a36Sopenharmony_ci "crtc %d failed to acquire vblank counter, %d\n", 185962306a36Sopenharmony_ci pipe, ret); 186062306a36Sopenharmony_ci return ret; 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci seq = drm_vblank_count(dev, pipe); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 186562306a36Sopenharmony_ci case _DRM_VBLANK_RELATIVE: 186662306a36Sopenharmony_ci req_seq = seq + vblwait->request.sequence; 186762306a36Sopenharmony_ci vblwait->request.sequence = req_seq; 186862306a36Sopenharmony_ci vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 186962306a36Sopenharmony_ci break; 187062306a36Sopenharmony_ci case _DRM_VBLANK_ABSOLUTE: 187162306a36Sopenharmony_ci req_seq = widen_32_to_64(vblwait->request.sequence, seq); 187262306a36Sopenharmony_ci break; 187362306a36Sopenharmony_ci default: 187462306a36Sopenharmony_ci ret = -EINVAL; 187562306a36Sopenharmony_ci goto done; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if ((flags & _DRM_VBLANK_NEXTONMISS) && 187962306a36Sopenharmony_ci drm_vblank_passed(seq, req_seq)) { 188062306a36Sopenharmony_ci req_seq = seq + 1; 188162306a36Sopenharmony_ci vblwait->request.type &= ~_DRM_VBLANK_NEXTONMISS; 188262306a36Sopenharmony_ci vblwait->request.sequence = req_seq; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci if (flags & _DRM_VBLANK_EVENT) { 188662306a36Sopenharmony_ci /* must hold on to the vblank ref until the event fires 188762306a36Sopenharmony_ci * drm_vblank_put will be called asynchronously 188862306a36Sopenharmony_ci */ 188962306a36Sopenharmony_ci return drm_queue_vblank_event(dev, pipe, req_seq, vblwait, file_priv); 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (req_seq != seq) { 189362306a36Sopenharmony_ci int wait; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci drm_dbg_core(dev, "waiting on vblank count %llu, crtc %u\n", 189662306a36Sopenharmony_ci req_seq, pipe); 189762306a36Sopenharmony_ci wait = wait_event_interruptible_timeout(vblank->queue, 189862306a36Sopenharmony_ci drm_vblank_passed(drm_vblank_count(dev, pipe), req_seq) || 189962306a36Sopenharmony_ci !READ_ONCE(vblank->enabled), 190062306a36Sopenharmony_ci msecs_to_jiffies(3000)); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci switch (wait) { 190362306a36Sopenharmony_ci case 0: 190462306a36Sopenharmony_ci /* timeout */ 190562306a36Sopenharmony_ci ret = -EBUSY; 190662306a36Sopenharmony_ci break; 190762306a36Sopenharmony_ci case -ERESTARTSYS: 190862306a36Sopenharmony_ci /* interrupted by signal */ 190962306a36Sopenharmony_ci ret = -EINTR; 191062306a36Sopenharmony_ci break; 191162306a36Sopenharmony_ci default: 191262306a36Sopenharmony_ci ret = 0; 191362306a36Sopenharmony_ci break; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci if (ret != -EINTR) { 191862306a36Sopenharmony_ci drm_wait_vblank_reply(dev, pipe, &vblwait->reply); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci drm_dbg_core(dev, "crtc %d returning %u to client\n", 192162306a36Sopenharmony_ci pipe, vblwait->reply.sequence); 192262306a36Sopenharmony_ci } else { 192362306a36Sopenharmony_ci drm_dbg_core(dev, "crtc %d vblank wait interrupted by signal\n", 192462306a36Sopenharmony_ci pipe); 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_cidone: 192862306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 192962306a36Sopenharmony_ci return ret; 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 193562306a36Sopenharmony_ci bool high_prec = false; 193662306a36Sopenharmony_ci struct drm_pending_vblank_event *e, *t; 193762306a36Sopenharmony_ci ktime_t now; 193862306a36Sopenharmony_ci u64 seq; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci assert_spin_locked(&dev->event_lock); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 194562306a36Sopenharmony_ci if (e->pipe != pipe) 194662306a36Sopenharmony_ci continue; 194762306a36Sopenharmony_ci if (!drm_vblank_passed(seq, e->sequence)) 194862306a36Sopenharmony_ci continue; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci drm_dbg_core(dev, "vblank event on %llu, current %llu\n", 195162306a36Sopenharmony_ci e->sequence, seq); 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci list_del(&e->base.link); 195462306a36Sopenharmony_ci drm_vblank_put(dev, pipe); 195562306a36Sopenharmony_ci send_vblank_event(dev, e, seq, now); 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (crtc && crtc->funcs->get_vblank_timestamp) 195962306a36Sopenharmony_ci high_prec = true; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci trace_drm_vblank_event(pipe, seq, now, high_prec); 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci/** 196562306a36Sopenharmony_ci * drm_handle_vblank - handle a vblank event 196662306a36Sopenharmony_ci * @dev: DRM device 196762306a36Sopenharmony_ci * @pipe: index of CRTC where this event occurred 196862306a36Sopenharmony_ci * 196962306a36Sopenharmony_ci * Drivers should call this routine in their vblank interrupt handlers to 197062306a36Sopenharmony_ci * update the vblank counter and send any signals that may be pending. 197162306a36Sopenharmony_ci * 197262306a36Sopenharmony_ci * This is the legacy version of drm_crtc_handle_vblank(). 197362306a36Sopenharmony_ci */ 197462306a36Sopenharmony_cibool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 197762306a36Sopenharmony_ci unsigned long irqflags; 197862306a36Sopenharmony_ci bool disable_irq; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (drm_WARN_ON_ONCE(dev, !drm_dev_has_vblank(dev))) 198162306a36Sopenharmony_ci return false; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 198462306a36Sopenharmony_ci return false; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci spin_lock_irqsave(&dev->event_lock, irqflags); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci /* Need timestamp lock to prevent concurrent execution with 198962306a36Sopenharmony_ci * vblank enable/disable, as this would cause inconsistent 199062306a36Sopenharmony_ci * or corrupted timestamps and vblank counts. 199162306a36Sopenharmony_ci */ 199262306a36Sopenharmony_ci spin_lock(&dev->vblank_time_lock); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci /* Vblank irq handling disabled. Nothing to do. */ 199562306a36Sopenharmony_ci if (!vblank->enabled) { 199662306a36Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 199762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->event_lock, irqflags); 199862306a36Sopenharmony_ci return false; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci drm_update_vblank_count(dev, pipe, true); 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci wake_up(&vblank->queue); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci /* With instant-off, we defer disabling the interrupt until after 200862306a36Sopenharmony_ci * we finish processing the following vblank after all events have 200962306a36Sopenharmony_ci * been signaled. The disable has to be last (after 201062306a36Sopenharmony_ci * drm_handle_vblank_events) so that the timestamp is always accurate. 201162306a36Sopenharmony_ci */ 201262306a36Sopenharmony_ci disable_irq = (dev->vblank_disable_immediate && 201362306a36Sopenharmony_ci drm_vblank_offdelay > 0 && 201462306a36Sopenharmony_ci !atomic_read(&vblank->refcount)); 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci drm_handle_vblank_events(dev, pipe); 201762306a36Sopenharmony_ci drm_handle_vblank_works(vblank); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->event_lock, irqflags); 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci if (disable_irq) 202262306a36Sopenharmony_ci vblank_disable_fn(&vblank->disable_timer); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci return true; 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_handle_vblank); 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci/** 202962306a36Sopenharmony_ci * drm_crtc_handle_vblank - handle a vblank event 203062306a36Sopenharmony_ci * @crtc: where this event occurred 203162306a36Sopenharmony_ci * 203262306a36Sopenharmony_ci * Drivers should call this routine in their vblank interrupt handlers to 203362306a36Sopenharmony_ci * update the vblank counter and send any signals that may be pending. 203462306a36Sopenharmony_ci * 203562306a36Sopenharmony_ci * This is the native KMS version of drm_handle_vblank(). 203662306a36Sopenharmony_ci * 203762306a36Sopenharmony_ci * Note that for a given vblank counter value drm_crtc_handle_vblank() 203862306a36Sopenharmony_ci * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() 203962306a36Sopenharmony_ci * provide a barrier: Any writes done before calling 204062306a36Sopenharmony_ci * drm_crtc_handle_vblank() will be visible to callers of the later 204162306a36Sopenharmony_ci * functions, if the vblank count is the same or a later one. 204262306a36Sopenharmony_ci * 204362306a36Sopenharmony_ci * See also &drm_vblank_crtc.count. 204462306a36Sopenharmony_ci * 204562306a36Sopenharmony_ci * Returns: 204662306a36Sopenharmony_ci * True if the event was successfully handled, false on failure. 204762306a36Sopenharmony_ci */ 204862306a36Sopenharmony_cibool drm_crtc_handle_vblank(struct drm_crtc *crtc) 204962306a36Sopenharmony_ci{ 205062306a36Sopenharmony_ci return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); 205162306a36Sopenharmony_ci} 205262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_handle_vblank); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci/* 205562306a36Sopenharmony_ci * Get crtc VBLANK count. 205662306a36Sopenharmony_ci * 205762306a36Sopenharmony_ci * \param dev DRM device 205862306a36Sopenharmony_ci * \param data user argument, pointing to a drm_crtc_get_sequence structure. 205962306a36Sopenharmony_ci * \param file_priv drm file private for the user's open file descriptor 206062306a36Sopenharmony_ci */ 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ciint drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, 206362306a36Sopenharmony_ci struct drm_file *file_priv) 206462306a36Sopenharmony_ci{ 206562306a36Sopenharmony_ci struct drm_crtc *crtc; 206662306a36Sopenharmony_ci struct drm_vblank_crtc *vblank; 206762306a36Sopenharmony_ci int pipe; 206862306a36Sopenharmony_ci struct drm_crtc_get_sequence *get_seq = data; 206962306a36Sopenharmony_ci ktime_t now; 207062306a36Sopenharmony_ci bool vblank_enabled; 207162306a36Sopenharmony_ci int ret; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 207462306a36Sopenharmony_ci return -EOPNOTSUPP; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 207762306a36Sopenharmony_ci return -EOPNOTSUPP; 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id); 208062306a36Sopenharmony_ci if (!crtc) 208162306a36Sopenharmony_ci return -ENOENT; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci pipe = drm_crtc_index(crtc); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci vblank = &dev->vblank[pipe]; 208662306a36Sopenharmony_ci vblank_enabled = dev->vblank_disable_immediate && READ_ONCE(vblank->enabled); 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci if (!vblank_enabled) { 208962306a36Sopenharmony_ci ret = drm_crtc_vblank_get(crtc); 209062306a36Sopenharmony_ci if (ret) { 209162306a36Sopenharmony_ci drm_dbg_core(dev, 209262306a36Sopenharmony_ci "crtc %d failed to acquire vblank counter, %d\n", 209362306a36Sopenharmony_ci pipe, ret); 209462306a36Sopenharmony_ci return ret; 209562306a36Sopenharmony_ci } 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci drm_modeset_lock(&crtc->mutex, NULL); 209862306a36Sopenharmony_ci if (crtc->state) 209962306a36Sopenharmony_ci get_seq->active = crtc->state->enable; 210062306a36Sopenharmony_ci else 210162306a36Sopenharmony_ci get_seq->active = crtc->enabled; 210262306a36Sopenharmony_ci drm_modeset_unlock(&crtc->mutex); 210362306a36Sopenharmony_ci get_seq->sequence = drm_vblank_count_and_time(dev, pipe, &now); 210462306a36Sopenharmony_ci get_seq->sequence_ns = ktime_to_ns(now); 210562306a36Sopenharmony_ci if (!vblank_enabled) 210662306a36Sopenharmony_ci drm_crtc_vblank_put(crtc); 210762306a36Sopenharmony_ci return 0; 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci/* 211162306a36Sopenharmony_ci * Queue a event for VBLANK sequence 211262306a36Sopenharmony_ci * 211362306a36Sopenharmony_ci * \param dev DRM device 211462306a36Sopenharmony_ci * \param data user argument, pointing to a drm_crtc_queue_sequence structure. 211562306a36Sopenharmony_ci * \param file_priv drm file private for the user's open file descriptor 211662306a36Sopenharmony_ci */ 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ciint drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, 211962306a36Sopenharmony_ci struct drm_file *file_priv) 212062306a36Sopenharmony_ci{ 212162306a36Sopenharmony_ci struct drm_crtc *crtc; 212262306a36Sopenharmony_ci struct drm_vblank_crtc *vblank; 212362306a36Sopenharmony_ci int pipe; 212462306a36Sopenharmony_ci struct drm_crtc_queue_sequence *queue_seq = data; 212562306a36Sopenharmony_ci ktime_t now; 212662306a36Sopenharmony_ci struct drm_pending_vblank_event *e; 212762306a36Sopenharmony_ci u32 flags; 212862306a36Sopenharmony_ci u64 seq; 212962306a36Sopenharmony_ci u64 req_seq; 213062306a36Sopenharmony_ci int ret; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 213362306a36Sopenharmony_ci return -EOPNOTSUPP; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 213662306a36Sopenharmony_ci return -EOPNOTSUPP; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id); 213962306a36Sopenharmony_ci if (!crtc) 214062306a36Sopenharmony_ci return -ENOENT; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci flags = queue_seq->flags; 214362306a36Sopenharmony_ci /* Check valid flag bits */ 214462306a36Sopenharmony_ci if (flags & ~(DRM_CRTC_SEQUENCE_RELATIVE| 214562306a36Sopenharmony_ci DRM_CRTC_SEQUENCE_NEXT_ON_MISS)) 214662306a36Sopenharmony_ci return -EINVAL; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci pipe = drm_crtc_index(crtc); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci vblank = &dev->vblank[pipe]; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci e = kzalloc(sizeof(*e), GFP_KERNEL); 215362306a36Sopenharmony_ci if (e == NULL) 215462306a36Sopenharmony_ci return -ENOMEM; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci ret = drm_crtc_vblank_get(crtc); 215762306a36Sopenharmony_ci if (ret) { 215862306a36Sopenharmony_ci drm_dbg_core(dev, 215962306a36Sopenharmony_ci "crtc %d failed to acquire vblank counter, %d\n", 216062306a36Sopenharmony_ci pipe, ret); 216162306a36Sopenharmony_ci goto err_free; 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 216562306a36Sopenharmony_ci req_seq = queue_seq->sequence; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci if (flags & DRM_CRTC_SEQUENCE_RELATIVE) 216862306a36Sopenharmony_ci req_seq += seq; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci if ((flags & DRM_CRTC_SEQUENCE_NEXT_ON_MISS) && drm_vblank_passed(seq, req_seq)) 217162306a36Sopenharmony_ci req_seq = seq + 1; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci e->pipe = pipe; 217462306a36Sopenharmony_ci e->event.base.type = DRM_EVENT_CRTC_SEQUENCE; 217562306a36Sopenharmony_ci e->event.base.length = sizeof(e->event.seq); 217662306a36Sopenharmony_ci e->event.seq.user_data = queue_seq->user_data; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci spin_lock_irq(&dev->event_lock); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci /* 218162306a36Sopenharmony_ci * drm_crtc_vblank_off() might have been called after we called 218262306a36Sopenharmony_ci * drm_crtc_vblank_get(). drm_crtc_vblank_off() holds event_lock around the 218362306a36Sopenharmony_ci * vblank disable, so no need for further locking. The reference from 218462306a36Sopenharmony_ci * drm_crtc_vblank_get() protects against vblank disable from another source. 218562306a36Sopenharmony_ci */ 218662306a36Sopenharmony_ci if (!READ_ONCE(vblank->enabled)) { 218762306a36Sopenharmony_ci ret = -EINVAL; 218862306a36Sopenharmony_ci goto err_unlock; 218962306a36Sopenharmony_ci } 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci ret = drm_event_reserve_init_locked(dev, file_priv, &e->base, 219262306a36Sopenharmony_ci &e->event.base); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci if (ret) 219562306a36Sopenharmony_ci goto err_unlock; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci e->sequence = req_seq; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci if (drm_vblank_passed(seq, req_seq)) { 220062306a36Sopenharmony_ci drm_crtc_vblank_put(crtc); 220162306a36Sopenharmony_ci send_vblank_event(dev, e, seq, now); 220262306a36Sopenharmony_ci queue_seq->sequence = seq; 220362306a36Sopenharmony_ci } else { 220462306a36Sopenharmony_ci /* drm_handle_vblank_events will call drm_vblank_put */ 220562306a36Sopenharmony_ci list_add_tail(&e->base.link, &dev->vblank_event_list); 220662306a36Sopenharmony_ci queue_seq->sequence = req_seq; 220762306a36Sopenharmony_ci } 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 221062306a36Sopenharmony_ci return 0; 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_cierr_unlock: 221362306a36Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 221462306a36Sopenharmony_ci drm_crtc_vblank_put(crtc); 221562306a36Sopenharmony_cierr_free: 221662306a36Sopenharmony_ci kfree(e); 221762306a36Sopenharmony_ci return ret; 221862306a36Sopenharmony_ci} 221962306a36Sopenharmony_ci 2220