summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_vblank_helper.c
blob: a04a6ba1b0ca055d1186f496b3dcd16e68c47287 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// SPDX-License-Identifier: MIT

#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_vblank_helper.h>

/**
 * DOC: overview
 *
 * The vblank helper library provides functions for supporting vertical
 * blanking in DRM drivers.
 *
 * For vblank timers, several callback implementations are available.
 * Drivers enable support for vblank timers by setting the vblank callbacks
 * in struct &drm_crtc_funcs to the helpers provided by this library. The
 * initializer macro DRM_CRTC_VBLANK_TIMER_FUNCS does this conveniently.
 * The driver further has to send the VBLANK event from its atomic_flush
 * callback and control vblank from the CRTC's atomic_enable and atomic_disable
 * callbacks. The callbacks are located in struct &drm_crtc_helper_funcs.
 * The vblank helper library provides implementations of these callbacks
 * for drivers without further requirements. The initializer macro
 * DRM_CRTC_HELPER_VBLANK_FUNCS sets them coveniently.
 *
 * Once the driver enables vblank support with drm_vblank_init(), each
 * CRTC's vblank timer fires according to the programmed display mode. By
 * default, the vblank timer invokes drm_crtc_handle_vblank(). Drivers with
 * more specific requirements can set their own handler function in
 * struct &drm_crtc_helper_funcs.handle_vblank_timeout.
 */

/*
 * VBLANK helpers
 */

/**
 * drm_crtc_vblank_atomic_flush -
 *	Implements struct &drm_crtc_helper_funcs.atomic_flush
 * @crtc: The CRTC
 * @state: The atomic state to apply
 *
 * The helper drm_crtc_vblank_atomic_flush() implements atomic_flush of
 * struct drm_crtc_helper_funcs for CRTCs that only need to send out a
 * VBLANK event.
 *
 * See also struct &drm_crtc_helper_funcs.atomic_flush.
 */
void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc,
				  struct drm_atomic_state *state)
{
	struct drm_device *dev = crtc->dev;
	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
	struct drm_pending_vblank_event *event;

	spin_lock_irq(&dev->event_lock);

	event = crtc_state->event;
	crtc_state->event = NULL;

	if (event) {
		if (drm_crtc_vblank_get(crtc) == 0)
			drm_crtc_arm_vblank_event(crtc, event);
		else
			drm_crtc_send_vblank_event(crtc, event);
	}

	spin_unlock_irq(&dev->event_lock);
}
EXPORT_SYMBOL(drm_crtc_vblank_atomic_flush);

/**
 * drm_crtc_vblank_atomic_enable - Implements struct &drm_crtc_helper_funcs.atomic_enable
 * @crtc: The CRTC
 * @state: The atomic state
 *
 * The helper drm_crtc_vblank_atomic_enable() implements atomic_enable
 * of struct drm_crtc_helper_funcs for CRTCs the only need to enable VBLANKs.
 *
 * See also struct &drm_crtc_helper_funcs.atomic_enable.
 */
void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc,
				   struct drm_atomic_state *state)
{
	drm_crtc_vblank_on(crtc);
}
EXPORT_SYMBOL(drm_crtc_vblank_atomic_enable);

/**
 * drm_crtc_vblank_atomic_disable - Implements struct &drm_crtc_helper_funcs.atomic_disable
 * @crtc: The CRTC
 * @state: The atomic state
 *
 * The helper drm_crtc_vblank_atomic_disable() implements atomic_disable
 * of struct drm_crtc_helper_funcs for CRTCs the only need to disable VBLANKs.
 *
 * See also struct &drm_crtc_funcs.atomic_disable.
 */
void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc,
				    struct drm_atomic_state *state)
{
	drm_crtc_vblank_off(crtc);
}
EXPORT_SYMBOL(drm_crtc_vblank_atomic_disable);

/*
 * VBLANK timer
 */

/**
 * drm_crtc_vblank_helper_enable_vblank_timer - Implements struct &drm_crtc_funcs.enable_vblank
 * @crtc: The CRTC
 *
 * The helper drm_crtc_vblank_helper_enable_vblank_timer() implements
 * enable_vblank of struct drm_crtc_helper_funcs for CRTCs that require
 * a VBLANK timer. It sets up the timer on the first invocation. The
 * started timer expires after the current frame duration. See struct
 * &drm_vblank_crtc.framedur_ns.
 *
 * See also struct &drm_crtc_helper_funcs.enable_vblank.
 *
 * Returns:
 * 0 on success, or a negative errno code otherwise.
 */
int drm_crtc_vblank_helper_enable_vblank_timer(struct drm_crtc *crtc)
{
	return drm_crtc_vblank_start_timer(crtc);
}
EXPORT_SYMBOL(drm_crtc_vblank_helper_enable_vblank_timer);

/**
 * drm_crtc_vblank_helper_disable_vblank_timer - Implements struct &drm_crtc_funcs.disable_vblank
 * @crtc: The CRTC
 *
 * The helper drm_crtc_vblank_helper_disable_vblank_timer() implements
 * disable_vblank of struct drm_crtc_funcs for CRTCs that require a
 * VBLANK timer.
 *
 * See also struct &drm_crtc_helper_funcs.disable_vblank.
 */
void drm_crtc_vblank_helper_disable_vblank_timer(struct drm_crtc *crtc)
{
	drm_crtc_vblank_cancel_timer(crtc);
}
EXPORT_SYMBOL(drm_crtc_vblank_helper_disable_vblank_timer);

/**
 * drm_crtc_vblank_helper_get_vblank_timestamp_from_timer -
 *	Implements struct &drm_crtc_funcs.get_vblank_timestamp
 * @crtc: The CRTC
 * @max_error: Maximum acceptable error
 * @vblank_time: Returns the next vblank timestamp
 * @in_vblank_irq: True is called from drm_crtc_handle_vblank()
 *
 * The helper drm_crtc_helper_get_vblank_timestamp_from_timer() implements
 * get_vblank_timestamp of struct drm_crtc_funcs for CRTCs that require a
 * VBLANK timer. It returns the timestamp according to the timer's expiry
 * time.
 *
 * See also struct &drm_crtc_funcs.get_vblank_timestamp.
 *
 * Returns:
 * True on success, or false otherwise.
 */
bool drm_crtc_vblank_helper_get_vblank_timestamp_from_timer(struct drm_crtc *crtc,
							    int *max_error,
							    ktime_t *vblank_time,
							    bool in_vblank_irq)
{
	drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time);

	return true;
}
EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_from_timer);