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