18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * drm_irq.c IRQ and vblank support 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * \author Rickard E. (Rik) Faith <faith@valinux.com> 58c2ecf20Sopenharmony_ci * \author Gareth Hughes <gareth@valinux.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 88c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 98c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 108c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 118c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 128c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 158c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 168c2ecf20Sopenharmony_ci * Software. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 218c2ecf20Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 228c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 238c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 248c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/export.h> 288c2ecf20Sopenharmony_ci#include <linux/kthread.h> 298c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 328c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 338c2ecf20Sopenharmony_ci#include <drm/drm_framebuffer.h> 348c2ecf20Sopenharmony_ci#include <drm/drm_managed.h> 358c2ecf20Sopenharmony_ci#include <drm/drm_modeset_helper_vtables.h> 368c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 378c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "drm_internal.h" 408c2ecf20Sopenharmony_ci#include "drm_trace.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * DOC: vblank handling 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * From the computer's perspective, every time the monitor displays 468c2ecf20Sopenharmony_ci * a new frame the scanout engine has "scanned out" the display image 478c2ecf20Sopenharmony_ci * from top to bottom, one row of pixels at a time. The current row 488c2ecf20Sopenharmony_ci * of pixels is referred to as the current scanline. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * In addition to the display's visible area, there's usually a couple of 518c2ecf20Sopenharmony_ci * extra scanlines which aren't actually displayed on the screen. 528c2ecf20Sopenharmony_ci * These extra scanlines don't contain image data and are occasionally used 538c2ecf20Sopenharmony_ci * for features like audio and infoframes. The region made up of these 548c2ecf20Sopenharmony_ci * scanlines is referred to as the vertical blanking region, or vblank for 558c2ecf20Sopenharmony_ci * short. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * For historical reference, the vertical blanking period was designed to 588c2ecf20Sopenharmony_ci * give the electron gun (on CRTs) enough time to move back to the top of 598c2ecf20Sopenharmony_ci * the screen to start scanning out the next frame. Similar for horizontal 608c2ecf20Sopenharmony_ci * blanking periods. They were designed to give the electron gun enough 618c2ecf20Sopenharmony_ci * time to move back to the other side of the screen to start scanning the 628c2ecf20Sopenharmony_ci * next scanline. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * :: 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * physical → ⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽ 688c2ecf20Sopenharmony_ci * top of | | 698c2ecf20Sopenharmony_ci * display | | 708c2ecf20Sopenharmony_ci * | New frame | 718c2ecf20Sopenharmony_ci * | | 728c2ecf20Sopenharmony_ci * |↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓| 738c2ecf20Sopenharmony_ci * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| ← Scanline, 748c2ecf20Sopenharmony_ci * |↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓| updates the 758c2ecf20Sopenharmony_ci * | | frame as it 768c2ecf20Sopenharmony_ci * | | travels down 778c2ecf20Sopenharmony_ci * | | ("sacn out") 788c2ecf20Sopenharmony_ci * | Old frame | 798c2ecf20Sopenharmony_ci * | | 808c2ecf20Sopenharmony_ci * | | 818c2ecf20Sopenharmony_ci * | | 828c2ecf20Sopenharmony_ci * | | physical 838c2ecf20Sopenharmony_ci * | | bottom of 848c2ecf20Sopenharmony_ci * vertical |⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽| ← display 858c2ecf20Sopenharmony_ci * blanking ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆ 868c2ecf20Sopenharmony_ci * region → ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆ 878c2ecf20Sopenharmony_ci * ┆xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx┆ 888c2ecf20Sopenharmony_ci * start of → ⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽ 898c2ecf20Sopenharmony_ci * new frame 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * "Physical top of display" is the reference point for the high-precision/ 928c2ecf20Sopenharmony_ci * corrected timestamp. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * On a lot of display hardware, programming needs to take effect during the 958c2ecf20Sopenharmony_ci * vertical blanking period so that settings like gamma, the image buffer 968c2ecf20Sopenharmony_ci * buffer to be scanned out, etc. can safely be changed without showing 978c2ecf20Sopenharmony_ci * any visual artifacts on the screen. In some unforgiving hardware, some of 988c2ecf20Sopenharmony_ci * this programming has to both start and end in the same vblank. To help 998c2ecf20Sopenharmony_ci * with the timing of the hardware programming, an interrupt is usually 1008c2ecf20Sopenharmony_ci * available to notify the driver when it can start the updating of registers. 1018c2ecf20Sopenharmony_ci * The interrupt is in this context named the vblank interrupt. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * The vblank interrupt may be fired at different points depending on the 1048c2ecf20Sopenharmony_ci * hardware. Some hardware implementations will fire the interrupt when the 1058c2ecf20Sopenharmony_ci * new frame start, other implementations will fire the interrupt at different 1068c2ecf20Sopenharmony_ci * points in time. 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci * Vertical blanking plays a major role in graphics rendering. To achieve 1098c2ecf20Sopenharmony_ci * tear-free display, users must synchronize page flips and/or rendering to 1108c2ecf20Sopenharmony_ci * vertical blanking. The DRM API offers ioctls to perform page flips 1118c2ecf20Sopenharmony_ci * synchronized to vertical blanking and wait for vertical blanking. 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * The DRM core handles most of the vertical blanking management logic, which 1148c2ecf20Sopenharmony_ci * involves filtering out spurious interrupts, keeping race-free blanking 1158c2ecf20Sopenharmony_ci * counters, coping with counter wrap-around and resets and keeping use counts. 1168c2ecf20Sopenharmony_ci * It relies on the driver to generate vertical blanking interrupts and 1178c2ecf20Sopenharmony_ci * optionally provide a hardware vertical blanking counter. 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Drivers must initialize the vertical blanking handling core with a call to 1208c2ecf20Sopenharmony_ci * drm_vblank_init(). Minimally, a driver needs to implement 1218c2ecf20Sopenharmony_ci * &drm_crtc_funcs.enable_vblank and &drm_crtc_funcs.disable_vblank plus call 1228c2ecf20Sopenharmony_ci * drm_crtc_handle_vblank() in its vblank interrupt handler for working vblank 1238c2ecf20Sopenharmony_ci * support. 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * Vertical blanking interrupts can be enabled by the DRM core or by drivers 1268c2ecf20Sopenharmony_ci * themselves (for instance to handle page flipping operations). The DRM core 1278c2ecf20Sopenharmony_ci * maintains a vertical blanking use count to ensure that the interrupts are not 1288c2ecf20Sopenharmony_ci * disabled while a user still needs them. To increment the use count, drivers 1298c2ecf20Sopenharmony_ci * call drm_crtc_vblank_get() and release the vblank reference again with 1308c2ecf20Sopenharmony_ci * drm_crtc_vblank_put(). In between these two calls vblank interrupts are 1318c2ecf20Sopenharmony_ci * guaranteed to be enabled. 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * On many hardware disabling the vblank interrupt cannot be done in a race-free 1348c2ecf20Sopenharmony_ci * manner, see &drm_driver.vblank_disable_immediate and 1358c2ecf20Sopenharmony_ci * &drm_driver.max_vblank_count. In that case the vblank core only disables the 1368c2ecf20Sopenharmony_ci * vblanks after a timer has expired, which can be configured through the 1378c2ecf20Sopenharmony_ci * ``vblankoffdelay`` module parameter. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * Drivers for hardware without support for vertical-blanking interrupts 1408c2ecf20Sopenharmony_ci * must not call drm_vblank_init(). For such drivers, atomic helpers will 1418c2ecf20Sopenharmony_ci * automatically generate fake vblank events as part of the display update. 1428c2ecf20Sopenharmony_ci * This functionality also can be controlled by the driver by enabling and 1438c2ecf20Sopenharmony_ci * disabling struct drm_crtc_state.no_vblank. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* Retry timestamp calculation up to 3 times to satisfy 1478c2ecf20Sopenharmony_ci * drm_timestamp_precision before giving up. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci#define DRM_TIMESTAMP_MAXRETRIES 3 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* Threshold in nanoseconds for detection of redundant 1528c2ecf20Sopenharmony_ci * vblank irq in drm_handle_vblank(). 1 msec should be ok. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic bool 1578c2ecf20Sopenharmony_cidrm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, 1588c2ecf20Sopenharmony_ci ktime_t *tvblank, bool in_vblank_irq); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cimodule_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); 1658c2ecf20Sopenharmony_cimodule_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); 1668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); 1678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void store_vblank(struct drm_device *dev, unsigned int pipe, 1708c2ecf20Sopenharmony_ci u32 vblank_count_inc, 1718c2ecf20Sopenharmony_ci ktime_t t_vblank, u32 last) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci assert_spin_locked(&dev->vblank_time_lock); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci vblank->last = last; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci write_seqlock(&vblank->seqlock); 1808c2ecf20Sopenharmony_ci vblank->time = t_vblank; 1818c2ecf20Sopenharmony_ci atomic64_add(vblank_count_inc, &vblank->count); 1828c2ecf20Sopenharmony_ci write_sequnlock(&vblank->seqlock); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return vblank->max_vblank_count ?: dev->max_vblank_count; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * "No hw counter" fallback implementation of .get_vblank_counter() hook, 1948c2ecf20Sopenharmony_ci * if there is no useable hardware frame counter available. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_cistatic u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci drm_WARN_ON_ONCE(dev, drm_max_vblank_count(dev, pipe) != 0); 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 2058c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, !crtc)) 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (crtc->funcs->get_vblank_counter) 2118c2ecf20Sopenharmony_ci return crtc->funcs->get_vblank_counter(crtc); 2128c2ecf20Sopenharmony_ci } else if (dev->driver->get_vblank_counter) { 2138c2ecf20Sopenharmony_ci return dev->driver->get_vblank_counter(dev, pipe); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return drm_vblank_no_hw_counter(dev, pipe); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * Reset the stored timestamp for the current vblank count to correspond 2218c2ecf20Sopenharmony_ci * to the last vblank occurred. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * Only to be called from drm_crtc_vblank_on(). 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * Note: caller must hold &drm_device.vbl_lock since this reads & writes 2268c2ecf20Sopenharmony_ci * device vblank fields. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci u32 cur_vblank; 2318c2ecf20Sopenharmony_ci bool rc; 2328c2ecf20Sopenharmony_ci ktime_t t_vblank; 2338c2ecf20Sopenharmony_ci int count = DRM_TIMESTAMP_MAXRETRIES; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci spin_lock(&dev->vblank_time_lock); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * sample the current counter to avoid random jumps 2398c2ecf20Sopenharmony_ci * when drm_vblank_enable() applies the diff 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci do { 2428c2ecf20Sopenharmony_ci cur_vblank = __get_vblank_counter(dev, pipe); 2438c2ecf20Sopenharmony_ci rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); 2448c2ecf20Sopenharmony_ci } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Only reinitialize corresponding vblank timestamp if high-precision query 2488c2ecf20Sopenharmony_ci * available and didn't fail. Otherwise reinitialize delayed at next vblank 2498c2ecf20Sopenharmony_ci * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci if (!rc) 2528c2ecf20Sopenharmony_ci t_vblank = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* 2558c2ecf20Sopenharmony_ci * +1 to make sure user will never see the same 2568c2ecf20Sopenharmony_ci * vblank counter value before and after a modeset 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci store_vblank(dev, pipe, 1, t_vblank, cur_vblank); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* 2648c2ecf20Sopenharmony_ci * Call back into the driver to update the appropriate vblank counter 2658c2ecf20Sopenharmony_ci * (specified by @pipe). Deal with wraparound, if it occurred, and 2668c2ecf20Sopenharmony_ci * update the last read value so we can deal with wraparound on the next 2678c2ecf20Sopenharmony_ci * call if necessary. 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Only necessary when going from off->on, to account for frames we 2708c2ecf20Sopenharmony_ci * didn't get an interrupt for. 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * Note: caller must hold &drm_device.vbl_lock since this reads & writes 2738c2ecf20Sopenharmony_ci * device vblank fields. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_cistatic void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, 2768c2ecf20Sopenharmony_ci bool in_vblank_irq) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 2798c2ecf20Sopenharmony_ci u32 cur_vblank, diff; 2808c2ecf20Sopenharmony_ci bool rc; 2818c2ecf20Sopenharmony_ci ktime_t t_vblank; 2828c2ecf20Sopenharmony_ci int count = DRM_TIMESTAMP_MAXRETRIES; 2838c2ecf20Sopenharmony_ci int framedur_ns = vblank->framedur_ns; 2848c2ecf20Sopenharmony_ci u32 max_vblank_count = drm_max_vblank_count(dev, pipe); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Interrupts were disabled prior to this call, so deal with counter 2888c2ecf20Sopenharmony_ci * wrap if needed. 2898c2ecf20Sopenharmony_ci * NOTE! It's possible we lost a full dev->max_vblank_count + 1 events 2908c2ecf20Sopenharmony_ci * here if the register is small or we had vblank interrupts off for 2918c2ecf20Sopenharmony_ci * a long time. 2928c2ecf20Sopenharmony_ci * 2938c2ecf20Sopenharmony_ci * We repeat the hardware vblank counter & timestamp query until 2948c2ecf20Sopenharmony_ci * we get consistent results. This to prevent races between gpu 2958c2ecf20Sopenharmony_ci * updating its hardware counter while we are retrieving the 2968c2ecf20Sopenharmony_ci * corresponding vblank timestamp. 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ci do { 2998c2ecf20Sopenharmony_ci cur_vblank = __get_vblank_counter(dev, pipe); 3008c2ecf20Sopenharmony_ci rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq); 3018c2ecf20Sopenharmony_ci } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (max_vblank_count) { 3048c2ecf20Sopenharmony_ci /* trust the hw counter when it's around */ 3058c2ecf20Sopenharmony_ci diff = (cur_vblank - vblank->last) & max_vblank_count; 3068c2ecf20Sopenharmony_ci } else if (rc && framedur_ns) { 3078c2ecf20Sopenharmony_ci u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * Figure out how many vblanks we've missed based 3118c2ecf20Sopenharmony_ci * on the difference in the timestamps and the 3128c2ecf20Sopenharmony_ci * frame/field duration. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, "crtc %u: Calculating number of vblanks." 3168c2ecf20Sopenharmony_ci " diff_ns = %lld, framedur_ns = %d)\n", 3178c2ecf20Sopenharmony_ci pipe, (long long)diff_ns, framedur_ns); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (diff == 0 && in_vblank_irq) 3228c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, "crtc %u: Redundant vblirq ignored\n", 3238c2ecf20Sopenharmony_ci pipe); 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci /* some kind of default for drivers w/o accurate vbl timestamping */ 3268c2ecf20Sopenharmony_ci diff = in_vblank_irq ? 1 : 0; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset 3318c2ecf20Sopenharmony_ci * interval? If so then vblank irqs keep running and it will likely 3328c2ecf20Sopenharmony_ci * happen that the hardware vblank counter is not trustworthy as it 3338c2ecf20Sopenharmony_ci * might reset at some point in that interval and vblank timestamps 3348c2ecf20Sopenharmony_ci * are not trustworthy either in that interval. Iow. this can result 3358c2ecf20Sopenharmony_ci * in a bogus diff >> 1 which must be avoided as it would cause 3368c2ecf20Sopenharmony_ci * random large forward jumps of the software vblank counter. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (diff > 1 && (vblank->inmodeset & 0x2)) { 3398c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, 3408c2ecf20Sopenharmony_ci "clamping vblank bump to 1 on crtc %u: diffr=%u" 3418c2ecf20Sopenharmony_ci " due to pre-modeset.\n", pipe, diff); 3428c2ecf20Sopenharmony_ci diff = 1; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, "updating vblank count on crtc %u:" 3468c2ecf20Sopenharmony_ci " current=%llu, diff=%u, hw=%u hw_last=%u\n", 3478c2ecf20Sopenharmony_ci pipe, (unsigned long long)atomic64_read(&vblank->count), 3488c2ecf20Sopenharmony_ci diff, cur_vblank, vblank->last); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (diff == 0) { 3518c2ecf20Sopenharmony_ci drm_WARN_ON_ONCE(dev, cur_vblank != vblank->last); 3528c2ecf20Sopenharmony_ci return; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * Only reinitialize corresponding vblank timestamp if high-precision query 3578c2ecf20Sopenharmony_ci * available and didn't fail, or we were called from the vblank interrupt. 3588c2ecf20Sopenharmony_ci * Otherwise reinitialize delayed at next vblank interrupt and assign 0 3598c2ecf20Sopenharmony_ci * for now, to mark the vblanktimestamp as invalid. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (!rc && !in_vblank_irq) 3628c2ecf20Sopenharmony_ci t_vblank = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci store_vblank(dev, pipe, diff, t_vblank, cur_vblank); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciu64 drm_vblank_count(struct drm_device *dev, unsigned int pipe) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 3708c2ecf20Sopenharmony_ci u64 count; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci count = atomic64_read(&vblank->count); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * This read barrier corresponds to the implicit write barrier of the 3798c2ecf20Sopenharmony_ci * write seqlock in store_vblank(). Note that this is the only place 3808c2ecf20Sopenharmony_ci * where we need an explicit barrier, since all other access goes 3818c2ecf20Sopenharmony_ci * through drm_vblank_count_and_time(), which already has the required 3828c2ecf20Sopenharmony_ci * read barrier curtesy of the read seqlock. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci smp_rmb(); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return count; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/** 3908c2ecf20Sopenharmony_ci * drm_crtc_accurate_vblank_count - retrieve the master vblank counter 3918c2ecf20Sopenharmony_ci * @crtc: which counter to retrieve 3928c2ecf20Sopenharmony_ci * 3938c2ecf20Sopenharmony_ci * This function is similar to drm_crtc_vblank_count() but this function 3948c2ecf20Sopenharmony_ci * interpolates to handle a race with vblank interrupts using the high precision 3958c2ecf20Sopenharmony_ci * timestamping support. 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * This is mostly useful for hardware that can obtain the scanout position, but 3988c2ecf20Sopenharmony_ci * doesn't have a hardware frame counter. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ciu64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 4038c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 4048c2ecf20Sopenharmony_ci u64 vblank; 4058c2ecf20Sopenharmony_ci unsigned long flags; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci drm_WARN_ONCE(dev, drm_debug_enabled(DRM_UT_VBL) && 4088c2ecf20Sopenharmony_ci !crtc->funcs->get_vblank_timestamp, 4098c2ecf20Sopenharmony_ci "This function requires support for accurate vblank timestamps."); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->vblank_time_lock, flags); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci drm_update_vblank_count(dev, pipe, false); 4148c2ecf20Sopenharmony_ci vblank = drm_vblank_count(dev, pipe); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->vblank_time_lock, flags); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return vblank; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_accurate_vblank_count); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void __disable_vblank(struct drm_device *dev, unsigned int pipe) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 4258c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, !crtc)) 4288c2ecf20Sopenharmony_ci return; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (crtc->funcs->disable_vblank) 4318c2ecf20Sopenharmony_ci crtc->funcs->disable_vblank(crtc); 4328c2ecf20Sopenharmony_ci } else { 4338c2ecf20Sopenharmony_ci dev->driver->disable_vblank(dev, pipe); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci/* 4388c2ecf20Sopenharmony_ci * Disable vblank irq's on crtc, make sure that last vblank count 4398c2ecf20Sopenharmony_ci * of hardware and corresponding consistent software vblank counter 4408c2ecf20Sopenharmony_ci * are preserved, even if there are any spurious vblank irq's after 4418c2ecf20Sopenharmony_ci * disable. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_civoid drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 4468c2ecf20Sopenharmony_ci unsigned long irqflags; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci assert_spin_locked(&dev->vbl_lock); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* Prevent vblank irq processing while disabling vblank irqs, 4518c2ecf20Sopenharmony_ci * so no updates of timestamps or count can happen after we've 4528c2ecf20Sopenharmony_ci * disabled. Needed to prevent races in case of delayed irq's. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->vblank_time_lock, irqflags); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* 4578c2ecf20Sopenharmony_ci * Update vblank count and disable vblank interrupts only if the 4588c2ecf20Sopenharmony_ci * interrupts were enabled. This avoids calling the ->disable_vblank() 4598c2ecf20Sopenharmony_ci * operation in atomic context with the hardware potentially runtime 4608c2ecf20Sopenharmony_ci * suspended. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci if (!vblank->enabled) 4638c2ecf20Sopenharmony_ci goto out; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * Update the count and timestamp to maintain the 4678c2ecf20Sopenharmony_ci * appearance that the counter has been ticking all along until 4688c2ecf20Sopenharmony_ci * this time. This makes the count account for the entire time 4698c2ecf20Sopenharmony_ci * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci drm_update_vblank_count(dev, pipe, false); 4728c2ecf20Sopenharmony_ci __disable_vblank(dev, pipe); 4738c2ecf20Sopenharmony_ci vblank->enabled = false; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ciout: 4768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void vblank_disable_fn(struct timer_list *t) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = from_timer(vblank, t, disable_timer); 4828c2ecf20Sopenharmony_ci struct drm_device *dev = vblank->dev; 4838c2ecf20Sopenharmony_ci unsigned int pipe = vblank->pipe; 4848c2ecf20Sopenharmony_ci unsigned long irqflags; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->vbl_lock, irqflags); 4878c2ecf20Sopenharmony_ci if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) { 4888c2ecf20Sopenharmony_ci drm_dbg_core(dev, "disabling vblank on crtc %u\n", pipe); 4898c2ecf20Sopenharmony_ci drm_vblank_disable_and_save(dev, pipe); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void drm_vblank_init_release(struct drm_device *dev, void *ptr) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = ptr; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci drm_WARN_ON(dev, READ_ONCE(vblank->enabled) && 4998c2ecf20Sopenharmony_ci drm_core_check_feature(dev, DRIVER_MODESET)); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci drm_vblank_destroy_worker(vblank); 5028c2ecf20Sopenharmony_ci del_timer_sync(&vblank->disable_timer); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci/** 5068c2ecf20Sopenharmony_ci * drm_vblank_init - initialize vblank support 5078c2ecf20Sopenharmony_ci * @dev: DRM device 5088c2ecf20Sopenharmony_ci * @num_crtcs: number of CRTCs supported by @dev 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * This function initializes vblank support for @num_crtcs display pipelines. 5118c2ecf20Sopenharmony_ci * Cleanup is handled automatically through a cleanup function added with 5128c2ecf20Sopenharmony_ci * drmm_add_action_or_reset(). 5138c2ecf20Sopenharmony_ci * 5148c2ecf20Sopenharmony_ci * Returns: 5158c2ecf20Sopenharmony_ci * Zero on success or a negative error code on failure. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ciint drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci int ret; 5208c2ecf20Sopenharmony_ci unsigned int i; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci spin_lock_init(&dev->vbl_lock); 5238c2ecf20Sopenharmony_ci spin_lock_init(&dev->vblank_time_lock); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci dev->vblank = drmm_kcalloc(dev, num_crtcs, sizeof(*dev->vblank), GFP_KERNEL); 5268c2ecf20Sopenharmony_ci if (!dev->vblank) 5278c2ecf20Sopenharmony_ci return -ENOMEM; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci dev->num_crtcs = num_crtcs; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci for (i = 0; i < num_crtcs; i++) { 5328c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[i]; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci vblank->dev = dev; 5358c2ecf20Sopenharmony_ci vblank->pipe = i; 5368c2ecf20Sopenharmony_ci init_waitqueue_head(&vblank->queue); 5378c2ecf20Sopenharmony_ci timer_setup(&vblank->disable_timer, vblank_disable_fn, 0); 5388c2ecf20Sopenharmony_ci seqlock_init(&vblank->seqlock); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci ret = drmm_add_action_or_reset(dev, drm_vblank_init_release, 5418c2ecf20Sopenharmony_ci vblank); 5428c2ecf20Sopenharmony_ci if (ret) 5438c2ecf20Sopenharmony_ci return ret; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci ret = drm_vblank_worker_init(vblank); 5468c2ecf20Sopenharmony_ci if (ret) 5478c2ecf20Sopenharmony_ci return ret; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_vblank_init); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/** 5558c2ecf20Sopenharmony_ci * drm_dev_has_vblank - test if vblanking has been initialized for 5568c2ecf20Sopenharmony_ci * a device 5578c2ecf20Sopenharmony_ci * @dev: the device 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Drivers may call this function to test if vblank support is 5608c2ecf20Sopenharmony_ci * initialized for a device. For most hardware this means that vblanking 5618c2ecf20Sopenharmony_ci * can also be enabled. 5628c2ecf20Sopenharmony_ci * 5638c2ecf20Sopenharmony_ci * Atomic helpers use this function to initialize 5648c2ecf20Sopenharmony_ci * &drm_crtc_state.no_vblank. See also drm_atomic_helper_check_modeset(). 5658c2ecf20Sopenharmony_ci * 5668c2ecf20Sopenharmony_ci * Returns: 5678c2ecf20Sopenharmony_ci * True if vblanking has been initialized for the given device, false 5688c2ecf20Sopenharmony_ci * otherwise. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_cibool drm_dev_has_vblank(const struct drm_device *dev) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci return dev->num_crtcs != 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_dev_has_vblank); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/** 5778c2ecf20Sopenharmony_ci * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC 5788c2ecf20Sopenharmony_ci * @crtc: which CRTC's vblank waitqueue to retrieve 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * This function returns a pointer to the vblank waitqueue for the CRTC. 5818c2ecf20Sopenharmony_ci * Drivers can use this to implement vblank waits using wait_event() and related 5828c2ecf20Sopenharmony_ci * functions. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ciwait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci return &crtc->dev->vblank[drm_crtc_index(crtc)].queue; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_waitqueue); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/** 5928c2ecf20Sopenharmony_ci * drm_calc_timestamping_constants - calculate vblank timestamp constants 5938c2ecf20Sopenharmony_ci * @crtc: drm_crtc whose timestamp constants should be updated. 5948c2ecf20Sopenharmony_ci * @mode: display mode containing the scanout timings 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Calculate and store various constants which are later needed by vblank and 5978c2ecf20Sopenharmony_ci * swap-completion timestamping, e.g, by 5988c2ecf20Sopenharmony_ci * drm_crtc_vblank_helper_get_vblank_timestamp(). They are derived from 5998c2ecf20Sopenharmony_ci * CRTC's true scanout timing, so they take things like panel scaling or 6008c2ecf20Sopenharmony_ci * other adjustments into account. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_civoid drm_calc_timestamping_constants(struct drm_crtc *crtc, 6038c2ecf20Sopenharmony_ci const struct drm_display_mode *mode) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 6068c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 6078c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 6088c2ecf20Sopenharmony_ci int linedur_ns = 0, framedur_ns = 0; 6098c2ecf20Sopenharmony_ci int dotclock = mode->crtc_clock; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 6128c2ecf20Sopenharmony_ci return; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 6158c2ecf20Sopenharmony_ci return; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Valid dotclock? */ 6188c2ecf20Sopenharmony_ci if (dotclock > 0) { 6198c2ecf20Sopenharmony_ci int frame_size = mode->crtc_htotal * mode->crtc_vtotal; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* 6228c2ecf20Sopenharmony_ci * Convert scanline length in pixels and video 6238c2ecf20Sopenharmony_ci * dot clock to line duration and frame duration 6248c2ecf20Sopenharmony_ci * in nanoseconds: 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); 6278c2ecf20Sopenharmony_ci framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * Fields of interlaced scanout modes are only half a frame duration. 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_INTERLACE) 6338c2ecf20Sopenharmony_ci framedur_ns /= 2; 6348c2ecf20Sopenharmony_ci } else { 6358c2ecf20Sopenharmony_ci drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n", 6368c2ecf20Sopenharmony_ci crtc->base.id); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci vblank->linedur_ns = linedur_ns; 6408c2ecf20Sopenharmony_ci vblank->framedur_ns = framedur_ns; 6418c2ecf20Sopenharmony_ci vblank->hwmode = *mode; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci drm_dbg_core(dev, 6448c2ecf20Sopenharmony_ci "crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", 6458c2ecf20Sopenharmony_ci crtc->base.id, mode->crtc_htotal, 6468c2ecf20Sopenharmony_ci mode->crtc_vtotal, mode->crtc_vdisplay); 6478c2ecf20Sopenharmony_ci drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n", 6488c2ecf20Sopenharmony_ci crtc->base.id, dotclock, framedur_ns, linedur_ns); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_calc_timestamping_constants); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/** 6538c2ecf20Sopenharmony_ci * drm_crtc_vblank_helper_get_vblank_timestamp_internal - precise vblank 6548c2ecf20Sopenharmony_ci * timestamp helper 6558c2ecf20Sopenharmony_ci * @crtc: CRTC whose vblank timestamp to retrieve 6568c2ecf20Sopenharmony_ci * @max_error: Desired maximum allowable error in timestamps (nanosecs) 6578c2ecf20Sopenharmony_ci * On return contains true maximum error of timestamp 6588c2ecf20Sopenharmony_ci * @vblank_time: Pointer to time which should receive the timestamp 6598c2ecf20Sopenharmony_ci * @in_vblank_irq: 6608c2ecf20Sopenharmony_ci * True when called from drm_crtc_handle_vblank(). Some drivers 6618c2ecf20Sopenharmony_ci * need to apply some workarounds for gpu-specific vblank irq quirks 6628c2ecf20Sopenharmony_ci * if flag is set. 6638c2ecf20Sopenharmony_ci * @get_scanout_position: 6648c2ecf20Sopenharmony_ci * Callback function to retrieve the scanout position. See 6658c2ecf20Sopenharmony_ci * @struct drm_crtc_helper_funcs.get_scanout_position. 6668c2ecf20Sopenharmony_ci * 6678c2ecf20Sopenharmony_ci * Implements calculation of exact vblank timestamps from given drm_display_mode 6688c2ecf20Sopenharmony_ci * timings and current video scanout position of a CRTC. 6698c2ecf20Sopenharmony_ci * 6708c2ecf20Sopenharmony_ci * The current implementation only handles standard video modes. For double scan 6718c2ecf20Sopenharmony_ci * and interlaced modes the driver is supposed to adjust the hardware mode 6728c2ecf20Sopenharmony_ci * (taken from &drm_crtc_state.adjusted mode for atomic modeset drivers) to 6738c2ecf20Sopenharmony_ci * match the scanout position reported. 6748c2ecf20Sopenharmony_ci * 6758c2ecf20Sopenharmony_ci * Note that atomic drivers must call drm_calc_timestamping_constants() before 6768c2ecf20Sopenharmony_ci * enabling a CRTC. The atomic helpers already take care of that in 6778c2ecf20Sopenharmony_ci * drm_atomic_helper_calc_timestamping_constants(). 6788c2ecf20Sopenharmony_ci * 6798c2ecf20Sopenharmony_ci * Returns: 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * Returns true on success, and false on failure, i.e. when no accurate 6828c2ecf20Sopenharmony_ci * timestamp could be acquired. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_cibool 6858c2ecf20Sopenharmony_cidrm_crtc_vblank_helper_get_vblank_timestamp_internal( 6868c2ecf20Sopenharmony_ci struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, 6878c2ecf20Sopenharmony_ci bool in_vblank_irq, 6888c2ecf20Sopenharmony_ci drm_vblank_get_scanout_position_func get_scanout_position) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 6918c2ecf20Sopenharmony_ci unsigned int pipe = crtc->index; 6928c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 6938c2ecf20Sopenharmony_ci struct timespec64 ts_etime, ts_vblank_time; 6948c2ecf20Sopenharmony_ci ktime_t stime, etime; 6958c2ecf20Sopenharmony_ci bool vbl_status; 6968c2ecf20Sopenharmony_ci const struct drm_display_mode *mode; 6978c2ecf20Sopenharmony_ci int vpos, hpos, i; 6988c2ecf20Sopenharmony_ci int delta_ns, duration_ns; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (pipe >= dev->num_crtcs) { 7018c2ecf20Sopenharmony_ci drm_err(dev, "Invalid crtc %u\n", pipe); 7028c2ecf20Sopenharmony_ci return false; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* Scanout position query not supported? Should not happen. */ 7068c2ecf20Sopenharmony_ci if (!get_scanout_position) { 7078c2ecf20Sopenharmony_ci drm_err(dev, "Called from CRTC w/o get_scanout_position()!?\n"); 7088c2ecf20Sopenharmony_ci return false; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (drm_drv_uses_atomic_modeset(dev)) 7128c2ecf20Sopenharmony_ci mode = &vblank->hwmode; 7138c2ecf20Sopenharmony_ci else 7148c2ecf20Sopenharmony_ci mode = &crtc->hwmode; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* If mode timing undefined, just return as no-op: 7178c2ecf20Sopenharmony_ci * Happens during initial modesetting of a crtc. 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_ci if (mode->crtc_clock == 0) { 7208c2ecf20Sopenharmony_ci drm_dbg_core(dev, "crtc %u: Noop due to uninitialized mode.\n", 7218c2ecf20Sopenharmony_ci pipe); 7228c2ecf20Sopenharmony_ci drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev)); 7238c2ecf20Sopenharmony_ci return false; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Get current scanout position with system timestamp. 7278c2ecf20Sopenharmony_ci * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times 7288c2ecf20Sopenharmony_ci * if single query takes longer than max_error nanoseconds. 7298c2ecf20Sopenharmony_ci * 7308c2ecf20Sopenharmony_ci * This guarantees a tight bound on maximum error if 7318c2ecf20Sopenharmony_ci * code gets preempted or delayed for some reason. 7328c2ecf20Sopenharmony_ci */ 7338c2ecf20Sopenharmony_ci for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * Get vertical and horizontal scanout position vpos, hpos, 7368c2ecf20Sopenharmony_ci * and bounding timestamps stime, etime, pre/post query. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci vbl_status = get_scanout_position(crtc, in_vblank_irq, 7398c2ecf20Sopenharmony_ci &vpos, &hpos, 7408c2ecf20Sopenharmony_ci &stime, &etime, 7418c2ecf20Sopenharmony_ci mode); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Return as no-op if scanout query unsupported or failed. */ 7448c2ecf20Sopenharmony_ci if (!vbl_status) { 7458c2ecf20Sopenharmony_ci drm_dbg_core(dev, 7468c2ecf20Sopenharmony_ci "crtc %u : scanoutpos query failed.\n", 7478c2ecf20Sopenharmony_ci pipe); 7488c2ecf20Sopenharmony_ci return false; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Compute uncertainty in timestamp of scanout position query. */ 7528c2ecf20Sopenharmony_ci duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Accept result with < max_error nsecs timing uncertainty. */ 7558c2ecf20Sopenharmony_ci if (duration_ns <= *max_error) 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* Noisy system timing? */ 7608c2ecf20Sopenharmony_ci if (i == DRM_TIMESTAMP_MAXRETRIES) { 7618c2ecf20Sopenharmony_ci drm_dbg_core(dev, 7628c2ecf20Sopenharmony_ci "crtc %u: Noisy timestamp %d us > %d us [%d reps].\n", 7638c2ecf20Sopenharmony_ci pipe, duration_ns / 1000, *max_error / 1000, i); 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* Return upper bound of timestamp precision error. */ 7678c2ecf20Sopenharmony_ci *max_error = duration_ns; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* Convert scanout position into elapsed time at raw_time query 7708c2ecf20Sopenharmony_ci * since start of scanout at first display scanline. delta_ns 7718c2ecf20Sopenharmony_ci * can be negative if start of scanout hasn't happened yet. 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_ci delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos), 7748c2ecf20Sopenharmony_ci mode->crtc_clock); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* Subtract time delta from raw timestamp to get final 7778c2ecf20Sopenharmony_ci * vblank_time timestamp for end of vblank. 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci *vblank_time = ktime_sub_ns(etime, delta_ns); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (!drm_debug_enabled(DRM_UT_VBL)) 7828c2ecf20Sopenharmony_ci return true; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ts_etime = ktime_to_timespec64(etime); 7858c2ecf20Sopenharmony_ci ts_vblank_time = ktime_to_timespec64(*vblank_time); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, 7888c2ecf20Sopenharmony_ci "crtc %u : v p(%d,%d)@ %lld.%06ld -> %lld.%06ld [e %d us, %d rep]\n", 7898c2ecf20Sopenharmony_ci pipe, hpos, vpos, 7908c2ecf20Sopenharmony_ci (u64)ts_etime.tv_sec, ts_etime.tv_nsec / 1000, 7918c2ecf20Sopenharmony_ci (u64)ts_vblank_time.tv_sec, ts_vblank_time.tv_nsec / 1000, 7928c2ecf20Sopenharmony_ci duration_ns / 1000, i); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return true; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_internal); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/** 7998c2ecf20Sopenharmony_ci * drm_crtc_vblank_helper_get_vblank_timestamp - precise vblank timestamp 8008c2ecf20Sopenharmony_ci * helper 8018c2ecf20Sopenharmony_ci * @crtc: CRTC whose vblank timestamp to retrieve 8028c2ecf20Sopenharmony_ci * @max_error: Desired maximum allowable error in timestamps (nanosecs) 8038c2ecf20Sopenharmony_ci * On return contains true maximum error of timestamp 8048c2ecf20Sopenharmony_ci * @vblank_time: Pointer to time which should receive the timestamp 8058c2ecf20Sopenharmony_ci * @in_vblank_irq: 8068c2ecf20Sopenharmony_ci * True when called from drm_crtc_handle_vblank(). Some drivers 8078c2ecf20Sopenharmony_ci * need to apply some workarounds for gpu-specific vblank irq quirks 8088c2ecf20Sopenharmony_ci * if flag is set. 8098c2ecf20Sopenharmony_ci * 8108c2ecf20Sopenharmony_ci * Implements calculation of exact vblank timestamps from given drm_display_mode 8118c2ecf20Sopenharmony_ci * timings and current video scanout position of a CRTC. This can be directly 8128c2ecf20Sopenharmony_ci * used as the &drm_crtc_funcs.get_vblank_timestamp implementation of a kms 8138c2ecf20Sopenharmony_ci * driver if &drm_crtc_helper_funcs.get_scanout_position is implemented. 8148c2ecf20Sopenharmony_ci * 8158c2ecf20Sopenharmony_ci * The current implementation only handles standard video modes. For double scan 8168c2ecf20Sopenharmony_ci * and interlaced modes the driver is supposed to adjust the hardware mode 8178c2ecf20Sopenharmony_ci * (taken from &drm_crtc_state.adjusted mode for atomic modeset drivers) to 8188c2ecf20Sopenharmony_ci * match the scanout position reported. 8198c2ecf20Sopenharmony_ci * 8208c2ecf20Sopenharmony_ci * Note that atomic drivers must call drm_calc_timestamping_constants() before 8218c2ecf20Sopenharmony_ci * enabling a CRTC. The atomic helpers already take care of that in 8228c2ecf20Sopenharmony_ci * drm_atomic_helper_calc_timestamping_constants(). 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * Returns: 8258c2ecf20Sopenharmony_ci * 8268c2ecf20Sopenharmony_ci * Returns true on success, and false on failure, i.e. when no accurate 8278c2ecf20Sopenharmony_ci * timestamp could be acquired. 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_cibool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc, 8308c2ecf20Sopenharmony_ci int *max_error, 8318c2ecf20Sopenharmony_ci ktime_t *vblank_time, 8328c2ecf20Sopenharmony_ci bool in_vblank_irq) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci return drm_crtc_vblank_helper_get_vblank_timestamp_internal( 8358c2ecf20Sopenharmony_ci crtc, max_error, vblank_time, in_vblank_irq, 8368c2ecf20Sopenharmony_ci crtc->helper_private->get_scanout_position); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/** 8418c2ecf20Sopenharmony_ci * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent 8428c2ecf20Sopenharmony_ci * vblank interval 8438c2ecf20Sopenharmony_ci * @dev: DRM device 8448c2ecf20Sopenharmony_ci * @pipe: index of CRTC whose vblank timestamp to retrieve 8458c2ecf20Sopenharmony_ci * @tvblank: Pointer to target time which should receive the timestamp 8468c2ecf20Sopenharmony_ci * @in_vblank_irq: 8478c2ecf20Sopenharmony_ci * True when called from drm_crtc_handle_vblank(). Some drivers 8488c2ecf20Sopenharmony_ci * need to apply some workarounds for gpu-specific vblank irq quirks 8498c2ecf20Sopenharmony_ci * if flag is set. 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * Fetches the system timestamp corresponding to the time of the most recent 8528c2ecf20Sopenharmony_ci * vblank interval on specified CRTC. May call into kms-driver to 8538c2ecf20Sopenharmony_ci * compute the timestamp with a high-precision GPU specific method. 8548c2ecf20Sopenharmony_ci * 8558c2ecf20Sopenharmony_ci * Returns zero if timestamp originates from uncorrected do_gettimeofday() 8568c2ecf20Sopenharmony_ci * call, i.e., it isn't very precisely locked to the true vblank. 8578c2ecf20Sopenharmony_ci * 8588c2ecf20Sopenharmony_ci * Returns: 8598c2ecf20Sopenharmony_ci * True if timestamp is considered to be very precise, false otherwise. 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_cistatic bool 8628c2ecf20Sopenharmony_cidrm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, 8638c2ecf20Sopenharmony_ci ktime_t *tvblank, bool in_vblank_irq) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 8668c2ecf20Sopenharmony_ci bool ret = false; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* Define requested maximum error on timestamps (nanoseconds). */ 8698c2ecf20Sopenharmony_ci int max_error = (int) drm_timestamp_precision * 1000; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* Query driver if possible and precision timestamping enabled. */ 8728c2ecf20Sopenharmony_ci if (crtc && crtc->funcs->get_vblank_timestamp && max_error > 0) { 8738c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci ret = crtc->funcs->get_vblank_timestamp(crtc, &max_error, 8768c2ecf20Sopenharmony_ci tvblank, in_vblank_irq); 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* GPU high precision timestamp query unsupported or failed. 8808c2ecf20Sopenharmony_ci * Return current monotonic/gettimeofday timestamp as best estimate. 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci if (!ret) 8838c2ecf20Sopenharmony_ci *tvblank = ktime_get(); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return ret; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci/** 8898c2ecf20Sopenharmony_ci * drm_crtc_vblank_count - retrieve "cooked" vblank counter value 8908c2ecf20Sopenharmony_ci * @crtc: which counter to retrieve 8918c2ecf20Sopenharmony_ci * 8928c2ecf20Sopenharmony_ci * Fetches the "cooked" vblank count value that represents the number of 8938c2ecf20Sopenharmony_ci * vblank events since the system was booted, including lost events due to 8948c2ecf20Sopenharmony_ci * modesetting activity. Note that this timer isn't correct against a racing 8958c2ecf20Sopenharmony_ci * vblank interrupt (since it only reports the software vblank counter), see 8968c2ecf20Sopenharmony_ci * drm_crtc_accurate_vblank_count() for such use-cases. 8978c2ecf20Sopenharmony_ci * 8988c2ecf20Sopenharmony_ci * Note that for a given vblank counter value drm_crtc_handle_vblank() 8998c2ecf20Sopenharmony_ci * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() 9008c2ecf20Sopenharmony_ci * provide a barrier: Any writes done before calling 9018c2ecf20Sopenharmony_ci * drm_crtc_handle_vblank() will be visible to callers of the later 9028c2ecf20Sopenharmony_ci * functions, iff the vblank count is the same or a later one. 9038c2ecf20Sopenharmony_ci * 9048c2ecf20Sopenharmony_ci * See also &drm_vblank_crtc.count. 9058c2ecf20Sopenharmony_ci * 9068c2ecf20Sopenharmony_ci * Returns: 9078c2ecf20Sopenharmony_ci * The software vblank counter. 9088c2ecf20Sopenharmony_ci */ 9098c2ecf20Sopenharmony_ciu64 drm_crtc_vblank_count(struct drm_crtc *crtc) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci return drm_vblank_count(crtc->dev, drm_crtc_index(crtc)); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_count); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci/** 9168c2ecf20Sopenharmony_ci * drm_vblank_count_and_time - retrieve "cooked" vblank counter value and the 9178c2ecf20Sopenharmony_ci * system timestamp corresponding to that vblank counter value. 9188c2ecf20Sopenharmony_ci * @dev: DRM device 9198c2ecf20Sopenharmony_ci * @pipe: index of CRTC whose counter to retrieve 9208c2ecf20Sopenharmony_ci * @vblanktime: Pointer to ktime_t to receive the vblank timestamp. 9218c2ecf20Sopenharmony_ci * 9228c2ecf20Sopenharmony_ci * Fetches the "cooked" vblank count value that represents the number of 9238c2ecf20Sopenharmony_ci * vblank events since the system was booted, including lost events due to 9248c2ecf20Sopenharmony_ci * modesetting activity. Returns corresponding system timestamp of the time 9258c2ecf20Sopenharmony_ci * of the vblank interval that corresponds to the current vblank counter value. 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * This is the legacy version of drm_crtc_vblank_count_and_time(). 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_cistatic u64 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, 9308c2ecf20Sopenharmony_ci ktime_t *vblanktime) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 9338c2ecf20Sopenharmony_ci u64 vblank_count; 9348c2ecf20Sopenharmony_ci unsigned int seq; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) { 9378c2ecf20Sopenharmony_ci *vblanktime = 0; 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci do { 9428c2ecf20Sopenharmony_ci seq = read_seqbegin(&vblank->seqlock); 9438c2ecf20Sopenharmony_ci vblank_count = atomic64_read(&vblank->count); 9448c2ecf20Sopenharmony_ci *vblanktime = vblank->time; 9458c2ecf20Sopenharmony_ci } while (read_seqretry(&vblank->seqlock, seq)); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return vblank_count; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci/** 9518c2ecf20Sopenharmony_ci * drm_crtc_vblank_count_and_time - retrieve "cooked" vblank counter value 9528c2ecf20Sopenharmony_ci * and the system timestamp corresponding to that vblank counter value 9538c2ecf20Sopenharmony_ci * @crtc: which counter to retrieve 9548c2ecf20Sopenharmony_ci * @vblanktime: Pointer to time to receive the vblank timestamp. 9558c2ecf20Sopenharmony_ci * 9568c2ecf20Sopenharmony_ci * Fetches the "cooked" vblank count value that represents the number of 9578c2ecf20Sopenharmony_ci * vblank events since the system was booted, including lost events due to 9588c2ecf20Sopenharmony_ci * modesetting activity. Returns corresponding system timestamp of the time 9598c2ecf20Sopenharmony_ci * of the vblank interval that corresponds to the current vblank counter value. 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci * Note that for a given vblank counter value drm_crtc_handle_vblank() 9628c2ecf20Sopenharmony_ci * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() 9638c2ecf20Sopenharmony_ci * provide a barrier: Any writes done before calling 9648c2ecf20Sopenharmony_ci * drm_crtc_handle_vblank() will be visible to callers of the later 9658c2ecf20Sopenharmony_ci * functions, iff the vblank count is the same or a later one. 9668c2ecf20Sopenharmony_ci * 9678c2ecf20Sopenharmony_ci * See also &drm_vblank_crtc.count. 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_ciu64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, 9708c2ecf20Sopenharmony_ci ktime_t *vblanktime) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci return drm_vblank_count_and_time(crtc->dev, drm_crtc_index(crtc), 9738c2ecf20Sopenharmony_ci vblanktime); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_count_and_time); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic void send_vblank_event(struct drm_device *dev, 9788c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e, 9798c2ecf20Sopenharmony_ci u64 seq, ktime_t now) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci struct timespec64 tv; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci switch (e->event.base.type) { 9848c2ecf20Sopenharmony_ci case DRM_EVENT_VBLANK: 9858c2ecf20Sopenharmony_ci case DRM_EVENT_FLIP_COMPLETE: 9868c2ecf20Sopenharmony_ci tv = ktime_to_timespec64(now); 9878c2ecf20Sopenharmony_ci e->event.vbl.sequence = seq; 9888c2ecf20Sopenharmony_ci /* 9898c2ecf20Sopenharmony_ci * e->event is a user space structure, with hardcoded unsigned 9908c2ecf20Sopenharmony_ci * 32-bit seconds/microseconds. This is safe as we always use 9918c2ecf20Sopenharmony_ci * monotonic timestamps since linux-4.15 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci e->event.vbl.tv_sec = tv.tv_sec; 9948c2ecf20Sopenharmony_ci e->event.vbl.tv_usec = tv.tv_nsec / 1000; 9958c2ecf20Sopenharmony_ci break; 9968c2ecf20Sopenharmony_ci case DRM_EVENT_CRTC_SEQUENCE: 9978c2ecf20Sopenharmony_ci if (seq) 9988c2ecf20Sopenharmony_ci e->event.seq.sequence = seq; 9998c2ecf20Sopenharmony_ci e->event.seq.time_ns = ktime_to_ns(now); 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci trace_drm_vblank_event_delivered(e->base.file_priv, e->pipe, seq); 10038c2ecf20Sopenharmony_ci drm_send_event_locked(dev, &e->base); 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci/** 10078c2ecf20Sopenharmony_ci * drm_crtc_arm_vblank_event - arm vblank event after pageflip 10088c2ecf20Sopenharmony_ci * @crtc: the source CRTC of the vblank event 10098c2ecf20Sopenharmony_ci * @e: the event to send 10108c2ecf20Sopenharmony_ci * 10118c2ecf20Sopenharmony_ci * A lot of drivers need to generate vblank events for the very next vblank 10128c2ecf20Sopenharmony_ci * interrupt. For example when the page flip interrupt happens when the page 10138c2ecf20Sopenharmony_ci * flip gets armed, but not when it actually executes within the next vblank 10148c2ecf20Sopenharmony_ci * period. This helper function implements exactly the required vblank arming 10158c2ecf20Sopenharmony_ci * behaviour. 10168c2ecf20Sopenharmony_ci * 10178c2ecf20Sopenharmony_ci * NOTE: Drivers using this to send out the &drm_crtc_state.event as part of an 10188c2ecf20Sopenharmony_ci * atomic commit must ensure that the next vblank happens at exactly the same 10198c2ecf20Sopenharmony_ci * time as the atomic commit is committed to the hardware. This function itself 10208c2ecf20Sopenharmony_ci * does **not** protect against the next vblank interrupt racing with either this 10218c2ecf20Sopenharmony_ci * function call or the atomic commit operation. A possible sequence could be: 10228c2ecf20Sopenharmony_ci * 10238c2ecf20Sopenharmony_ci * 1. Driver commits new hardware state into vblank-synchronized registers. 10248c2ecf20Sopenharmony_ci * 2. A vblank happens, committing the hardware state. Also the corresponding 10258c2ecf20Sopenharmony_ci * vblank interrupt is fired off and fully processed by the interrupt 10268c2ecf20Sopenharmony_ci * handler. 10278c2ecf20Sopenharmony_ci * 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event(). 10288c2ecf20Sopenharmony_ci * 4. The event is only send out for the next vblank, which is wrong. 10298c2ecf20Sopenharmony_ci * 10308c2ecf20Sopenharmony_ci * An equivalent race can happen when the driver calls 10318c2ecf20Sopenharmony_ci * drm_crtc_arm_vblank_event() before writing out the new hardware state. 10328c2ecf20Sopenharmony_ci * 10338c2ecf20Sopenharmony_ci * The only way to make this work safely is to prevent the vblank from firing 10348c2ecf20Sopenharmony_ci * (and the hardware from committing anything else) until the entire atomic 10358c2ecf20Sopenharmony_ci * commit sequence has run to completion. If the hardware does not have such a 10368c2ecf20Sopenharmony_ci * feature (e.g. using a "go" bit), then it is unsafe to use this functions. 10378c2ecf20Sopenharmony_ci * Instead drivers need to manually send out the event from their interrupt 10388c2ecf20Sopenharmony_ci * handler by calling drm_crtc_send_vblank_event() and make sure that there's no 10398c2ecf20Sopenharmony_ci * possible race with the hardware committing the atomic update. 10408c2ecf20Sopenharmony_ci * 10418c2ecf20Sopenharmony_ci * Caller must hold a vblank reference for the event @e acquired by a 10428c2ecf20Sopenharmony_ci * drm_crtc_vblank_get(), which will be dropped when the next vblank arrives. 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_civoid drm_crtc_arm_vblank_event(struct drm_crtc *crtc, 10458c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 10488c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci assert_spin_locked(&dev->event_lock); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci e->pipe = pipe; 10538c2ecf20Sopenharmony_ci e->sequence = drm_crtc_accurate_vblank_count(crtc) + 1; 10548c2ecf20Sopenharmony_ci list_add_tail(&e->base.link, &dev->vblank_event_list); 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_arm_vblank_event); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci/** 10598c2ecf20Sopenharmony_ci * drm_crtc_send_vblank_event - helper to send vblank event after pageflip 10608c2ecf20Sopenharmony_ci * @crtc: the source CRTC of the vblank event 10618c2ecf20Sopenharmony_ci * @e: the event to send 10628c2ecf20Sopenharmony_ci * 10638c2ecf20Sopenharmony_ci * Updates sequence # and timestamp on event for the most recently processed 10648c2ecf20Sopenharmony_ci * vblank, and sends it to userspace. Caller must hold event lock. 10658c2ecf20Sopenharmony_ci * 10668c2ecf20Sopenharmony_ci * See drm_crtc_arm_vblank_event() for a helper which can be used in certain 10678c2ecf20Sopenharmony_ci * situation, especially to send out events for atomic commit operations. 10688c2ecf20Sopenharmony_ci */ 10698c2ecf20Sopenharmony_civoid drm_crtc_send_vblank_event(struct drm_crtc *crtc, 10708c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 10738c2ecf20Sopenharmony_ci u64 seq; 10748c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 10758c2ecf20Sopenharmony_ci ktime_t now; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (drm_dev_has_vblank(dev)) { 10788c2ecf20Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 10798c2ecf20Sopenharmony_ci } else { 10808c2ecf20Sopenharmony_ci seq = 0; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci now = ktime_get(); 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci e->pipe = pipe; 10858c2ecf20Sopenharmony_ci send_vblank_event(dev, e, seq, now); 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_send_vblank_event); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic int __enable_vblank(struct drm_device *dev, unsigned int pipe) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 10928c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, !crtc)) 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (crtc->funcs->enable_vblank) 10988c2ecf20Sopenharmony_ci return crtc->funcs->enable_vblank(crtc); 10998c2ecf20Sopenharmony_ci } else if (dev->driver->enable_vblank) { 11008c2ecf20Sopenharmony_ci return dev->driver->enable_vblank(dev, pipe); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci return -EINVAL; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 11098c2ecf20Sopenharmony_ci int ret = 0; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci assert_spin_locked(&dev->vbl_lock); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci spin_lock(&dev->vblank_time_lock); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!vblank->enabled) { 11168c2ecf20Sopenharmony_ci /* 11178c2ecf20Sopenharmony_ci * Enable vblank irqs under vblank_time_lock protection. 11188c2ecf20Sopenharmony_ci * All vblank count & timestamp updates are held off 11198c2ecf20Sopenharmony_ci * until we are done reinitializing master counter and 11208c2ecf20Sopenharmony_ci * timestamps. Filtercode in drm_handle_vblank() will 11218c2ecf20Sopenharmony_ci * prevent double-accounting of same vblank interval. 11228c2ecf20Sopenharmony_ci */ 11238c2ecf20Sopenharmony_ci ret = __enable_vblank(dev, pipe); 11248c2ecf20Sopenharmony_ci drm_dbg_core(dev, "enabling vblank on crtc %u, ret: %d\n", 11258c2ecf20Sopenharmony_ci pipe, ret); 11268c2ecf20Sopenharmony_ci if (ret) { 11278c2ecf20Sopenharmony_ci atomic_dec(&vblank->refcount); 11288c2ecf20Sopenharmony_ci } else { 11298c2ecf20Sopenharmony_ci drm_update_vblank_count(dev, pipe, 0); 11308c2ecf20Sopenharmony_ci /* drm_update_vblank_count() includes a wmb so we just 11318c2ecf20Sopenharmony_ci * need to ensure that the compiler emits the write 11328c2ecf20Sopenharmony_ci * to mark the vblank as enabled after the call 11338c2ecf20Sopenharmony_ci * to drm_update_vblank_count(). 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_ci WRITE_ONCE(vblank->enabled, true); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci return ret; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ciint drm_vblank_get(struct drm_device *dev, unsigned int pipe) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 11478c2ecf20Sopenharmony_ci unsigned long irqflags; 11488c2ecf20Sopenharmony_ci int ret = 0; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 11518c2ecf20Sopenharmony_ci return -EINVAL; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 11548c2ecf20Sopenharmony_ci return -EINVAL; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->vbl_lock, irqflags); 11578c2ecf20Sopenharmony_ci /* Going from 0->1 means we have to enable interrupts again */ 11588c2ecf20Sopenharmony_ci if (atomic_add_return(1, &vblank->refcount) == 1) { 11598c2ecf20Sopenharmony_ci ret = drm_vblank_enable(dev, pipe); 11608c2ecf20Sopenharmony_ci } else { 11618c2ecf20Sopenharmony_ci if (!vblank->enabled) { 11628c2ecf20Sopenharmony_ci atomic_dec(&vblank->refcount); 11638c2ecf20Sopenharmony_ci ret = -EINVAL; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci return ret; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci/** 11728c2ecf20Sopenharmony_ci * drm_crtc_vblank_get - get a reference count on vblank events 11738c2ecf20Sopenharmony_ci * @crtc: which CRTC to own 11748c2ecf20Sopenharmony_ci * 11758c2ecf20Sopenharmony_ci * Acquire a reference count on vblank events to avoid having them disabled 11768c2ecf20Sopenharmony_ci * while in use. 11778c2ecf20Sopenharmony_ci * 11788c2ecf20Sopenharmony_ci * Returns: 11798c2ecf20Sopenharmony_ci * Zero on success or a negative error code on failure. 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_ciint drm_crtc_vblank_get(struct drm_crtc *crtc) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci return drm_vblank_get(crtc->dev, drm_crtc_index(crtc)); 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_get); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_civoid drm_vblank_put(struct drm_device *dev, unsigned int pipe) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 11928c2ecf20Sopenharmony_ci return; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, atomic_read(&vblank->refcount) == 0)) 11958c2ecf20Sopenharmony_ci return; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* Last user schedules interrupt disable */ 11988c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&vblank->refcount)) { 11998c2ecf20Sopenharmony_ci if (drm_vblank_offdelay == 0) 12008c2ecf20Sopenharmony_ci return; 12018c2ecf20Sopenharmony_ci else if (drm_vblank_offdelay < 0) 12028c2ecf20Sopenharmony_ci vblank_disable_fn(&vblank->disable_timer); 12038c2ecf20Sopenharmony_ci else if (!dev->vblank_disable_immediate) 12048c2ecf20Sopenharmony_ci mod_timer(&vblank->disable_timer, 12058c2ecf20Sopenharmony_ci jiffies + ((drm_vblank_offdelay * HZ)/1000)); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci/** 12108c2ecf20Sopenharmony_ci * drm_crtc_vblank_put - give up ownership of vblank events 12118c2ecf20Sopenharmony_ci * @crtc: which counter to give up 12128c2ecf20Sopenharmony_ci * 12138c2ecf20Sopenharmony_ci * Release ownership of a given vblank counter, turning off interrupts 12148c2ecf20Sopenharmony_ci * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_civoid drm_crtc_vblank_put(struct drm_crtc *crtc) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci drm_vblank_put(crtc->dev, drm_crtc_index(crtc)); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_put); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci/** 12238c2ecf20Sopenharmony_ci * drm_wait_one_vblank - wait for one vblank 12248c2ecf20Sopenharmony_ci * @dev: DRM device 12258c2ecf20Sopenharmony_ci * @pipe: CRTC index 12268c2ecf20Sopenharmony_ci * 12278c2ecf20Sopenharmony_ci * This waits for one vblank to pass on @pipe, using the irq driver interfaces. 12288c2ecf20Sopenharmony_ci * It is a failure to call this when the vblank irq for @pipe is disabled, e.g. 12298c2ecf20Sopenharmony_ci * due to lack of driver support or because the crtc is off. 12308c2ecf20Sopenharmony_ci * 12318c2ecf20Sopenharmony_ci * This is the legacy version of drm_crtc_wait_one_vblank(). 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_civoid drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 12368c2ecf20Sopenharmony_ci int ret; 12378c2ecf20Sopenharmony_ci u64 last; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 12408c2ecf20Sopenharmony_ci return; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci ret = drm_vblank_get(dev, pipe); 12438c2ecf20Sopenharmony_ci if (drm_WARN(dev, ret, "vblank not available on crtc %i, ret=%i\n", 12448c2ecf20Sopenharmony_ci pipe, ret)) 12458c2ecf20Sopenharmony_ci return; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci last = drm_vblank_count(dev, pipe); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci ret = wait_event_timeout(vblank->queue, 12508c2ecf20Sopenharmony_ci last != drm_vblank_count(dev, pipe), 12518c2ecf20Sopenharmony_ci msecs_to_jiffies(100)); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_wait_one_vblank); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci/** 12608c2ecf20Sopenharmony_ci * drm_crtc_wait_one_vblank - wait for one vblank 12618c2ecf20Sopenharmony_ci * @crtc: DRM crtc 12628c2ecf20Sopenharmony_ci * 12638c2ecf20Sopenharmony_ci * This waits for one vblank to pass on @crtc, using the irq driver interfaces. 12648c2ecf20Sopenharmony_ci * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. 12658c2ecf20Sopenharmony_ci * due to lack of driver support or because the crtc is off. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_civoid drm_crtc_wait_one_vblank(struct drm_crtc *crtc) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_wait_one_vblank); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci/** 12748c2ecf20Sopenharmony_ci * drm_crtc_vblank_off - disable vblank events on a CRTC 12758c2ecf20Sopenharmony_ci * @crtc: CRTC in question 12768c2ecf20Sopenharmony_ci * 12778c2ecf20Sopenharmony_ci * Drivers can use this function to shut down the vblank interrupt handling when 12788c2ecf20Sopenharmony_ci * disabling a crtc. This function ensures that the latest vblank frame count is 12798c2ecf20Sopenharmony_ci * stored so that drm_vblank_on can restore it again. 12808c2ecf20Sopenharmony_ci * 12818c2ecf20Sopenharmony_ci * Drivers must use this function when the hardware vblank counter can get 12828c2ecf20Sopenharmony_ci * reset, e.g. when suspending or disabling the @crtc in general. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_civoid drm_crtc_vblank_off(struct drm_crtc *crtc) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 12878c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 12888c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 12898c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e, *t; 12908c2ecf20Sopenharmony_ci ktime_t now; 12918c2ecf20Sopenharmony_ci u64 seq; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 12948c2ecf20Sopenharmony_ci return; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * Grab event_lock early to prevent vblank work from being scheduled 12988c2ecf20Sopenharmony_ci * while we're in the middle of shutting down vblank interrupts 12998c2ecf20Sopenharmony_ci */ 13008c2ecf20Sopenharmony_ci spin_lock_irq(&dev->event_lock); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci spin_lock(&dev->vbl_lock); 13038c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n", 13048c2ecf20Sopenharmony_ci pipe, vblank->enabled, vblank->inmodeset); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* Avoid redundant vblank disables without previous 13078c2ecf20Sopenharmony_ci * drm_crtc_vblank_on(). */ 13088c2ecf20Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset) 13098c2ecf20Sopenharmony_ci drm_vblank_disable_and_save(dev, pipe); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci wake_up(&vblank->queue); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* 13148c2ecf20Sopenharmony_ci * Prevent subsequent drm_vblank_get() from re-enabling 13158c2ecf20Sopenharmony_ci * the vblank interrupt by bumping the refcount. 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ci if (!vblank->inmodeset) { 13188c2ecf20Sopenharmony_ci atomic_inc(&vblank->refcount); 13198c2ecf20Sopenharmony_ci vblank->inmodeset = 1; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci spin_unlock(&dev->vbl_lock); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* Send any queued vblank events, lest the natives grow disquiet */ 13248c2ecf20Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 13278c2ecf20Sopenharmony_ci if (e->pipe != pipe) 13288c2ecf20Sopenharmony_ci continue; 13298c2ecf20Sopenharmony_ci drm_dbg_core(dev, "Sending premature vblank event on disable: " 13308c2ecf20Sopenharmony_ci "wanted %llu, current %llu\n", 13318c2ecf20Sopenharmony_ci e->sequence, seq); 13328c2ecf20Sopenharmony_ci list_del(&e->base.link); 13338c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 13348c2ecf20Sopenharmony_ci send_vblank_event(dev, e, seq, now); 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* Cancel any leftover pending vblank work */ 13388c2ecf20Sopenharmony_ci drm_vblank_cancel_pending_works(vblank); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* Will be reset by the modeset helpers when re-enabling the crtc by 13438c2ecf20Sopenharmony_ci * calling drm_calc_timestamping_constants(). */ 13448c2ecf20Sopenharmony_ci vblank->hwmode.crtc_clock = 0; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* Wait for any vblank work that's still executing to finish */ 13478c2ecf20Sopenharmony_ci drm_vblank_flush_worker(vblank); 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_off); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci/** 13528c2ecf20Sopenharmony_ci * drm_crtc_vblank_reset - reset vblank state to off on a CRTC 13538c2ecf20Sopenharmony_ci * @crtc: CRTC in question 13548c2ecf20Sopenharmony_ci * 13558c2ecf20Sopenharmony_ci * Drivers can use this function to reset the vblank state to off at load time. 13568c2ecf20Sopenharmony_ci * Drivers should use this together with the drm_crtc_vblank_off() and 13578c2ecf20Sopenharmony_ci * drm_crtc_vblank_on() functions. The difference compared to 13588c2ecf20Sopenharmony_ci * drm_crtc_vblank_off() is that this function doesn't save the vblank counter 13598c2ecf20Sopenharmony_ci * and hence doesn't need to call any driver hooks. 13608c2ecf20Sopenharmony_ci * 13618c2ecf20Sopenharmony_ci * This is useful for recovering driver state e.g. on driver load, or on resume. 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_civoid drm_crtc_vblank_reset(struct drm_crtc *crtc) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 13668c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 13678c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci spin_lock_irq(&dev->vbl_lock); 13708c2ecf20Sopenharmony_ci /* 13718c2ecf20Sopenharmony_ci * Prevent subsequent drm_vblank_get() from enabling the vblank 13728c2ecf20Sopenharmony_ci * interrupt by bumping the refcount. 13738c2ecf20Sopenharmony_ci */ 13748c2ecf20Sopenharmony_ci if (!vblank->inmodeset) { 13758c2ecf20Sopenharmony_ci atomic_inc(&vblank->refcount); 13768c2ecf20Sopenharmony_ci vblank->inmodeset = 1; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->vbl_lock); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci drm_WARN_ON(dev, !list_empty(&dev->vblank_event_list)); 13818c2ecf20Sopenharmony_ci drm_WARN_ON(dev, !list_empty(&vblank->pending_work)); 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_reset); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/** 13868c2ecf20Sopenharmony_ci * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value 13878c2ecf20Sopenharmony_ci * @crtc: CRTC in question 13888c2ecf20Sopenharmony_ci * @max_vblank_count: max hardware vblank counter value 13898c2ecf20Sopenharmony_ci * 13908c2ecf20Sopenharmony_ci * Update the maximum hardware vblank counter value for @crtc 13918c2ecf20Sopenharmony_ci * at runtime. Useful for hardware where the operation of the 13928c2ecf20Sopenharmony_ci * hardware vblank counter depends on the currently active 13938c2ecf20Sopenharmony_ci * display configuration. 13948c2ecf20Sopenharmony_ci * 13958c2ecf20Sopenharmony_ci * For example, if the hardware vblank counter does not work 13968c2ecf20Sopenharmony_ci * when a specific connector is active the maximum can be set 13978c2ecf20Sopenharmony_ci * to zero. And when that specific connector isn't active the 13988c2ecf20Sopenharmony_ci * maximum can again be set to the appropriate non-zero value. 13998c2ecf20Sopenharmony_ci * 14008c2ecf20Sopenharmony_ci * If used, must be called before drm_vblank_on(). 14018c2ecf20Sopenharmony_ci */ 14028c2ecf20Sopenharmony_civoid drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, 14038c2ecf20Sopenharmony_ci u32 max_vblank_count) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 14068c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 14078c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci drm_WARN_ON(dev, dev->max_vblank_count); 14108c2ecf20Sopenharmony_ci drm_WARN_ON(dev, !READ_ONCE(vblank->inmodeset)); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci vblank->max_vblank_count = max_vblank_count; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_set_max_vblank_count); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci/** 14178c2ecf20Sopenharmony_ci * drm_crtc_vblank_on - enable vblank events on a CRTC 14188c2ecf20Sopenharmony_ci * @crtc: CRTC in question 14198c2ecf20Sopenharmony_ci * 14208c2ecf20Sopenharmony_ci * This functions restores the vblank interrupt state captured with 14218c2ecf20Sopenharmony_ci * drm_crtc_vblank_off() again and is generally called when enabling @crtc. Note 14228c2ecf20Sopenharmony_ci * that calls to drm_crtc_vblank_on() and drm_crtc_vblank_off() can be 14238c2ecf20Sopenharmony_ci * unbalanced and so can also be unconditionally called in driver load code to 14248c2ecf20Sopenharmony_ci * reflect the current hardware state of the crtc. 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_civoid drm_crtc_vblank_on(struct drm_crtc *crtc) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 14298c2ecf20Sopenharmony_ci unsigned int pipe = drm_crtc_index(crtc); 14308c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 14338c2ecf20Sopenharmony_ci return; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci spin_lock_irq(&dev->vbl_lock); 14368c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n", 14378c2ecf20Sopenharmony_ci pipe, vblank->enabled, vblank->inmodeset); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Drop our private "prevent drm_vblank_get" refcount */ 14408c2ecf20Sopenharmony_ci if (vblank->inmodeset) { 14418c2ecf20Sopenharmony_ci atomic_dec(&vblank->refcount); 14428c2ecf20Sopenharmony_ci vblank->inmodeset = 0; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci drm_reset_vblank_timestamp(dev, pipe); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* 14488c2ecf20Sopenharmony_ci * re-enable interrupts if there are users left, or the 14498c2ecf20Sopenharmony_ci * user wishes vblank interrupts to be enabled all the time. 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_ci if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0) 14528c2ecf20Sopenharmony_ci drm_WARN_ON(dev, drm_vblank_enable(dev, pipe)); 14538c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->vbl_lock); 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_on); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci/** 14588c2ecf20Sopenharmony_ci * drm_vblank_restore - estimate missed vblanks and update vblank count. 14598c2ecf20Sopenharmony_ci * @dev: DRM device 14608c2ecf20Sopenharmony_ci * @pipe: CRTC index 14618c2ecf20Sopenharmony_ci * 14628c2ecf20Sopenharmony_ci * Power manamement features can cause frame counter resets between vblank 14638c2ecf20Sopenharmony_ci * disable and enable. Drivers can use this function in their 14648c2ecf20Sopenharmony_ci * &drm_crtc_funcs.enable_vblank implementation to estimate missed vblanks since 14658c2ecf20Sopenharmony_ci * the last &drm_crtc_funcs.disable_vblank using timestamps and update the 14668c2ecf20Sopenharmony_ci * vblank counter. 14678c2ecf20Sopenharmony_ci * 14688c2ecf20Sopenharmony_ci * This function is the legacy version of drm_crtc_vblank_restore(). 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_civoid drm_vblank_restore(struct drm_device *dev, unsigned int pipe) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci ktime_t t_vblank; 14738c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank; 14748c2ecf20Sopenharmony_ci int framedur_ns; 14758c2ecf20Sopenharmony_ci u64 diff_ns; 14768c2ecf20Sopenharmony_ci u32 cur_vblank, diff = 1; 14778c2ecf20Sopenharmony_ci int count = DRM_TIMESTAMP_MAXRETRIES; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 14808c2ecf20Sopenharmony_ci return; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci assert_spin_locked(&dev->vbl_lock); 14838c2ecf20Sopenharmony_ci assert_spin_locked(&dev->vblank_time_lock); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci vblank = &dev->vblank[pipe]; 14868c2ecf20Sopenharmony_ci drm_WARN_ONCE(dev, 14878c2ecf20Sopenharmony_ci drm_debug_enabled(DRM_UT_VBL) && !vblank->framedur_ns, 14888c2ecf20Sopenharmony_ci "Cannot compute missed vblanks without frame duration\n"); 14898c2ecf20Sopenharmony_ci framedur_ns = vblank->framedur_ns; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci do { 14928c2ecf20Sopenharmony_ci cur_vblank = __get_vblank_counter(dev, pipe); 14938c2ecf20Sopenharmony_ci drm_get_last_vbltimestamp(dev, pipe, &t_vblank, false); 14948c2ecf20Sopenharmony_ci } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time)); 14978c2ecf20Sopenharmony_ci if (framedur_ns) 14988c2ecf20Sopenharmony_ci diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci drm_dbg_vbl(dev, 15028c2ecf20Sopenharmony_ci "missed %d vblanks in %lld ns, frame duration=%d ns, hw_diff=%d\n", 15038c2ecf20Sopenharmony_ci diff, diff_ns, framedur_ns, cur_vblank - vblank->last); 15048c2ecf20Sopenharmony_ci store_vblank(dev, pipe, diff, t_vblank, cur_vblank); 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_vblank_restore); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci/** 15098c2ecf20Sopenharmony_ci * drm_crtc_vblank_restore - estimate missed vblanks and update vblank count. 15108c2ecf20Sopenharmony_ci * @crtc: CRTC in question 15118c2ecf20Sopenharmony_ci * 15128c2ecf20Sopenharmony_ci * Power manamement features can cause frame counter resets between vblank 15138c2ecf20Sopenharmony_ci * disable and enable. Drivers can use this function in their 15148c2ecf20Sopenharmony_ci * &drm_crtc_funcs.enable_vblank implementation to estimate missed vblanks since 15158c2ecf20Sopenharmony_ci * the last &drm_crtc_funcs.disable_vblank using timestamps and update the 15168c2ecf20Sopenharmony_ci * vblank counter. 15178c2ecf20Sopenharmony_ci */ 15188c2ecf20Sopenharmony_civoid drm_crtc_vblank_restore(struct drm_crtc *crtc) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci drm_vblank_restore(crtc->dev, drm_crtc_index(crtc)); 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_vblank_restore); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic void drm_legacy_vblank_pre_modeset(struct drm_device *dev, 15258c2ecf20Sopenharmony_ci unsigned int pipe) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* vblank is not initialized (IRQ not installed ?), or has been freed */ 15308c2ecf20Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 15318c2ecf20Sopenharmony_ci return; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 15348c2ecf20Sopenharmony_ci return; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* 15378c2ecf20Sopenharmony_ci * To avoid all the problems that might happen if interrupts 15388c2ecf20Sopenharmony_ci * were enabled/disabled around or between these calls, we just 15398c2ecf20Sopenharmony_ci * have the kernel take a reference on the CRTC (just once though 15408c2ecf20Sopenharmony_ci * to avoid corrupting the count if multiple, mismatch calls occur), 15418c2ecf20Sopenharmony_ci * so that interrupts remain enabled in the interim. 15428c2ecf20Sopenharmony_ci */ 15438c2ecf20Sopenharmony_ci if (!vblank->inmodeset) { 15448c2ecf20Sopenharmony_ci vblank->inmodeset = 0x1; 15458c2ecf20Sopenharmony_ci if (drm_vblank_get(dev, pipe) == 0) 15468c2ecf20Sopenharmony_ci vblank->inmodeset |= 0x2; 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci} 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_cistatic void drm_legacy_vblank_post_modeset(struct drm_device *dev, 15518c2ecf20Sopenharmony_ci unsigned int pipe) 15528c2ecf20Sopenharmony_ci{ 15538c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* vblank is not initialized (IRQ not installed ?), or has been freed */ 15568c2ecf20Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 15578c2ecf20Sopenharmony_ci return; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 15608c2ecf20Sopenharmony_ci return; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (vblank->inmodeset) { 15638c2ecf20Sopenharmony_ci spin_lock_irq(&dev->vbl_lock); 15648c2ecf20Sopenharmony_ci drm_reset_vblank_timestamp(dev, pipe); 15658c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->vbl_lock); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (vblank->inmodeset & 0x2) 15688c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci vblank->inmodeset = 0; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci} 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ciint drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, 15758c2ecf20Sopenharmony_ci struct drm_file *file_priv) 15768c2ecf20Sopenharmony_ci{ 15778c2ecf20Sopenharmony_ci struct drm_modeset_ctl *modeset = data; 15788c2ecf20Sopenharmony_ci unsigned int pipe; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* If drm_vblank_init() hasn't been called yet, just no-op */ 15818c2ecf20Sopenharmony_ci if (!drm_dev_has_vblank(dev)) 15828c2ecf20Sopenharmony_ci return 0; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* KMS drivers handle this internally */ 15858c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_LEGACY)) 15868c2ecf20Sopenharmony_ci return 0; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci pipe = modeset->crtc; 15898c2ecf20Sopenharmony_ci if (pipe >= dev->num_crtcs) 15908c2ecf20Sopenharmony_ci return -EINVAL; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci switch (modeset->cmd) { 15938c2ecf20Sopenharmony_ci case _DRM_PRE_MODESET: 15948c2ecf20Sopenharmony_ci drm_legacy_vblank_pre_modeset(dev, pipe); 15958c2ecf20Sopenharmony_ci break; 15968c2ecf20Sopenharmony_ci case _DRM_POST_MODESET: 15978c2ecf20Sopenharmony_ci drm_legacy_vblank_post_modeset(dev, pipe); 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci default: 16008c2ecf20Sopenharmony_ci return -EINVAL; 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci return 0; 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_cistatic int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, 16078c2ecf20Sopenharmony_ci u64 req_seq, 16088c2ecf20Sopenharmony_ci union drm_wait_vblank *vblwait, 16098c2ecf20Sopenharmony_ci struct drm_file *file_priv) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 16128c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e; 16138c2ecf20Sopenharmony_ci ktime_t now; 16148c2ecf20Sopenharmony_ci u64 seq; 16158c2ecf20Sopenharmony_ci int ret; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci e = kzalloc(sizeof(*e), GFP_KERNEL); 16188c2ecf20Sopenharmony_ci if (e == NULL) { 16198c2ecf20Sopenharmony_ci ret = -ENOMEM; 16208c2ecf20Sopenharmony_ci goto err_put; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci e->pipe = pipe; 16248c2ecf20Sopenharmony_ci e->event.base.type = DRM_EVENT_VBLANK; 16258c2ecf20Sopenharmony_ci e->event.base.length = sizeof(e->event.vbl); 16268c2ecf20Sopenharmony_ci e->event.vbl.user_data = vblwait->request.signal; 16278c2ecf20Sopenharmony_ci e->event.vbl.crtc_id = 0; 16288c2ecf20Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 16298c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (crtc) 16328c2ecf20Sopenharmony_ci e->event.vbl.crtc_id = crtc->base.id; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci spin_lock_irq(&dev->event_lock); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* 16388c2ecf20Sopenharmony_ci * drm_crtc_vblank_off() might have been called after we called 16398c2ecf20Sopenharmony_ci * drm_vblank_get(). drm_crtc_vblank_off() holds event_lock around the 16408c2ecf20Sopenharmony_ci * vblank disable, so no need for further locking. The reference from 16418c2ecf20Sopenharmony_ci * drm_vblank_get() protects against vblank disable from another source. 16428c2ecf20Sopenharmony_ci */ 16438c2ecf20Sopenharmony_ci if (!READ_ONCE(vblank->enabled)) { 16448c2ecf20Sopenharmony_ci ret = -EINVAL; 16458c2ecf20Sopenharmony_ci goto err_unlock; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci ret = drm_event_reserve_init_locked(dev, file_priv, &e->base, 16498c2ecf20Sopenharmony_ci &e->event.base); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (ret) 16528c2ecf20Sopenharmony_ci goto err_unlock; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci drm_dbg_core(dev, "event on vblank count %llu, current %llu, crtc %u\n", 16578c2ecf20Sopenharmony_ci req_seq, seq, pipe); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci trace_drm_vblank_event_queued(file_priv, pipe, req_seq); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci e->sequence = req_seq; 16628c2ecf20Sopenharmony_ci if (drm_vblank_passed(seq, req_seq)) { 16638c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 16648c2ecf20Sopenharmony_ci send_vblank_event(dev, e, seq, now); 16658c2ecf20Sopenharmony_ci vblwait->reply.sequence = seq; 16668c2ecf20Sopenharmony_ci } else { 16678c2ecf20Sopenharmony_ci /* drm_handle_vblank_events will call drm_vblank_put */ 16688c2ecf20Sopenharmony_ci list_add_tail(&e->base.link, &dev->vblank_event_list); 16698c2ecf20Sopenharmony_ci vblwait->reply.sequence = req_seq; 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci return 0; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cierr_unlock: 16778c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 16788c2ecf20Sopenharmony_ci kfree(e); 16798c2ecf20Sopenharmony_cierr_put: 16808c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 16818c2ecf20Sopenharmony_ci return ret; 16828c2ecf20Sopenharmony_ci} 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait) 16858c2ecf20Sopenharmony_ci{ 16868c2ecf20Sopenharmony_ci if (vblwait->request.sequence) 16878c2ecf20Sopenharmony_ci return false; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci return _DRM_VBLANK_RELATIVE == 16908c2ecf20Sopenharmony_ci (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK | 16918c2ecf20Sopenharmony_ci _DRM_VBLANK_EVENT | 16928c2ecf20Sopenharmony_ci _DRM_VBLANK_NEXTONMISS)); 16938c2ecf20Sopenharmony_ci} 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci/* 16968c2ecf20Sopenharmony_ci * Widen a 32-bit param to 64-bits. 16978c2ecf20Sopenharmony_ci * 16988c2ecf20Sopenharmony_ci * \param narrow 32-bit value (missing upper 32 bits) 16998c2ecf20Sopenharmony_ci * \param near 64-bit value that should be 'close' to near 17008c2ecf20Sopenharmony_ci * 17018c2ecf20Sopenharmony_ci * This function returns a 64-bit value using the lower 32-bits from 17028c2ecf20Sopenharmony_ci * 'narrow' and constructing the upper 32-bits so that the result is 17038c2ecf20Sopenharmony_ci * as close as possible to 'near'. 17048c2ecf20Sopenharmony_ci */ 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_cistatic u64 widen_32_to_64(u32 narrow, u64 near) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci return near + (s32) (narrow - near); 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe, 17128c2ecf20Sopenharmony_ci struct drm_wait_vblank_reply *reply) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci ktime_t now; 17158c2ecf20Sopenharmony_ci struct timespec64 ts; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci /* 17188c2ecf20Sopenharmony_ci * drm_wait_vblank_reply is a UAPI structure that uses 'long' 17198c2ecf20Sopenharmony_ci * to store the seconds. This is safe as we always use monotonic 17208c2ecf20Sopenharmony_ci * timestamps since linux-4.15. 17218c2ecf20Sopenharmony_ci */ 17228c2ecf20Sopenharmony_ci reply->sequence = drm_vblank_count_and_time(dev, pipe, &now); 17238c2ecf20Sopenharmony_ci ts = ktime_to_timespec64(now); 17248c2ecf20Sopenharmony_ci reply->tval_sec = (u32)ts.tv_sec; 17258c2ecf20Sopenharmony_ci reply->tval_usec = ts.tv_nsec / 1000; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ciint drm_wait_vblank_ioctl(struct drm_device *dev, void *data, 17298c2ecf20Sopenharmony_ci struct drm_file *file_priv) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 17328c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank; 17338c2ecf20Sopenharmony_ci union drm_wait_vblank *vblwait = data; 17348c2ecf20Sopenharmony_ci int ret; 17358c2ecf20Sopenharmony_ci u64 req_seq, seq; 17368c2ecf20Sopenharmony_ci unsigned int pipe_index; 17378c2ecf20Sopenharmony_ci unsigned int flags, pipe, high_pipe; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if (!dev->irq_enabled) 17408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci if (vblwait->request.type & _DRM_VBLANK_SIGNAL) 17438c2ecf20Sopenharmony_ci return -EINVAL; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (vblwait->request.type & 17468c2ecf20Sopenharmony_ci ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 17478c2ecf20Sopenharmony_ci _DRM_VBLANK_HIGH_CRTC_MASK)) { 17488c2ecf20Sopenharmony_ci drm_dbg_core(dev, 17498c2ecf20Sopenharmony_ci "Unsupported type value 0x%x, supported mask 0x%x\n", 17508c2ecf20Sopenharmony_ci vblwait->request.type, 17518c2ecf20Sopenharmony_ci (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 17528c2ecf20Sopenharmony_ci _DRM_VBLANK_HIGH_CRTC_MASK)); 17538c2ecf20Sopenharmony_ci return -EINVAL; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 17578c2ecf20Sopenharmony_ci high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); 17588c2ecf20Sopenharmony_ci if (high_pipe) 17598c2ecf20Sopenharmony_ci pipe_index = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT; 17608c2ecf20Sopenharmony_ci else 17618c2ecf20Sopenharmony_ci pipe_index = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci /* Convert lease-relative crtc index into global crtc index */ 17648c2ecf20Sopenharmony_ci if (drm_core_check_feature(dev, DRIVER_MODESET)) { 17658c2ecf20Sopenharmony_ci pipe = 0; 17668c2ecf20Sopenharmony_ci drm_for_each_crtc(crtc, dev) { 17678c2ecf20Sopenharmony_ci if (drm_lease_held(file_priv, crtc->base.id)) { 17688c2ecf20Sopenharmony_ci if (pipe_index == 0) 17698c2ecf20Sopenharmony_ci break; 17708c2ecf20Sopenharmony_ci pipe_index--; 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci pipe++; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci } else { 17758c2ecf20Sopenharmony_ci pipe = pipe_index; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci if (pipe >= dev->num_crtcs) 17798c2ecf20Sopenharmony_ci return -EINVAL; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci vblank = &dev->vblank[pipe]; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci /* If the counter is currently enabled and accurate, short-circuit 17848c2ecf20Sopenharmony_ci * queries to return the cached timestamp of the last vblank. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci if (dev->vblank_disable_immediate && 17878c2ecf20Sopenharmony_ci drm_wait_vblank_is_query(vblwait) && 17888c2ecf20Sopenharmony_ci READ_ONCE(vblank->enabled)) { 17898c2ecf20Sopenharmony_ci drm_wait_vblank_reply(dev, pipe, &vblwait->reply); 17908c2ecf20Sopenharmony_ci return 0; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci ret = drm_vblank_get(dev, pipe); 17948c2ecf20Sopenharmony_ci if (ret) { 17958c2ecf20Sopenharmony_ci drm_dbg_core(dev, 17968c2ecf20Sopenharmony_ci "crtc %d failed to acquire vblank counter, %d\n", 17978c2ecf20Sopenharmony_ci pipe, ret); 17988c2ecf20Sopenharmony_ci return ret; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci seq = drm_vblank_count(dev, pipe); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 18038c2ecf20Sopenharmony_ci case _DRM_VBLANK_RELATIVE: 18048c2ecf20Sopenharmony_ci req_seq = seq + vblwait->request.sequence; 18058c2ecf20Sopenharmony_ci vblwait->request.sequence = req_seq; 18068c2ecf20Sopenharmony_ci vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 18078c2ecf20Sopenharmony_ci break; 18088c2ecf20Sopenharmony_ci case _DRM_VBLANK_ABSOLUTE: 18098c2ecf20Sopenharmony_ci req_seq = widen_32_to_64(vblwait->request.sequence, seq); 18108c2ecf20Sopenharmony_ci break; 18118c2ecf20Sopenharmony_ci default: 18128c2ecf20Sopenharmony_ci ret = -EINVAL; 18138c2ecf20Sopenharmony_ci goto done; 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if ((flags & _DRM_VBLANK_NEXTONMISS) && 18178c2ecf20Sopenharmony_ci drm_vblank_passed(seq, req_seq)) { 18188c2ecf20Sopenharmony_ci req_seq = seq + 1; 18198c2ecf20Sopenharmony_ci vblwait->request.type &= ~_DRM_VBLANK_NEXTONMISS; 18208c2ecf20Sopenharmony_ci vblwait->request.sequence = req_seq; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (flags & _DRM_VBLANK_EVENT) { 18248c2ecf20Sopenharmony_ci /* must hold on to the vblank ref until the event fires 18258c2ecf20Sopenharmony_ci * drm_vblank_put will be called asynchronously 18268c2ecf20Sopenharmony_ci */ 18278c2ecf20Sopenharmony_ci return drm_queue_vblank_event(dev, pipe, req_seq, vblwait, file_priv); 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (req_seq != seq) { 18318c2ecf20Sopenharmony_ci int wait; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci drm_dbg_core(dev, "waiting on vblank count %llu, crtc %u\n", 18348c2ecf20Sopenharmony_ci req_seq, pipe); 18358c2ecf20Sopenharmony_ci wait = wait_event_interruptible_timeout(vblank->queue, 18368c2ecf20Sopenharmony_ci drm_vblank_passed(drm_vblank_count(dev, pipe), req_seq) || 18378c2ecf20Sopenharmony_ci !READ_ONCE(vblank->enabled), 18388c2ecf20Sopenharmony_ci msecs_to_jiffies(3000)); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci switch (wait) { 18418c2ecf20Sopenharmony_ci case 0: 18428c2ecf20Sopenharmony_ci /* timeout */ 18438c2ecf20Sopenharmony_ci ret = -EBUSY; 18448c2ecf20Sopenharmony_ci break; 18458c2ecf20Sopenharmony_ci case -ERESTARTSYS: 18468c2ecf20Sopenharmony_ci /* interrupted by signal */ 18478c2ecf20Sopenharmony_ci ret = -EINTR; 18488c2ecf20Sopenharmony_ci break; 18498c2ecf20Sopenharmony_ci default: 18508c2ecf20Sopenharmony_ci ret = 0; 18518c2ecf20Sopenharmony_ci break; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci if (ret != -EINTR) { 18568c2ecf20Sopenharmony_ci drm_wait_vblank_reply(dev, pipe, &vblwait->reply); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci drm_dbg_core(dev, "crtc %d returning %u to client\n", 18598c2ecf20Sopenharmony_ci pipe, vblwait->reply.sequence); 18608c2ecf20Sopenharmony_ci } else { 18618c2ecf20Sopenharmony_ci drm_dbg_core(dev, "crtc %d vblank wait interrupted by signal\n", 18628c2ecf20Sopenharmony_ci pipe); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_cidone: 18668c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 18678c2ecf20Sopenharmony_ci return ret; 18688c2ecf20Sopenharmony_ci} 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 18738c2ecf20Sopenharmony_ci bool high_prec = false; 18748c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e, *t; 18758c2ecf20Sopenharmony_ci ktime_t now; 18768c2ecf20Sopenharmony_ci u64 seq; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci assert_spin_locked(&dev->event_lock); 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 18838c2ecf20Sopenharmony_ci if (e->pipe != pipe) 18848c2ecf20Sopenharmony_ci continue; 18858c2ecf20Sopenharmony_ci if (!drm_vblank_passed(seq, e->sequence)) 18868c2ecf20Sopenharmony_ci continue; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci drm_dbg_core(dev, "vblank event on %llu, current %llu\n", 18898c2ecf20Sopenharmony_ci e->sequence, seq); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci list_del(&e->base.link); 18928c2ecf20Sopenharmony_ci drm_vblank_put(dev, pipe); 18938c2ecf20Sopenharmony_ci send_vblank_event(dev, e, seq, now); 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci if (crtc && crtc->funcs->get_vblank_timestamp) 18978c2ecf20Sopenharmony_ci high_prec = true; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci trace_drm_vblank_event(pipe, seq, now, high_prec); 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci/** 19038c2ecf20Sopenharmony_ci * drm_handle_vblank - handle a vblank event 19048c2ecf20Sopenharmony_ci * @dev: DRM device 19058c2ecf20Sopenharmony_ci * @pipe: index of CRTC where this event occurred 19068c2ecf20Sopenharmony_ci * 19078c2ecf20Sopenharmony_ci * Drivers should call this routine in their vblank interrupt handlers to 19088c2ecf20Sopenharmony_ci * update the vblank counter and send any signals that may be pending. 19098c2ecf20Sopenharmony_ci * 19108c2ecf20Sopenharmony_ci * This is the legacy version of drm_crtc_handle_vblank(). 19118c2ecf20Sopenharmony_ci */ 19128c2ecf20Sopenharmony_cibool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 19158c2ecf20Sopenharmony_ci unsigned long irqflags; 19168c2ecf20Sopenharmony_ci bool disable_irq; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (drm_WARN_ON_ONCE(dev, !drm_dev_has_vblank(dev))) 19198c2ecf20Sopenharmony_ci return false; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) 19228c2ecf20Sopenharmony_ci return false; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->event_lock, irqflags); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci /* Need timestamp lock to prevent concurrent execution with 19278c2ecf20Sopenharmony_ci * vblank enable/disable, as this would cause inconsistent 19288c2ecf20Sopenharmony_ci * or corrupted timestamps and vblank counts. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci spin_lock(&dev->vblank_time_lock); 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* Vblank irq handling disabled. Nothing to do. */ 19338c2ecf20Sopenharmony_ci if (!vblank->enabled) { 19348c2ecf20Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 19358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->event_lock, irqflags); 19368c2ecf20Sopenharmony_ci return false; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci drm_update_vblank_count(dev, pipe, true); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci spin_unlock(&dev->vblank_time_lock); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci wake_up(&vblank->queue); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* With instant-off, we defer disabling the interrupt until after 19468c2ecf20Sopenharmony_ci * we finish processing the following vblank after all events have 19478c2ecf20Sopenharmony_ci * been signaled. The disable has to be last (after 19488c2ecf20Sopenharmony_ci * drm_handle_vblank_events) so that the timestamp is always accurate. 19498c2ecf20Sopenharmony_ci */ 19508c2ecf20Sopenharmony_ci disable_irq = (dev->vblank_disable_immediate && 19518c2ecf20Sopenharmony_ci drm_vblank_offdelay > 0 && 19528c2ecf20Sopenharmony_ci !atomic_read(&vblank->refcount)); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci drm_handle_vblank_events(dev, pipe); 19558c2ecf20Sopenharmony_ci drm_handle_vblank_works(vblank); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->event_lock, irqflags); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci if (disable_irq) 19608c2ecf20Sopenharmony_ci vblank_disable_fn(&vblank->disable_timer); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci return true; 19638c2ecf20Sopenharmony_ci} 19648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_handle_vblank); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci/** 19678c2ecf20Sopenharmony_ci * drm_crtc_handle_vblank - handle a vblank event 19688c2ecf20Sopenharmony_ci * @crtc: where this event occurred 19698c2ecf20Sopenharmony_ci * 19708c2ecf20Sopenharmony_ci * Drivers should call this routine in their vblank interrupt handlers to 19718c2ecf20Sopenharmony_ci * update the vblank counter and send any signals that may be pending. 19728c2ecf20Sopenharmony_ci * 19738c2ecf20Sopenharmony_ci * This is the native KMS version of drm_handle_vblank(). 19748c2ecf20Sopenharmony_ci * 19758c2ecf20Sopenharmony_ci * Note that for a given vblank counter value drm_crtc_handle_vblank() 19768c2ecf20Sopenharmony_ci * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() 19778c2ecf20Sopenharmony_ci * provide a barrier: Any writes done before calling 19788c2ecf20Sopenharmony_ci * drm_crtc_handle_vblank() will be visible to callers of the later 19798c2ecf20Sopenharmony_ci * functions, iff the vblank count is the same or a later one. 19808c2ecf20Sopenharmony_ci * 19818c2ecf20Sopenharmony_ci * See also &drm_vblank_crtc.count. 19828c2ecf20Sopenharmony_ci * 19838c2ecf20Sopenharmony_ci * Returns: 19848c2ecf20Sopenharmony_ci * True if the event was successfully handled, false on failure. 19858c2ecf20Sopenharmony_ci */ 19868c2ecf20Sopenharmony_cibool drm_crtc_handle_vblank(struct drm_crtc *crtc) 19878c2ecf20Sopenharmony_ci{ 19888c2ecf20Sopenharmony_ci return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_crtc_handle_vblank); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci/* 19938c2ecf20Sopenharmony_ci * Get crtc VBLANK count. 19948c2ecf20Sopenharmony_ci * 19958c2ecf20Sopenharmony_ci * \param dev DRM device 19968c2ecf20Sopenharmony_ci * \param data user arguement, pointing to a drm_crtc_get_sequence structure. 19978c2ecf20Sopenharmony_ci * \param file_priv drm file private for the user's open file descriptor 19988c2ecf20Sopenharmony_ci */ 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ciint drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, 20018c2ecf20Sopenharmony_ci struct drm_file *file_priv) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 20048c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank; 20058c2ecf20Sopenharmony_ci int pipe; 20068c2ecf20Sopenharmony_ci struct drm_crtc_get_sequence *get_seq = data; 20078c2ecf20Sopenharmony_ci ktime_t now; 20088c2ecf20Sopenharmony_ci bool vblank_enabled; 20098c2ecf20Sopenharmony_ci int ret; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 20128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (!dev->irq_enabled) 20158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id); 20188c2ecf20Sopenharmony_ci if (!crtc) 20198c2ecf20Sopenharmony_ci return -ENOENT; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci pipe = drm_crtc_index(crtc); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci vblank = &dev->vblank[pipe]; 20248c2ecf20Sopenharmony_ci vblank_enabled = dev->vblank_disable_immediate && READ_ONCE(vblank->enabled); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (!vblank_enabled) { 20278c2ecf20Sopenharmony_ci ret = drm_crtc_vblank_get(crtc); 20288c2ecf20Sopenharmony_ci if (ret) { 20298c2ecf20Sopenharmony_ci drm_dbg_core(dev, 20308c2ecf20Sopenharmony_ci "crtc %d failed to acquire vblank counter, %d\n", 20318c2ecf20Sopenharmony_ci pipe, ret); 20328c2ecf20Sopenharmony_ci return ret; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci drm_modeset_lock(&crtc->mutex, NULL); 20368c2ecf20Sopenharmony_ci if (crtc->state) 20378c2ecf20Sopenharmony_ci get_seq->active = crtc->state->enable; 20388c2ecf20Sopenharmony_ci else 20398c2ecf20Sopenharmony_ci get_seq->active = crtc->enabled; 20408c2ecf20Sopenharmony_ci drm_modeset_unlock(&crtc->mutex); 20418c2ecf20Sopenharmony_ci get_seq->sequence = drm_vblank_count_and_time(dev, pipe, &now); 20428c2ecf20Sopenharmony_ci get_seq->sequence_ns = ktime_to_ns(now); 20438c2ecf20Sopenharmony_ci if (!vblank_enabled) 20448c2ecf20Sopenharmony_ci drm_crtc_vblank_put(crtc); 20458c2ecf20Sopenharmony_ci return 0; 20468c2ecf20Sopenharmony_ci} 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci/* 20498c2ecf20Sopenharmony_ci * Queue a event for VBLANK sequence 20508c2ecf20Sopenharmony_ci * 20518c2ecf20Sopenharmony_ci * \param dev DRM device 20528c2ecf20Sopenharmony_ci * \param data user arguement, pointing to a drm_crtc_queue_sequence structure. 20538c2ecf20Sopenharmony_ci * \param file_priv drm file private for the user's open file descriptor 20548c2ecf20Sopenharmony_ci */ 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ciint drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, 20578c2ecf20Sopenharmony_ci struct drm_file *file_priv) 20588c2ecf20Sopenharmony_ci{ 20598c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 20608c2ecf20Sopenharmony_ci struct drm_vblank_crtc *vblank; 20618c2ecf20Sopenharmony_ci int pipe; 20628c2ecf20Sopenharmony_ci struct drm_crtc_queue_sequence *queue_seq = data; 20638c2ecf20Sopenharmony_ci ktime_t now; 20648c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *e; 20658c2ecf20Sopenharmony_ci u32 flags; 20668c2ecf20Sopenharmony_ci u64 seq; 20678c2ecf20Sopenharmony_ci u64 req_seq; 20688c2ecf20Sopenharmony_ci int ret; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 20718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (!dev->irq_enabled) 20748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id); 20778c2ecf20Sopenharmony_ci if (!crtc) 20788c2ecf20Sopenharmony_ci return -ENOENT; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci flags = queue_seq->flags; 20818c2ecf20Sopenharmony_ci /* Check valid flag bits */ 20828c2ecf20Sopenharmony_ci if (flags & ~(DRM_CRTC_SEQUENCE_RELATIVE| 20838c2ecf20Sopenharmony_ci DRM_CRTC_SEQUENCE_NEXT_ON_MISS)) 20848c2ecf20Sopenharmony_ci return -EINVAL; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci pipe = drm_crtc_index(crtc); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci vblank = &dev->vblank[pipe]; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci e = kzalloc(sizeof(*e), GFP_KERNEL); 20918c2ecf20Sopenharmony_ci if (e == NULL) 20928c2ecf20Sopenharmony_ci return -ENOMEM; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci ret = drm_crtc_vblank_get(crtc); 20958c2ecf20Sopenharmony_ci if (ret) { 20968c2ecf20Sopenharmony_ci drm_dbg_core(dev, 20978c2ecf20Sopenharmony_ci "crtc %d failed to acquire vblank counter, %d\n", 20988c2ecf20Sopenharmony_ci pipe, ret); 20998c2ecf20Sopenharmony_ci goto err_free; 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci seq = drm_vblank_count_and_time(dev, pipe, &now); 21038c2ecf20Sopenharmony_ci req_seq = queue_seq->sequence; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (flags & DRM_CRTC_SEQUENCE_RELATIVE) 21068c2ecf20Sopenharmony_ci req_seq += seq; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci if ((flags & DRM_CRTC_SEQUENCE_NEXT_ON_MISS) && drm_vblank_passed(seq, req_seq)) 21098c2ecf20Sopenharmony_ci req_seq = seq + 1; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci e->pipe = pipe; 21128c2ecf20Sopenharmony_ci e->event.base.type = DRM_EVENT_CRTC_SEQUENCE; 21138c2ecf20Sopenharmony_ci e->event.base.length = sizeof(e->event.seq); 21148c2ecf20Sopenharmony_ci e->event.seq.user_data = queue_seq->user_data; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci spin_lock_irq(&dev->event_lock); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci /* 21198c2ecf20Sopenharmony_ci * drm_crtc_vblank_off() might have been called after we called 21208c2ecf20Sopenharmony_ci * drm_crtc_vblank_get(). drm_crtc_vblank_off() holds event_lock around the 21218c2ecf20Sopenharmony_ci * vblank disable, so no need for further locking. The reference from 21228c2ecf20Sopenharmony_ci * drm_crtc_vblank_get() protects against vblank disable from another source. 21238c2ecf20Sopenharmony_ci */ 21248c2ecf20Sopenharmony_ci if (!READ_ONCE(vblank->enabled)) { 21258c2ecf20Sopenharmony_ci ret = -EINVAL; 21268c2ecf20Sopenharmony_ci goto err_unlock; 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci ret = drm_event_reserve_init_locked(dev, file_priv, &e->base, 21308c2ecf20Sopenharmony_ci &e->event.base); 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (ret) 21338c2ecf20Sopenharmony_ci goto err_unlock; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci e->sequence = req_seq; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (drm_vblank_passed(seq, req_seq)) { 21388c2ecf20Sopenharmony_ci drm_crtc_vblank_put(crtc); 21398c2ecf20Sopenharmony_ci send_vblank_event(dev, e, seq, now); 21408c2ecf20Sopenharmony_ci queue_seq->sequence = seq; 21418c2ecf20Sopenharmony_ci } else { 21428c2ecf20Sopenharmony_ci /* drm_handle_vblank_events will call drm_vblank_put */ 21438c2ecf20Sopenharmony_ci list_add_tail(&e->base.link, &dev->vblank_event_list); 21448c2ecf20Sopenharmony_ci queue_seq->sequence = req_seq; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 21488c2ecf20Sopenharmony_ci return 0; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_cierr_unlock: 21518c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 21528c2ecf20Sopenharmony_ci drm_crtc_vblank_put(crtc); 21538c2ecf20Sopenharmony_cierr_free: 21548c2ecf20Sopenharmony_ci kfree(e); 21558c2ecf20Sopenharmony_ci return ret; 21568c2ecf20Sopenharmony_ci} 21578c2ecf20Sopenharmony_ci 2158