Rev 5060 | Rev 6084 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5060 | serge | 1 | /* |
2 | * drm_irq.c IRQ and vblank support |
||
1963 | serge | 3 | * |
4 | * \author Rickard E. (Rik) Faith |
||
5 | * \author Gareth Hughes |
||
6 | */ |
||
7 | |||
8 | /* |
||
9 | * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com |
||
10 | * |
||
11 | * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. |
||
12 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. |
||
13 | * All Rights Reserved. |
||
14 | * |
||
15 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
16 | * copy of this software and associated documentation files (the "Software"), |
||
17 | * to deal in the Software without restriction, including without limitation |
||
18 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
19 | * and/or sell copies of the Software, and to permit persons to whom the |
||
20 | * Software is furnished to do so, subject to the following conditions: |
||
21 | * |
||
22 | * The above copyright notice and this permission notice (including the next |
||
23 | * paragraph) shall be included in all copies or substantial portions of the |
||
24 | * Software. |
||
25 | * |
||
26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
29 | * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
30 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
31 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
32 | * OTHER DEALINGS IN THE SOFTWARE. |
||
33 | */ |
||
34 | |||
3031 | serge | 35 | #include |
1963 | serge | 36 | //#include "drm_trace.h" |
5271 | serge | 37 | #include "drm_internal.h" |
1963 | serge | 38 | |
39 | //#include |
||
40 | #include |
||
41 | |||
5271 | serge | 42 | #include |
3031 | serge | 43 | #include |
1963 | serge | 44 | |
45 | /* Access macro for slots in vblank timestamp ringbuffer. */ |
||
4560 | Serge | 46 | #define vblanktimestamp(dev, crtc, count) \ |
47 | ((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE]) |
||
1963 | serge | 48 | |
49 | /* Retry timestamp calculation up to 3 times to satisfy |
||
50 | * drm_timestamp_precision before giving up. |
||
51 | */ |
||
52 | #define DRM_TIMESTAMP_MAXRETRIES 3 |
||
53 | |||
54 | /* Threshold in nanoseconds for detection of redundant |
||
55 | * vblank irq in drm_handle_vblank(). 1 msec should be ok. |
||
56 | */ |
||
57 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 |
||
58 | |||
5271 | serge | 59 | static bool |
60 | drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, |
||
61 | struct timeval *tvblank, unsigned flags); |
||
62 | |||
63 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ |
||
64 | |||
5060 | serge | 65 | /* |
66 | * Clear vblank timestamp buffer for a crtc. |
||
67 | */ |
||
1963 | serge | 68 | |
5060 | serge | 69 | |
70 | #if 0 |
||
71 | /** |
||
72 | * drm_vblank_init - initialize vblank support |
||
73 | * @dev: drm_device |
||
74 | * @num_crtcs: number of crtcs supported by @dev |
||
75 | * |
||
76 | * This function initializes vblank support for @num_crtcs display pipelines. |
||
77 | * |
||
78 | * Returns: |
||
79 | * Zero on success or a negative error code on failure. |
||
80 | */ |
||
81 | int drm_vblank_init(struct drm_device *dev, int num_crtcs) |
||
82 | { |
||
83 | int i, ret = -ENOMEM; |
||
84 | |||
85 | spin_lock_init(&dev->vbl_lock); |
||
86 | spin_lock_init(&dev->vblank_time_lock); |
||
87 | |||
88 | dev->num_crtcs = num_crtcs; |
||
89 | |||
90 | dev->vblank = kcalloc(num_crtcs, sizeof(*dev->vblank), GFP_KERNEL); |
||
91 | if (!dev->vblank) |
||
92 | goto err; |
||
93 | |||
94 | for (i = 0; i < num_crtcs; i++) { |
||
5271 | serge | 95 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
96 | |||
97 | vblank->dev = dev; |
||
98 | vblank->crtc = i; |
||
99 | init_waitqueue_head(&vblank->queue); |
||
100 | setup_timer(&vblank->disable_timer, vblank_disable_fn, |
||
101 | (unsigned long)vblank); |
||
5060 | serge | 102 | } |
103 | |||
104 | DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); |
||
105 | |||
106 | /* Driver specific high-precision vblank timestamping supported? */ |
||
107 | if (dev->driver->get_vblank_timestamp) |
||
108 | DRM_INFO("Driver supports precise vblank timestamp query.\n"); |
||
109 | else |
||
110 | DRM_INFO("No driver support for vblank timestamp query.\n"); |
||
111 | |||
112 | dev->vblank_disable_allowed = false; |
||
113 | |||
114 | return 0; |
||
115 | |||
116 | err: |
||
5271 | serge | 117 | dev->num_crtcs = 0; |
5060 | serge | 118 | return ret; |
119 | } |
||
120 | EXPORT_SYMBOL(drm_vblank_init); |
||
121 | |||
122 | #endif |
||
123 | |||
4075 | Serge | 124 | irqreturn_t device_irq_handler(struct drm_device *dev) |
125 | { |
||
126 | |||
4104 | Serge | 127 | // printf("video irq\n"); |
4075 | Serge | 128 | |
129 | // printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ; |
||
130 | |||
131 | return dev->driver->irq_handler(0, dev); |
||
132 | } |
||
133 | |||
134 | /** |
||
5060 | serge | 135 | * drm_irq_install - install IRQ handler |
136 | * @dev: DRM device |
||
137 | * @irq: IRQ number to install the handler for |
||
4075 | Serge | 138 | * |
5060 | serge | 139 | * Initializes the IRQ related data. Installs the handler, calling the driver |
140 | * irq_preinstall() and irq_postinstall() functions before and after the |
||
141 | * installation. |
||
4075 | Serge | 142 | * |
5060 | serge | 143 | * This is the simplified helper interface provided for drivers with no special |
144 | * needs. Drivers which need to install interrupt handlers for multiple |
||
145 | * interrupts must instead set drm_device->irq_enabled to signal the DRM core |
||
146 | * that vblank interrupts are available. |
||
147 | * |
||
148 | * Returns: |
||
149 | * Zero on success or a negative error code on failure. |
||
4075 | Serge | 150 | */ |
5060 | serge | 151 | int drm_irq_install(struct drm_device *dev, int irq) |
4075 | Serge | 152 | { |
153 | int ret; |
||
154 | unsigned long sh_flags = 0; |
||
155 | |||
4293 | Serge | 156 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
157 | return -EINVAL; |
||
4075 | Serge | 158 | |
5060 | serge | 159 | if (irq == 0) |
4075 | Serge | 160 | return -EINVAL; |
161 | |||
162 | /* Driver must have been initialized */ |
||
5060 | serge | 163 | if (!dev->dev_private) |
4075 | Serge | 164 | return -EINVAL; |
165 | |||
5060 | serge | 166 | if (dev->irq_enabled) |
4075 | Serge | 167 | return -EBUSY; |
4560 | Serge | 168 | dev->irq_enabled = true; |
4075 | Serge | 169 | |
5060 | serge | 170 | DRM_DEBUG("irq=%d\n", irq); |
4075 | Serge | 171 | |
172 | /* Before installing handler */ |
||
173 | if (dev->driver->irq_preinstall) |
||
174 | dev->driver->irq_preinstall(dev); |
||
175 | |||
5060 | serge | 176 | ret = !AttachIntHandler(irq, device_irq_handler, (u32)dev); |
4075 | Serge | 177 | |
178 | /* After installing handler */ |
||
179 | if (dev->driver->irq_postinstall) |
||
180 | ret = dev->driver->irq_postinstall(dev); |
||
181 | |||
182 | if (ret < 0) { |
||
5060 | serge | 183 | dev->irq_enabled = false; |
4539 | Serge | 184 | DRM_ERROR(__FUNCTION__); |
5060 | serge | 185 | } else { |
186 | dev->irq = irq; |
||
4075 | Serge | 187 | } |
188 | |||
5271 | serge | 189 | u16 cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4); |
4075 | Serge | 190 | cmd&= ~(1<<10); |
191 | PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd); |
||
192 | |||
193 | return ret; |
||
194 | } |
||
195 | EXPORT_SYMBOL(drm_irq_install); |
||
196 | |||
197 | |||
1963 | serge | 198 | |
199 | |||
200 | u64 div64_u64(u64 dividend, u64 divisor) |
||
201 | { |
||
202 | u32 high, d; |
||
203 | |||
204 | high = divisor >> 32; |
||
205 | if (high) { |
||
206 | unsigned int shift = fls(high); |
||
207 | |||
208 | d = divisor >> shift; |
||
209 | dividend >>= shift; |
||
210 | } else |
||
211 | d = divisor; |
||
212 | |||
213 | return div_u64(dividend, d); |
||
214 | } |
||
215 | |||
216 | /** |
||
5060 | serge | 217 | * drm_calc_timestamping_constants - calculate vblank timestamp constants |
218 | * @crtc: drm_crtc whose timestamp constants should be updated. |
||
219 | * @mode: display mode containing the scanout timings |
||
1963 | serge | 220 | * |
4560 | Serge | 221 | * Calculate and store various constants which are later |
222 | * needed by vblank and swap-completion timestamping, e.g, |
||
223 | * by drm_calc_vbltimestamp_from_scanoutpos(). They are |
||
5060 | serge | 224 | * derived from CRTC's true scanout timing, so they take |
4560 | Serge | 225 | * things like panel scaling or other adjustments into account. |
1963 | serge | 226 | */ |
4560 | Serge | 227 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, |
228 | const struct drm_display_mode *mode) |
||
1963 | serge | 229 | { |
4560 | Serge | 230 | int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; |
231 | int dotclock = mode->crtc_clock; |
||
1963 | serge | 232 | |
4560 | Serge | 233 | /* Valid dotclock? */ |
234 | if (dotclock > 0) { |
||
235 | int frame_size = mode->crtc_htotal * mode->crtc_vtotal; |
||
1963 | serge | 236 | |
4560 | Serge | 237 | /* |
238 | * Convert scanline length in pixels and video |
||
239 | * dot clock to line duration, frame duration |
||
240 | * and pixel duration in nanoseconds: |
||
1963 | serge | 241 | */ |
4560 | Serge | 242 | pixeldur_ns = 1000000 / dotclock; |
243 | linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); |
||
244 | framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); |
||
1963 | serge | 245 | |
4560 | Serge | 246 | /* |
247 | * Fields of interlaced scanout modes are only half a frame duration. |
||
1963 | serge | 248 | */ |
4560 | Serge | 249 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
250 | framedur_ns /= 2; |
||
1963 | serge | 251 | } else |
252 | DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", |
||
253 | crtc->base.id); |
||
254 | |||
255 | crtc->pixeldur_ns = pixeldur_ns; |
||
256 | crtc->linedur_ns = linedur_ns; |
||
257 | crtc->framedur_ns = framedur_ns; |
||
258 | |||
259 | DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", |
||
4560 | Serge | 260 | crtc->base.id, mode->crtc_htotal, |
261 | mode->crtc_vtotal, mode->crtc_vdisplay); |
||
1963 | serge | 262 | DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", |
4560 | Serge | 263 | crtc->base.id, dotclock, framedur_ns, |
264 | linedur_ns, pixeldur_ns); |
||
1963 | serge | 265 | } |
4293 | Serge | 266 | EXPORT_SYMBOL(drm_calc_timestamping_constants); |
1963 | serge | 267 | |
4293 | Serge | 268 | /** |
5060 | serge | 269 | * drm_calc_vbltimestamp_from_scanoutpos - precise vblank timestamp helper |
270 | * @dev: DRM device |
||
271 | * @crtc: Which CRTC's vblank timestamp to retrieve |
||
272 | * @max_error: Desired maximum allowable error in timestamps (nanosecs) |
||
273 | * On return contains true maximum error of timestamp |
||
274 | * @vblank_time: Pointer to struct timeval which should receive the timestamp |
||
275 | * @flags: Flags to pass to driver: |
||
276 | * 0 = Default, |
||
277 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler |
||
278 | * @refcrtc: CRTC which defines scanout timing |
||
279 | * @mode: mode which defines the scanout timings |
||
4293 | Serge | 280 | * |
5060 | serge | 281 | * Implements calculation of exact vblank timestamps from given drm_display_mode |
282 | * timings and current video scanout position of a CRTC. This can be called from |
||
283 | * within get_vblank_timestamp() implementation of a kms driver to implement the |
||
284 | * actual timestamping. |
||
285 | * |
||
4293 | Serge | 286 | * Should return timestamps conforming to the OML_sync_control OpenML |
287 | * extension specification. The timestamp corresponds to the end of |
||
288 | * the vblank interval, aka start of scanout of topmost-leftmost display |
||
289 | * pixel in the following video frame. |
||
290 | * |
||
291 | * Requires support for optional dev->driver->get_scanout_position() |
||
292 | * in kms driver, plus a bit of setup code to provide a drm_display_mode |
||
293 | * that corresponds to the true scanout timing. |
||
294 | * |
||
295 | * The current implementation only handles standard video modes. It |
||
296 | * returns as no operation if a doublescan or interlaced video mode is |
||
297 | * active. Higher level code is expected to handle this. |
||
298 | * |
||
5060 | serge | 299 | * Returns: |
300 | * Negative value on error, failure or if not supported in current |
||
4293 | Serge | 301 | * video mode: |
302 | * |
||
5060 | serge | 303 | * -EINVAL - Invalid CRTC. |
4293 | Serge | 304 | * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. |
305 | * -ENOTSUPP - Function not supported in current display mode. |
||
306 | * -EIO - Failed, e.g., due to failed scanout position query. |
||
307 | * |
||
308 | * Returns or'ed positive status flags on success: |
||
309 | * |
||
310 | * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. |
||
311 | * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. |
||
312 | * |
||
313 | */ |
||
314 | int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, |
||
315 | int *max_error, |
||
316 | struct timeval *vblank_time, |
||
317 | unsigned flags, |
||
4560 | Serge | 318 | const struct drm_crtc *refcrtc, |
319 | const struct drm_display_mode *mode) |
||
4293 | Serge | 320 | { |
321 | struct timeval tv_etime; |
||
4560 | Serge | 322 | int vbl_status; |
4293 | Serge | 323 | int vpos, hpos, i; |
4560 | Serge | 324 | int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; |
4293 | Serge | 325 | bool invbl; |
3031 | serge | 326 | |
4293 | Serge | 327 | if (crtc < 0 || crtc >= dev->num_crtcs) { |
328 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
329 | return -EINVAL; |
||
330 | } |
||
331 | |||
332 | /* Scanout position query not supported? Should not happen. */ |
||
333 | if (!dev->driver->get_scanout_position) { |
||
334 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); |
||
335 | return -EIO; |
||
336 | } |
||
337 | |||
338 | /* Durations of frames, lines, pixels in nanoseconds. */ |
||
339 | framedur_ns = refcrtc->framedur_ns; |
||
340 | linedur_ns = refcrtc->linedur_ns; |
||
341 | pixeldur_ns = refcrtc->pixeldur_ns; |
||
342 | |||
343 | /* If mode timing undefined, just return as no-op: |
||
344 | * Happens during initial modesetting of a crtc. |
||
345 | */ |
||
4560 | Serge | 346 | if (framedur_ns == 0) { |
4293 | Serge | 347 | DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); |
348 | return -EAGAIN; |
||
349 | } |
||
350 | |||
351 | return -EIO; |
||
352 | } |
||
353 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); |
||
354 | |||
5060 | serge | 355 | /** |
5271 | serge | 356 | * drm_vblank_get - get a reference count on vblank events |
357 | * @dev: DRM device |
||
358 | * @crtc: which CRTC to own |
||
359 | * |
||
360 | * Acquire a reference count on vblank events to avoid having them disabled |
||
361 | * while in use. |
||
362 | * |
||
363 | * This is the legacy version of drm_crtc_vblank_get(). |
||
364 | * |
||
365 | * Returns: |
||
366 | * Zero on success, nonzero on failure. |
||
367 | */ |
||
368 | int drm_vblank_get(struct drm_device *dev, int crtc) |
||
369 | { |
||
370 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
||
371 | unsigned long irqflags; |
||
372 | int ret = 0; |
||
373 | #if 0 |
||
374 | |||
375 | if (WARN_ON(crtc >= dev->num_crtcs)) |
||
376 | return -EINVAL; |
||
377 | |||
378 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
||
379 | /* Going from 0->1 means we have to enable interrupts again */ |
||
380 | if (atomic_add_return(1, &vblank->refcount) == 1) { |
||
381 | ret = drm_vblank_enable(dev, crtc); |
||
382 | } else { |
||
383 | if (!vblank->enabled) { |
||
384 | atomic_dec(&vblank->refcount); |
||
385 | ret = -EINVAL; |
||
386 | } |
||
387 | } |
||
388 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
||
389 | #endif |
||
390 | return ret; |
||
391 | } |
||
392 | EXPORT_SYMBOL(drm_vblank_get); |
||
393 | |||
394 | /** |
||
395 | * drm_crtc_vblank_get - get a reference count on vblank events |
||
396 | * @crtc: which CRTC to own |
||
397 | * |
||
398 | * Acquire a reference count on vblank events to avoid having them disabled |
||
399 | * while in use. |
||
400 | * |
||
401 | * This is the native kms version of drm_vblank_off(). |
||
402 | * |
||
403 | * Returns: |
||
404 | * Zero on success, nonzero on failure. |
||
405 | */ |
||
406 | int drm_crtc_vblank_get(struct drm_crtc *crtc) |
||
407 | { |
||
408 | return drm_vblank_get(crtc->dev, drm_crtc_index(crtc)); |
||
409 | } |
||
410 | EXPORT_SYMBOL(drm_crtc_vblank_get); |
||
411 | |||
412 | /** |
||
413 | * drm_vblank_put - give up ownership of vblank events |
||
414 | * @dev: DRM device |
||
415 | * @crtc: which counter to give up |
||
416 | * |
||
417 | * Release ownership of a given vblank counter, turning off interrupts |
||
418 | * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. |
||
419 | * |
||
420 | * This is the legacy version of drm_crtc_vblank_put(). |
||
421 | */ |
||
422 | void drm_vblank_put(struct drm_device *dev, int crtc) |
||
423 | { |
||
424 | #if 0 |
||
425 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
||
426 | |||
427 | if (WARN_ON(atomic_read(&vblank->refcount) == 0)) |
||
428 | return; |
||
429 | |||
430 | if (WARN_ON(crtc >= dev->num_crtcs)) |
||
431 | return; |
||
432 | |||
433 | /* Last user schedules interrupt disable */ |
||
434 | if (atomic_dec_and_test(&vblank->refcount)) { |
||
435 | if (drm_vblank_offdelay == 0) |
||
436 | return; |
||
437 | else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) |
||
438 | vblank_disable_fn((unsigned long)vblank); |
||
439 | else |
||
440 | mod_timer(&vblank->disable_timer, |
||
441 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); |
||
442 | } |
||
443 | #endif |
||
444 | } |
||
445 | EXPORT_SYMBOL(drm_vblank_put); |
||
446 | |||
447 | /** |
||
448 | * drm_crtc_vblank_put - give up ownership of vblank events |
||
449 | * @crtc: which counter to give up |
||
450 | * |
||
451 | * Release ownership of a given vblank counter, turning off interrupts |
||
452 | * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. |
||
453 | * |
||
454 | * This is the native kms version of drm_vblank_put(). |
||
455 | */ |
||
456 | void drm_crtc_vblank_put(struct drm_crtc *crtc) |
||
457 | { |
||
458 | drm_vblank_put(crtc->dev, drm_crtc_index(crtc)); |
||
459 | } |
||
460 | EXPORT_SYMBOL(drm_crtc_vblank_put); |
||
461 | |||
462 | /** |
||
463 | * drm_wait_one_vblank - wait for one vblank |
||
464 | * @dev: DRM device |
||
465 | * @crtc: crtc index |
||
466 | * |
||
467 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. |
||
468 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. |
||
469 | * due to lack of driver support or because the crtc is off. |
||
470 | */ |
||
471 | void drm_wait_one_vblank(struct drm_device *dev, int crtc) |
||
472 | { |
||
473 | #if 0 |
||
474 | int ret; |
||
475 | u32 last; |
||
476 | |||
477 | ret = drm_vblank_get(dev, crtc); |
||
478 | if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret)) |
||
479 | return; |
||
480 | |||
481 | last = drm_vblank_count(dev, crtc); |
||
482 | |||
483 | ret = wait_event_timeout(dev->vblank[crtc].queue, |
||
484 | last != drm_vblank_count(dev, crtc), |
||
485 | msecs_to_jiffies(100)); |
||
486 | |||
487 | WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc); |
||
488 | |||
489 | drm_vblank_put(dev, crtc); |
||
490 | #endif |
||
491 | } |
||
492 | EXPORT_SYMBOL(drm_wait_one_vblank); |
||
493 | |||
494 | /** |
||
495 | * drm_crtc_wait_one_vblank - wait for one vblank |
||
496 | * @crtc: DRM crtc |
||
497 | * |
||
498 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. |
||
499 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. |
||
500 | * due to lack of driver support or because the crtc is off. |
||
501 | */ |
||
502 | void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) |
||
503 | { |
||
504 | drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); |
||
505 | } |
||
506 | EXPORT_SYMBOL(drm_crtc_wait_one_vblank); |
||
507 | |||
508 | /** |
||
5060 | serge | 509 | * drm_vblank_off - disable vblank events on a CRTC |
510 | * @dev: DRM device |
||
511 | * @crtc: CRTC in question |
||
512 | * |
||
513 | * Drivers can use this function to shut down the vblank interrupt handling when |
||
514 | * disabling a crtc. This function ensures that the latest vblank frame count is |
||
515 | * stored so that drm_vblank_on() can restore it again. |
||
516 | * |
||
517 | * Drivers must use this function when the hardware vblank counter can get |
||
518 | * reset, e.g. when suspending. |
||
519 | * |
||
520 | * This is the legacy version of drm_crtc_vblank_off(). |
||
521 | */ |
||
522 | void drm_vblank_off(struct drm_device *dev, int crtc) |
||
523 | { |
||
5271 | serge | 524 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
5060 | serge | 525 | struct drm_pending_vblank_event *e, *t; |
526 | struct timeval now; |
||
527 | unsigned long irqflags; |
||
528 | unsigned int seq; |
||
4293 | Serge | 529 | |
5060 | serge | 530 | |
531 | } |
||
532 | EXPORT_SYMBOL(drm_vblank_off); |
||
533 | |||
3031 | serge | 534 | /** |
5060 | serge | 535 | * drm_crtc_vblank_off - disable vblank events on a CRTC |
536 | * @crtc: CRTC in question |
||
537 | * |
||
538 | * Drivers can use this function to shut down the vblank interrupt handling when |
||
539 | * disabling a crtc. This function ensures that the latest vblank frame count is |
||
540 | * stored so that drm_vblank_on can restore it again. |
||
541 | * |
||
542 | * Drivers must use this function when the hardware vblank counter can get |
||
543 | * reset, e.g. when suspending. |
||
544 | * |
||
545 | * This is the native kms version of drm_vblank_off(). |
||
546 | */ |
||
547 | void drm_crtc_vblank_off(struct drm_crtc *crtc) |
||
548 | { |
||
549 | drm_vblank_off(crtc->dev, drm_crtc_index(crtc)); |
||
550 | } |
||
551 | EXPORT_SYMBOL(drm_crtc_vblank_off); |
||
552 | |||
553 | /** |
||
554 | * drm_vblank_on - enable vblank events on a CRTC |
||
555 | * @dev: DRM device |
||
556 | * @crtc: CRTC in question |
||
557 | * |
||
558 | * This functions restores the vblank interrupt state captured with |
||
559 | * drm_vblank_off() again. Note that calls to drm_vblank_on() and |
||
5271 | serge | 560 | * drm_vblank_off() can be unbalanced and so can also be unconditionally called |
5060 | serge | 561 | * in driver load code to reflect the current hardware state of the crtc. |
562 | * |
||
563 | * This is the legacy version of drm_crtc_vblank_on(). |
||
564 | */ |
||
565 | void drm_vblank_on(struct drm_device *dev, int crtc) |
||
566 | { |
||
5271 | serge | 567 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
5060 | serge | 568 | unsigned long irqflags; |
569 | |||
570 | } |
||
571 | EXPORT_SYMBOL(drm_vblank_on); |
||
572 | |||
573 | /** |
||
574 | * drm_crtc_vblank_on - enable vblank events on a CRTC |
||
575 | * @crtc: CRTC in question |
||
576 | * |
||
577 | * This functions restores the vblank interrupt state captured with |
||
578 | * drm_vblank_off() again. Note that calls to drm_vblank_on() and |
||
5271 | serge | 579 | * drm_vblank_off() can be unbalanced and so can also be unconditionally called |
5060 | serge | 580 | * in driver load code to reflect the current hardware state of the crtc. |
581 | * |
||
582 | * This is the native kms version of drm_vblank_on(). |
||
583 | */ |
||
584 | void drm_crtc_vblank_on(struct drm_crtc *crtc) |
||
585 | { |
||
586 | drm_vblank_on(crtc->dev, drm_crtc_index(crtc)); |
||
587 | } |
||
588 | EXPORT_SYMBOL(drm_crtc_vblank_on); |
||
589 | |||
590 | /** |
||
3031 | serge | 591 | * drm_vblank_pre_modeset - account for vblanks across mode sets |
592 | * @dev: DRM device |
||
593 | * @crtc: CRTC in question |
||
594 | * |
||
595 | * Account for vblank events across mode setting events, which will likely |
||
596 | * reset the hardware frame counter. |
||
5060 | serge | 597 | * |
598 | * This is done by grabbing a temporary vblank reference to ensure that the |
||
599 | * vblank interrupt keeps running across the modeset sequence. With this the |
||
600 | * software-side vblank frame counting will ensure that there are no jumps or |
||
601 | * discontinuities. |
||
602 | * |
||
603 | * Unfortunately this approach is racy and also doesn't work when the vblank |
||
604 | * interrupt stops running, e.g. across system suspend resume. It is therefore |
||
605 | * highly recommended that drivers use the newer drm_vblank_off() and |
||
606 | * drm_vblank_on() instead. drm_vblank_pre_modeset() only works correctly when |
||
607 | * using "cooked" software vblank frame counters and not relying on any hardware |
||
608 | * counters. |
||
609 | * |
||
610 | * Drivers must call drm_vblank_post_modeset() when re-enabling the same crtc |
||
611 | * again. |
||
3031 | serge | 612 | */ |
613 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) |
||
614 | { |
||
615 | #if 0 |
||
616 | /* vblank is not initialized (IRQ not installed ?) */ |
||
617 | if (!dev->num_crtcs) |
||
618 | return; |
||
5271 | serge | 619 | |
620 | if (WARN_ON(crtc >= dev->num_crtcs)) |
||
621 | return; |
||
622 | |||
3031 | serge | 623 | /* |
624 | * To avoid all the problems that might happen if interrupts |
||
625 | * were enabled/disabled around or between these calls, we just |
||
626 | * have the kernel take a reference on the CRTC (just once though |
||
627 | * to avoid corrupting the count if multiple, mismatch calls occur), |
||
628 | * so that interrupts remain enabled in the interim. |
||
629 | */ |
||
5271 | serge | 630 | if (!vblank->inmodeset) { |
631 | vblank->inmodeset = 0x1; |
||
3031 | serge | 632 | if (drm_vblank_get(dev, crtc) == 0) |
5271 | serge | 633 | vblank->inmodeset |= 0x2; |
3031 | serge | 634 | } |
635 | #endif |
||
636 | } |
||
637 | EXPORT_SYMBOL(drm_vblank_pre_modeset); |
||
638 | |||
5060 | serge | 639 | /** |
640 | * drm_vblank_post_modeset - undo drm_vblank_pre_modeset changes |
||
641 | * @dev: DRM device |
||
642 | * @crtc: CRTC in question |
||
643 | * |
||
644 | * This function again drops the temporary vblank reference acquired in |
||
645 | * drm_vblank_pre_modeset. |
||
646 | */ |
||
3031 | serge | 647 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) |
648 | { |
||
649 | #if 0 |
||
650 | unsigned long irqflags; |
||
651 | |||
4075 | Serge | 652 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
653 | if (!dev->num_crtcs) |
||
654 | return; |
||
655 | |||
5271 | serge | 656 | if (vblank->inmodeset) { |
3031 | serge | 657 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
4560 | Serge | 658 | dev->vblank_disable_allowed = true; |
3031 | serge | 659 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
660 | |||
5271 | serge | 661 | if (vblank->inmodeset & 0x2) |
3031 | serge | 662 | drm_vblank_put(dev, crtc); |
663 | |||
5271 | serge | 664 | vblank->inmodeset = 0; |
3031 | serge | 665 | } |
666 | #endif |
||
667 | } |
||
668 | EXPORT_SYMBOL(drm_vblank_post_modeset);>>10); |
||
5271 | serge | 669 | |
670 |