Rev 5271 | Rev 6088 | 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 | |
6084 | serge | 45 | ktime_t ktime_get(void); |
46 | |||
47 | static inline ktime_t ktime_get_real(void) |
||
48 | { |
||
49 | return ktime_get(); |
||
50 | } |
||
51 | |||
52 | static inline ktime_t ktime_mono_to_real(ktime_t mono) |
||
53 | { |
||
54 | return mono; |
||
55 | } |
||
56 | |||
57 | |||
1963 | serge | 58 | /* Access macro for slots in vblank timestamp ringbuffer. */ |
6084 | serge | 59 | #define vblanktimestamp(dev, pipe, count) \ |
60 | ((dev)->vblank[pipe].time[(count) % DRM_VBLANKTIME_RBSIZE]) |
||
1963 | serge | 61 | |
62 | /* Retry timestamp calculation up to 3 times to satisfy |
||
63 | * drm_timestamp_precision before giving up. |
||
64 | */ |
||
65 | #define DRM_TIMESTAMP_MAXRETRIES 3 |
||
66 | |||
67 | /* Threshold in nanoseconds for detection of redundant |
||
68 | * vblank irq in drm_handle_vblank(). 1 msec should be ok. |
||
69 | */ |
||
70 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 |
||
71 | |||
5271 | serge | 72 | static bool |
6084 | serge | 73 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, |
5271 | serge | 74 | struct timeval *tvblank, unsigned flags); |
75 | |||
76 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ |
||
77 | |||
5060 | serge | 78 | /* |
6084 | serge | 79 | * Default to use monotonic timestamps for wait-for-vblank and page-flip |
80 | * complete events. |
||
5060 | serge | 81 | */ |
6084 | serge | 82 | unsigned int drm_timestamp_monotonic = 1; |
1963 | serge | 83 | |
6084 | serge | 84 | static int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ |
5060 | serge | 85 | |
6084 | serge | 86 | module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); |
87 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); |
||
88 | module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); |
||
89 | |||
90 | static void store_vblank(struct drm_device *dev, unsigned int pipe, |
||
91 | u32 vblank_count_inc, |
||
92 | struct timeval *t_vblank, u32 last) |
||
93 | { |
||
94 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
95 | u32 tslot; |
||
96 | |||
97 | assert_spin_locked(&dev->vblank_time_lock); |
||
98 | |||
99 | vblank->last = last; |
||
100 | |||
101 | /* All writers hold the spinlock, but readers are serialized by |
||
102 | * the latching of vblank->count below. |
||
103 | */ |
||
104 | tslot = vblank->count + vblank_count_inc; |
||
105 | vblanktimestamp(dev, pipe, tslot) = *t_vblank; |
||
106 | |||
107 | /* |
||
108 | * vblank timestamp updates are protected on the write side with |
||
109 | * vblank_time_lock, but on the read side done locklessly using a |
||
110 | * sequence-lock on the vblank counter. Ensure correct ordering using |
||
111 | * memory barrriers. We need the barrier both before and also after the |
||
112 | * counter update to synchronize with the next timestamp write. |
||
113 | * The read-side barriers for this are in drm_vblank_count_and_time. |
||
114 | */ |
||
115 | smp_wmb(); |
||
116 | vblank->count += vblank_count_inc; |
||
117 | smp_wmb(); |
||
118 | } |
||
119 | |||
5060 | serge | 120 | /** |
6084 | serge | 121 | * drm_reset_vblank_timestamp - reset the last timestamp to the last vblank |
122 | * @dev: DRM device |
||
123 | * @pipe: index of CRTC for which to reset the timestamp |
||
124 | * |
||
125 | * Reset the stored timestamp for the current vblank count to correspond |
||
126 | * to the last vblank occurred. |
||
127 | * |
||
128 | * Only to be called from drm_vblank_on(). |
||
129 | * |
||
130 | * Note: caller must hold dev->vbl_lock since this reads & writes |
||
131 | * device vblank fields. |
||
132 | */ |
||
133 | static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe) |
||
134 | { |
||
135 | u32 cur_vblank; |
||
136 | bool rc; |
||
137 | struct timeval t_vblank; |
||
138 | int count = DRM_TIMESTAMP_MAXRETRIES; |
||
139 | |||
140 | spin_lock(&dev->vblank_time_lock); |
||
141 | |||
142 | /* |
||
143 | * sample the current counter to avoid random jumps |
||
144 | * when drm_vblank_enable() applies the diff |
||
145 | */ |
||
146 | do { |
||
147 | cur_vblank = dev->driver->get_vblank_counter(dev, pipe); |
||
148 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0); |
||
149 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0); |
||
150 | |||
151 | /* |
||
152 | * Only reinitialize corresponding vblank timestamp if high-precision query |
||
153 | * available and didn't fail. Otherwise reinitialize delayed at next vblank |
||
154 | * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid. |
||
155 | */ |
||
156 | if (!rc) |
||
157 | t_vblank = (struct timeval) {0, 0}; |
||
158 | |||
159 | /* |
||
160 | * +1 to make sure user will never see the same |
||
161 | * vblank counter value before and after a modeset |
||
162 | */ |
||
163 | store_vblank(dev, pipe, 1, &t_vblank, cur_vblank); |
||
164 | |||
165 | spin_unlock(&dev->vblank_time_lock); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * drm_update_vblank_count - update the master vblank counter |
||
170 | * @dev: DRM device |
||
171 | * @pipe: counter to update |
||
172 | * |
||
173 | * Call back into the driver to update the appropriate vblank counter |
||
174 | * (specified by @pipe). Deal with wraparound, if it occurred, and |
||
175 | * update the last read value so we can deal with wraparound on the next |
||
176 | * call if necessary. |
||
177 | * |
||
178 | * Only necessary when going from off->on, to account for frames we |
||
179 | * didn't get an interrupt for. |
||
180 | * |
||
181 | * Note: caller must hold dev->vbl_lock since this reads & writes |
||
182 | * device vblank fields. |
||
183 | */ |
||
184 | static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, |
||
185 | unsigned long flags) |
||
186 | { |
||
187 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
188 | u32 cur_vblank, diff; |
||
189 | bool rc; |
||
190 | struct timeval t_vblank; |
||
191 | int count = DRM_TIMESTAMP_MAXRETRIES; |
||
192 | int framedur_ns = vblank->framedur_ns; |
||
193 | |||
194 | /* |
||
195 | * Interrupts were disabled prior to this call, so deal with counter |
||
196 | * wrap if needed. |
||
197 | * NOTE! It's possible we lost a full dev->max_vblank_count + 1 events |
||
198 | * here if the register is small or we had vblank interrupts off for |
||
199 | * a long time. |
||
200 | * |
||
201 | * We repeat the hardware vblank counter & timestamp query until |
||
202 | * we get consistent results. This to prevent races between gpu |
||
203 | * updating its hardware counter while we are retrieving the |
||
204 | * corresponding vblank timestamp. |
||
205 | */ |
||
206 | do { |
||
207 | cur_vblank = dev->driver->get_vblank_counter(dev, pipe); |
||
208 | rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags); |
||
209 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0); |
||
210 | |||
211 | if (dev->max_vblank_count != 0) { |
||
212 | /* trust the hw counter when it's around */ |
||
213 | diff = (cur_vblank - vblank->last) & dev->max_vblank_count; |
||
214 | } else if (rc && framedur_ns) { |
||
215 | const struct timeval *t_old; |
||
216 | u64 diff_ns; |
||
217 | |||
218 | t_old = &vblanktimestamp(dev, pipe, vblank->count); |
||
219 | diff_ns = timeval_to_ns(&t_vblank) - timeval_to_ns(t_old); |
||
220 | |||
221 | /* |
||
222 | * Figure out how many vblanks we've missed based |
||
223 | * on the difference in the timestamps and the |
||
224 | * frame/field duration. |
||
225 | */ |
||
226 | diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); |
||
227 | |||
228 | if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ) |
||
229 | DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored." |
||
230 | " diff_ns = %lld, framedur_ns = %d)\n", |
||
231 | pipe, (long long) diff_ns, framedur_ns); |
||
232 | } else { |
||
233 | /* some kind of default for drivers w/o accurate vbl timestamping */ |
||
234 | diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; |
||
235 | } |
||
236 | |||
237 | DRM_DEBUG_VBL("updating vblank count on crtc %u:" |
||
238 | " current=%u, diff=%u, hw=%u hw_last=%u\n", |
||
239 | pipe, vblank->count, diff, cur_vblank, vblank->last); |
||
240 | |||
241 | if (diff == 0) { |
||
242 | WARN_ON_ONCE(cur_vblank != vblank->last); |
||
243 | return; |
||
244 | } |
||
245 | |||
246 | /* |
||
247 | * Only reinitialize corresponding vblank timestamp if high-precision query |
||
248 | * available and didn't fail, or we were called from the vblank interrupt. |
||
249 | * Otherwise reinitialize delayed at next vblank interrupt and assign 0 |
||
250 | * for now, to mark the vblanktimestamp as invalid. |
||
251 | */ |
||
252 | if (!rc && (flags & DRM_CALLED_FROM_VBLIRQ) == 0) |
||
253 | t_vblank = (struct timeval) {0, 0}; |
||
254 | |||
255 | store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); |
||
256 | } |
||
257 | |||
258 | /* |
||
259 | * Disable vblank irq's on crtc, make sure that last vblank count |
||
260 | * of hardware and corresponding consistent software vblank counter |
||
261 | * are preserved, even if there are any spurious vblank irq's after |
||
262 | * disable. |
||
263 | */ |
||
264 | static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) |
||
265 | { |
||
266 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
267 | unsigned long irqflags; |
||
268 | |||
269 | /* Prevent vblank irq processing while disabling vblank irqs, |
||
270 | * so no updates of timestamps or count can happen after we've |
||
271 | * disabled. Needed to prevent races in case of delayed irq's. |
||
272 | */ |
||
273 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); |
||
274 | |||
275 | /* |
||
276 | * Only disable vblank interrupts if they're enabled. This avoids |
||
277 | * calling the ->disable_vblank() operation in atomic context with the |
||
278 | * hardware potentially runtime suspended. |
||
279 | */ |
||
280 | if (vblank->enabled) { |
||
281 | dev->driver->disable_vblank(dev, pipe); |
||
282 | vblank->enabled = false; |
||
283 | } |
||
284 | |||
285 | /* |
||
286 | * Always update the count and timestamp to maintain the |
||
287 | * appearance that the counter has been ticking all along until |
||
288 | * this time. This makes the count account for the entire time |
||
289 | * between drm_vblank_on() and drm_vblank_off(). |
||
290 | */ |
||
291 | drm_update_vblank_count(dev, pipe, 0); |
||
292 | |||
293 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); |
||
294 | } |
||
295 | |||
296 | static void vblank_disable_fn(unsigned long arg) |
||
297 | { |
||
298 | struct drm_vblank_crtc *vblank = (void *)arg; |
||
299 | struct drm_device *dev = vblank->dev; |
||
300 | unsigned int pipe = vblank->pipe; |
||
301 | unsigned long irqflags; |
||
302 | |||
303 | if (!dev->vblank_disable_allowed) |
||
304 | return; |
||
305 | |||
306 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
||
307 | if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) { |
||
308 | DRM_DEBUG("disabling vblank on crtc %u\n", pipe); |
||
309 | vblank_disable_and_save(dev, pipe); |
||
310 | } |
||
311 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * drm_vblank_cleanup - cleanup vblank support |
||
316 | * @dev: DRM device |
||
317 | * |
||
318 | * This function cleans up any resources allocated in drm_vblank_init. |
||
319 | */ |
||
320 | void drm_vblank_cleanup(struct drm_device *dev) |
||
321 | { |
||
322 | unsigned int pipe; |
||
323 | |||
324 | /* Bail if the driver didn't call drm_vblank_init() */ |
||
325 | if (dev->num_crtcs == 0) |
||
326 | return; |
||
327 | |||
328 | for (pipe = 0; pipe < dev->num_crtcs; pipe++) { |
||
329 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
330 | |||
331 | WARN_ON(vblank->enabled && |
||
332 | drm_core_check_feature(dev, DRIVER_MODESET)); |
||
333 | |||
334 | del_timer_sync(&vblank->disable_timer); |
||
335 | } |
||
336 | |||
337 | kfree(dev->vblank); |
||
338 | |||
339 | dev->num_crtcs = 0; |
||
340 | } |
||
341 | EXPORT_SYMBOL(drm_vblank_cleanup); |
||
342 | |||
343 | /** |
||
5060 | serge | 344 | * drm_vblank_init - initialize vblank support |
6084 | serge | 345 | * @dev: DRM device |
346 | * @num_crtcs: number of CRTCs supported by @dev |
||
5060 | serge | 347 | * |
348 | * This function initializes vblank support for @num_crtcs display pipelines. |
||
349 | * |
||
350 | * Returns: |
||
351 | * Zero on success or a negative error code on failure. |
||
352 | */ |
||
6084 | serge | 353 | int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) |
5060 | serge | 354 | { |
6084 | serge | 355 | int ret = -ENOMEM; |
356 | unsigned int i; |
||
5060 | serge | 357 | |
358 | spin_lock_init(&dev->vbl_lock); |
||
359 | spin_lock_init(&dev->vblank_time_lock); |
||
360 | |||
361 | dev->num_crtcs = num_crtcs; |
||
362 | |||
363 | dev->vblank = kcalloc(num_crtcs, sizeof(*dev->vblank), GFP_KERNEL); |
||
364 | if (!dev->vblank) |
||
365 | goto err; |
||
366 | |||
367 | for (i = 0; i < num_crtcs; i++) { |
||
5271 | serge | 368 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
369 | |||
370 | vblank->dev = dev; |
||
6084 | serge | 371 | vblank->pipe = i; |
5271 | serge | 372 | init_waitqueue_head(&vblank->queue); |
6084 | serge | 373 | // setup_timer(&vblank->disable_timer, vblank_disable_fn, |
374 | // (unsigned long)vblank); |
||
5060 | serge | 375 | } |
376 | |||
377 | DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); |
||
378 | |||
379 | /* Driver specific high-precision vblank timestamping supported? */ |
||
380 | if (dev->driver->get_vblank_timestamp) |
||
381 | DRM_INFO("Driver supports precise vblank timestamp query.\n"); |
||
382 | else |
||
383 | DRM_INFO("No driver support for vblank timestamp query.\n"); |
||
384 | |||
6084 | serge | 385 | /* Must have precise timestamping for reliable vblank instant disable */ |
386 | if (dev->vblank_disable_immediate && !dev->driver->get_vblank_timestamp) { |
||
387 | dev->vblank_disable_immediate = false; |
||
388 | DRM_INFO("Setting vblank_disable_immediate to false because " |
||
389 | "get_vblank_timestamp == NULL\n"); |
||
390 | } |
||
391 | |||
5060 | serge | 392 | dev->vblank_disable_allowed = false; |
393 | |||
394 | return 0; |
||
395 | |||
396 | err: |
||
5271 | serge | 397 | dev->num_crtcs = 0; |
5060 | serge | 398 | return ret; |
399 | } |
||
400 | EXPORT_SYMBOL(drm_vblank_init); |
||
401 | |||
402 | |||
6084 | serge | 403 | |
4075 | Serge | 404 | irqreturn_t device_irq_handler(struct drm_device *dev) |
405 | { |
||
406 | |||
4104 | Serge | 407 | // printf("video irq\n"); |
4075 | Serge | 408 | |
409 | // printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ; |
||
410 | |||
411 | return dev->driver->irq_handler(0, dev); |
||
412 | } |
||
413 | |||
414 | /** |
||
5060 | serge | 415 | * drm_irq_install - install IRQ handler |
416 | * @dev: DRM device |
||
417 | * @irq: IRQ number to install the handler for |
||
4075 | Serge | 418 | * |
5060 | serge | 419 | * Initializes the IRQ related data. Installs the handler, calling the driver |
420 | * irq_preinstall() and irq_postinstall() functions before and after the |
||
421 | * installation. |
||
4075 | Serge | 422 | * |
5060 | serge | 423 | * This is the simplified helper interface provided for drivers with no special |
424 | * needs. Drivers which need to install interrupt handlers for multiple |
||
425 | * interrupts must instead set drm_device->irq_enabled to signal the DRM core |
||
426 | * that vblank interrupts are available. |
||
427 | * |
||
428 | * Returns: |
||
429 | * Zero on success or a negative error code on failure. |
||
4075 | Serge | 430 | */ |
5060 | serge | 431 | int drm_irq_install(struct drm_device *dev, int irq) |
4075 | Serge | 432 | { |
433 | int ret; |
||
6084 | serge | 434 | unsigned long sh_flags = 0; |
4075 | Serge | 435 | |
4293 | Serge | 436 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
437 | return -EINVAL; |
||
4075 | Serge | 438 | |
5060 | serge | 439 | if (irq == 0) |
4075 | Serge | 440 | return -EINVAL; |
441 | |||
6084 | serge | 442 | /* Driver must have been initialized */ |
5060 | serge | 443 | if (!dev->dev_private) |
6084 | serge | 444 | return -EINVAL; |
4075 | Serge | 445 | |
5060 | serge | 446 | if (dev->irq_enabled) |
6084 | serge | 447 | return -EBUSY; |
4560 | Serge | 448 | dev->irq_enabled = true; |
4075 | Serge | 449 | |
5060 | serge | 450 | DRM_DEBUG("irq=%d\n", irq); |
4075 | Serge | 451 | |
6084 | serge | 452 | /* Before installing handler */ |
453 | if (dev->driver->irq_preinstall) |
||
454 | dev->driver->irq_preinstall(dev); |
||
4075 | Serge | 455 | |
5060 | serge | 456 | ret = !AttachIntHandler(irq, device_irq_handler, (u32)dev); |
4075 | Serge | 457 | |
6084 | serge | 458 | /* After installing handler */ |
459 | if (dev->driver->irq_postinstall) |
||
460 | ret = dev->driver->irq_postinstall(dev); |
||
4075 | Serge | 461 | |
6084 | serge | 462 | if (ret < 0) { |
5060 | serge | 463 | dev->irq_enabled = false; |
464 | } else { |
||
465 | dev->irq = irq; |
||
6084 | serge | 466 | } |
4075 | Serge | 467 | |
5271 | serge | 468 | u16 cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4); |
4075 | Serge | 469 | cmd&= ~(1<<10); |
470 | PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd); |
||
471 | |||
472 | return ret; |
||
473 | } |
||
474 | EXPORT_SYMBOL(drm_irq_install); |
||
475 | |||
476 | |||
1963 | serge | 477 | |
478 | |||
479 | |||
480 | /** |
||
5060 | serge | 481 | * drm_calc_timestamping_constants - calculate vblank timestamp constants |
482 | * @crtc: drm_crtc whose timestamp constants should be updated. |
||
483 | * @mode: display mode containing the scanout timings |
||
1963 | serge | 484 | * |
4560 | Serge | 485 | * Calculate and store various constants which are later |
486 | * needed by vblank and swap-completion timestamping, e.g, |
||
487 | * by drm_calc_vbltimestamp_from_scanoutpos(). They are |
||
5060 | serge | 488 | * derived from CRTC's true scanout timing, so they take |
4560 | Serge | 489 | * things like panel scaling or other adjustments into account. |
1963 | serge | 490 | */ |
4560 | Serge | 491 | void drm_calc_timestamping_constants(struct drm_crtc *crtc, |
492 | const struct drm_display_mode *mode) |
||
1963 | serge | 493 | { |
6084 | serge | 494 | struct drm_device *dev = crtc->dev; |
495 | unsigned int pipe = drm_crtc_index(crtc); |
||
496 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
497 | int linedur_ns = 0, framedur_ns = 0; |
||
4560 | Serge | 498 | int dotclock = mode->crtc_clock; |
1963 | serge | 499 | |
6084 | serge | 500 | if (!dev->num_crtcs) |
501 | return; |
||
502 | |||
503 | if (WARN_ON(pipe >= dev->num_crtcs)) |
||
504 | return; |
||
505 | |||
4560 | Serge | 506 | /* Valid dotclock? */ |
507 | if (dotclock > 0) { |
||
508 | int frame_size = mode->crtc_htotal * mode->crtc_vtotal; |
||
1963 | serge | 509 | |
4560 | Serge | 510 | /* |
511 | * Convert scanline length in pixels and video |
||
6084 | serge | 512 | * dot clock to line duration and frame duration |
513 | * in nanoseconds: |
||
514 | */ |
||
4560 | Serge | 515 | linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock); |
516 | framedur_ns = div_u64((u64) frame_size * 1000000, dotclock); |
||
1963 | serge | 517 | |
4560 | Serge | 518 | /* |
519 | * Fields of interlaced scanout modes are only half a frame duration. |
||
1963 | serge | 520 | */ |
4560 | Serge | 521 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
522 | framedur_ns /= 2; |
||
1963 | serge | 523 | } else |
6084 | serge | 524 | DRM_ERROR("crtc %u: Can't calculate constants, dotclock = 0!\n", |
1963 | serge | 525 | crtc->base.id); |
526 | |||
6084 | serge | 527 | vblank->linedur_ns = linedur_ns; |
528 | vblank->framedur_ns = framedur_ns; |
||
1963 | serge | 529 | |
6084 | serge | 530 | DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", |
4560 | Serge | 531 | crtc->base.id, mode->crtc_htotal, |
532 | mode->crtc_vtotal, mode->crtc_vdisplay); |
||
6084 | serge | 533 | DRM_DEBUG("crtc %u: clock %d kHz framedur %d linedur %d\n", |
534 | crtc->base.id, dotclock, framedur_ns, linedur_ns); |
||
1963 | serge | 535 | } |
4293 | Serge | 536 | EXPORT_SYMBOL(drm_calc_timestamping_constants); |
1963 | serge | 537 | |
4293 | Serge | 538 | /** |
5060 | serge | 539 | * drm_calc_vbltimestamp_from_scanoutpos - precise vblank timestamp helper |
540 | * @dev: DRM device |
||
6084 | serge | 541 | * @pipe: index of CRTC whose vblank timestamp to retrieve |
5060 | serge | 542 | * @max_error: Desired maximum allowable error in timestamps (nanosecs) |
543 | * On return contains true maximum error of timestamp |
||
544 | * @vblank_time: Pointer to struct timeval which should receive the timestamp |
||
545 | * @flags: Flags to pass to driver: |
||
546 | * 0 = Default, |
||
547 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler |
||
548 | * @mode: mode which defines the scanout timings |
||
4293 | Serge | 549 | * |
5060 | serge | 550 | * Implements calculation of exact vblank timestamps from given drm_display_mode |
551 | * timings and current video scanout position of a CRTC. This can be called from |
||
552 | * within get_vblank_timestamp() implementation of a kms driver to implement the |
||
553 | * actual timestamping. |
||
554 | * |
||
4293 | Serge | 555 | * Should return timestamps conforming to the OML_sync_control OpenML |
556 | * extension specification. The timestamp corresponds to the end of |
||
557 | * the vblank interval, aka start of scanout of topmost-leftmost display |
||
558 | * pixel in the following video frame. |
||
559 | * |
||
560 | * Requires support for optional dev->driver->get_scanout_position() |
||
561 | * in kms driver, plus a bit of setup code to provide a drm_display_mode |
||
562 | * that corresponds to the true scanout timing. |
||
563 | * |
||
564 | * The current implementation only handles standard video modes. It |
||
565 | * returns as no operation if a doublescan or interlaced video mode is |
||
566 | * active. Higher level code is expected to handle this. |
||
567 | * |
||
5060 | serge | 568 | * Returns: |
569 | * Negative value on error, failure or if not supported in current |
||
4293 | Serge | 570 | * video mode: |
571 | * |
||
5060 | serge | 572 | * -EINVAL - Invalid CRTC. |
4293 | Serge | 573 | * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. |
574 | * -ENOTSUPP - Function not supported in current display mode. |
||
575 | * -EIO - Failed, e.g., due to failed scanout position query. |
||
576 | * |
||
577 | * Returns or'ed positive status flags on success: |
||
578 | * |
||
579 | * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. |
||
580 | * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. |
||
581 | * |
||
582 | */ |
||
6084 | serge | 583 | int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, |
584 | unsigned int pipe, |
||
4293 | Serge | 585 | int *max_error, |
586 | struct timeval *vblank_time, |
||
587 | unsigned flags, |
||
4560 | Serge | 588 | const struct drm_display_mode *mode) |
4293 | Serge | 589 | { |
590 | struct timeval tv_etime; |
||
6084 | serge | 591 | ktime_t stime, etime; |
592 | unsigned int vbl_status; |
||
593 | int ret = DRM_VBLANKTIME_SCANOUTPOS_METHOD; |
||
4293 | Serge | 594 | int vpos, hpos, i; |
6084 | serge | 595 | int delta_ns, duration_ns; |
3031 | serge | 596 | |
6084 | serge | 597 | if (pipe >= dev->num_crtcs) { |
598 | DRM_ERROR("Invalid crtc %u\n", pipe); |
||
4293 | Serge | 599 | return -EINVAL; |
600 | } |
||
601 | |||
602 | /* Scanout position query not supported? Should not happen. */ |
||
603 | if (!dev->driver->get_scanout_position) { |
||
604 | DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); |
||
605 | return -EIO; |
||
606 | } |
||
607 | |||
608 | /* If mode timing undefined, just return as no-op: |
||
609 | * Happens during initial modesetting of a crtc. |
||
610 | */ |
||
6084 | serge | 611 | if (mode->crtc_clock == 0) { |
612 | DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); |
||
4293 | Serge | 613 | return -EAGAIN; |
614 | } |
||
615 | |||
6084 | serge | 616 | /* Get current scanout position with system timestamp. |
617 | * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times |
||
618 | * if single query takes longer than max_error nanoseconds. |
||
619 | * |
||
620 | * This guarantees a tight bound on maximum error if |
||
621 | * code gets preempted or delayed for some reason. |
||
622 | */ |
||
623 | for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { |
||
624 | /* |
||
625 | * Get vertical and horizontal scanout position vpos, hpos, |
||
626 | * and bounding timestamps stime, etime, pre/post query. |
||
627 | */ |
||
628 | vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, |
||
629 | &vpos, &hpos, |
||
630 | &stime, &etime, |
||
631 | mode); |
||
632 | |||
633 | /* Return as no-op if scanout query unsupported or failed. */ |
||
634 | if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { |
||
635 | DRM_DEBUG("crtc %u : scanoutpos query failed [0x%x].\n", |
||
636 | pipe, vbl_status); |
||
637 | return -EIO; |
||
638 | } |
||
639 | |||
640 | /* Compute uncertainty in timestamp of scanout position query. */ |
||
641 | duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime); |
||
642 | |||
643 | /* Accept result with < max_error nsecs timing uncertainty. */ |
||
644 | if (duration_ns <= *max_error) |
||
645 | break; |
||
646 | } |
||
647 | |||
648 | /* Noisy system timing? */ |
||
649 | if (i == DRM_TIMESTAMP_MAXRETRIES) { |
||
650 | DRM_DEBUG("crtc %u: Noisy timestamp %d us > %d us [%d reps].\n", |
||
651 | pipe, duration_ns/1000, *max_error/1000, i); |
||
652 | } |
||
653 | |||
654 | /* Return upper bound of timestamp precision error. */ |
||
655 | *max_error = duration_ns; |
||
656 | |||
657 | /* Check if in vblank area: |
||
658 | * vpos is >=0 in video scanout area, but negative |
||
659 | * within vblank area, counting down the number of lines until |
||
660 | * start of scanout. |
||
661 | */ |
||
662 | if (vbl_status & DRM_SCANOUTPOS_IN_VBLANK) |
||
663 | ret |= DRM_VBLANKTIME_IN_VBLANK; |
||
664 | |||
665 | /* Convert scanout position into elapsed time at raw_time query |
||
666 | * since start of scanout at first display scanline. delta_ns |
||
667 | * can be negative if start of scanout hasn't happened yet. |
||
668 | */ |
||
669 | delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos), |
||
670 | mode->crtc_clock); |
||
671 | |||
672 | if (!drm_timestamp_monotonic) |
||
673 | etime = ktime_mono_to_real(etime); |
||
674 | |||
675 | /* save this only for debugging purposes */ |
||
676 | tv_etime = ktime_to_timeval(etime); |
||
677 | /* Subtract time delta from raw timestamp to get final |
||
678 | * vblank_time timestamp for end of vblank. |
||
679 | */ |
||
680 | if (delta_ns < 0) |
||
681 | etime = ktime_add_ns(etime, -delta_ns); |
||
682 | else |
||
683 | etime = ktime_sub_ns(etime, delta_ns); |
||
684 | *vblank_time = ktime_to_timeval(etime); |
||
685 | |||
686 | DRM_DEBUG_VBL("crtc %u : v 0x%x p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n", |
||
687 | pipe, vbl_status, hpos, vpos, |
||
688 | (long)tv_etime.tv_sec, (long)tv_etime.tv_usec, |
||
689 | (long)vblank_time->tv_sec, (long)vblank_time->tv_usec, |
||
690 | duration_ns/1000, i); |
||
691 | |||
692 | return ret; |
||
4293 | Serge | 693 | } |
694 | EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); |
||
695 | |||
6084 | serge | 696 | static struct timeval get_drm_timestamp(void) |
697 | { |
||
698 | ktime_t now; |
||
699 | |||
700 | now = drm_timestamp_monotonic ? ktime_get() : ktime_get_real(); |
||
701 | return ktime_to_timeval(now); |
||
702 | } |
||
703 | |||
5060 | serge | 704 | /** |
6084 | serge | 705 | * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent |
706 | * vblank interval |
||
707 | * @dev: DRM device |
||
708 | * @pipe: index of CRTC whose vblank timestamp to retrieve |
||
709 | * @tvblank: Pointer to target struct timeval which should receive the timestamp |
||
710 | * @flags: Flags to pass to driver: |
||
711 | * 0 = Default, |
||
712 | * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler |
||
713 | * |
||
714 | * Fetches the system timestamp corresponding to the time of the most recent |
||
715 | * vblank interval on specified CRTC. May call into kms-driver to |
||
716 | * compute the timestamp with a high-precision GPU specific method. |
||
717 | * |
||
718 | * Returns zero if timestamp originates from uncorrected do_gettimeofday() |
||
719 | * call, i.e., it isn't very precisely locked to the true vblank. |
||
720 | * |
||
721 | * Returns: |
||
722 | * True if timestamp is considered to be very precise, false otherwise. |
||
723 | */ |
||
724 | static bool |
||
725 | drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, |
||
726 | struct timeval *tvblank, unsigned flags) |
||
727 | { |
||
728 | int ret; |
||
729 | |||
730 | /* Define requested maximum error on timestamps (nanoseconds). */ |
||
731 | int max_error = (int) drm_timestamp_precision * 1000; |
||
732 | |||
733 | /* Query driver if possible and precision timestamping enabled. */ |
||
734 | if (dev->driver->get_vblank_timestamp && (max_error > 0)) { |
||
735 | ret = dev->driver->get_vblank_timestamp(dev, pipe, &max_error, |
||
736 | tvblank, flags); |
||
737 | if (ret > 0) |
||
738 | return true; |
||
739 | } |
||
740 | |||
741 | /* GPU high precision timestamp query unsupported or failed. |
||
742 | * Return current monotonic/gettimeofday timestamp as best estimate. |
||
743 | */ |
||
744 | *tvblank = get_drm_timestamp(); |
||
745 | |||
746 | return false; |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * drm_vblank_count - retrieve "cooked" vblank counter value |
||
751 | * @dev: DRM device |
||
752 | * @pipe: index of CRTC for which to retrieve the counter |
||
753 | * |
||
754 | * Fetches the "cooked" vblank count value that represents the number of |
||
755 | * vblank events since the system was booted, including lost events due to |
||
756 | * modesetting activity. |
||
757 | * |
||
758 | * This is the legacy version of drm_crtc_vblank_count(). |
||
759 | * |
||
760 | * Returns: |
||
761 | * The software vblank counter. |
||
762 | */ |
||
763 | u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe) |
||
764 | { |
||
765 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
766 | |||
767 | if (WARN_ON(pipe >= dev->num_crtcs)) |
||
768 | return 0; |
||
769 | |||
770 | return vblank->count; |
||
771 | } |
||
772 | EXPORT_SYMBOL(drm_vblank_count); |
||
773 | |||
774 | /** |
||
775 | * drm_crtc_vblank_count - retrieve "cooked" vblank counter value |
||
776 | * @crtc: which counter to retrieve |
||
777 | * |
||
778 | * Fetches the "cooked" vblank count value that represents the number of |
||
779 | * vblank events since the system was booted, including lost events due to |
||
780 | * modesetting activity. |
||
781 | * |
||
782 | * This is the native KMS version of drm_vblank_count(). |
||
783 | * |
||
784 | * Returns: |
||
785 | * The software vblank counter. |
||
786 | */ |
||
787 | u32 drm_crtc_vblank_count(struct drm_crtc *crtc) |
||
788 | { |
||
789 | return drm_vblank_count(crtc->dev, drm_crtc_index(crtc)); |
||
790 | } |
||
791 | EXPORT_SYMBOL(drm_crtc_vblank_count); |
||
792 | |||
793 | /** |
||
794 | * drm_vblank_count_and_time - retrieve "cooked" vblank counter value and the |
||
795 | * system timestamp corresponding to that vblank counter value. |
||
796 | * @dev: DRM device |
||
797 | * @pipe: index of CRTC whose counter to retrieve |
||
798 | * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. |
||
799 | * |
||
800 | * Fetches the "cooked" vblank count value that represents the number of |
||
801 | * vblank events since the system was booted, including lost events due to |
||
802 | * modesetting activity. Returns corresponding system timestamp of the time |
||
803 | * of the vblank interval that corresponds to the current vblank counter value. |
||
804 | * |
||
805 | * This is the legacy version of drm_crtc_vblank_count_and_time(). |
||
806 | */ |
||
807 | u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, |
||
808 | struct timeval *vblanktime) |
||
809 | { |
||
810 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
811 | int count = DRM_TIMESTAMP_MAXRETRIES; |
||
812 | u32 cur_vblank; |
||
813 | |||
814 | if (WARN_ON(pipe >= dev->num_crtcs)) |
||
815 | return 0; |
||
816 | |||
817 | /* |
||
818 | * Vblank timestamps are read lockless. To ensure consistency the vblank |
||
819 | * counter is rechecked and ordering is ensured using memory barriers. |
||
820 | * This works like a seqlock. The write-side barriers are in store_vblank. |
||
821 | */ |
||
822 | do { |
||
823 | cur_vblank = vblank->count; |
||
824 | smp_rmb(); |
||
825 | *vblanktime = vblanktimestamp(dev, pipe, cur_vblank); |
||
826 | smp_rmb(); |
||
827 | } while (cur_vblank != vblank->count && --count > 0); |
||
828 | |||
829 | return cur_vblank; |
||
830 | } |
||
831 | EXPORT_SYMBOL(drm_vblank_count_and_time); |
||
832 | /** |
||
833 | * drm_vblank_enable - enable the vblank interrupt on a CRTC |
||
834 | * @dev: DRM device |
||
835 | * @pipe: CRTC index |
||
836 | * |
||
837 | * Returns: |
||
838 | * Zero on success or a negative error code on failure. |
||
839 | */ |
||
840 | static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) |
||
841 | { |
||
842 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
843 | int ret = 0; |
||
844 | |||
845 | assert_spin_locked(&dev->vbl_lock); |
||
846 | |||
847 | spin_lock(&dev->vblank_time_lock); |
||
848 | |||
849 | if (!vblank->enabled) { |
||
850 | /* |
||
851 | * Enable vblank irqs under vblank_time_lock protection. |
||
852 | * All vblank count & timestamp updates are held off |
||
853 | * until we are done reinitializing master counter and |
||
854 | * timestamps. Filtercode in drm_handle_vblank() will |
||
855 | * prevent double-accounting of same vblank interval. |
||
856 | */ |
||
857 | ret = dev->driver->enable_vblank(dev, pipe); |
||
858 | DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret); |
||
859 | if (ret) |
||
860 | atomic_dec(&vblank->refcount); |
||
861 | else { |
||
862 | vblank->enabled = true; |
||
863 | drm_update_vblank_count(dev, pipe, 0); |
||
864 | } |
||
865 | } |
||
866 | |||
867 | spin_unlock(&dev->vblank_time_lock); |
||
868 | |||
869 | return ret; |
||
870 | } |
||
871 | |||
872 | /** |
||
5271 | serge | 873 | * drm_vblank_get - get a reference count on vblank events |
874 | * @dev: DRM device |
||
6084 | serge | 875 | * @pipe: index of CRTC to own |
5271 | serge | 876 | * |
877 | * Acquire a reference count on vblank events to avoid having them disabled |
||
878 | * while in use. |
||
879 | * |
||
880 | * This is the legacy version of drm_crtc_vblank_get(). |
||
881 | * |
||
882 | * Returns: |
||
6084 | serge | 883 | * Zero on success or a negative error code on failure. |
5271 | serge | 884 | */ |
6084 | serge | 885 | int drm_vblank_get(struct drm_device *dev, unsigned int pipe) |
5271 | serge | 886 | { |
6084 | serge | 887 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
5271 | serge | 888 | unsigned long irqflags; |
889 | int ret = 0; |
||
890 | |||
6084 | serge | 891 | if (!dev->num_crtcs) |
5271 | serge | 892 | return -EINVAL; |
893 | |||
6084 | serge | 894 | if (WARN_ON(pipe >= dev->num_crtcs)) |
895 | return -EINVAL; |
||
896 | |||
5271 | serge | 897 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
898 | /* Going from 0->1 means we have to enable interrupts again */ |
||
899 | if (atomic_add_return(1, &vblank->refcount) == 1) { |
||
6084 | serge | 900 | ret = drm_vblank_enable(dev, pipe); |
5271 | serge | 901 | } else { |
902 | if (!vblank->enabled) { |
||
903 | atomic_dec(&vblank->refcount); |
||
904 | ret = -EINVAL; |
||
905 | } |
||
906 | } |
||
907 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
||
6084 | serge | 908 | |
5271 | serge | 909 | return ret; |
910 | } |
||
911 | EXPORT_SYMBOL(drm_vblank_get); |
||
912 | |||
913 | /** |
||
914 | * drm_crtc_vblank_get - get a reference count on vblank events |
||
915 | * @crtc: which CRTC to own |
||
916 | * |
||
917 | * Acquire a reference count on vblank events to avoid having them disabled |
||
918 | * while in use. |
||
919 | * |
||
6084 | serge | 920 | * This is the native kms version of drm_vblank_get(). |
5271 | serge | 921 | * |
922 | * Returns: |
||
6084 | serge | 923 | * Zero on success or a negative error code on failure. |
5271 | serge | 924 | */ |
925 | int drm_crtc_vblank_get(struct drm_crtc *crtc) |
||
926 | { |
||
927 | return drm_vblank_get(crtc->dev, drm_crtc_index(crtc)); |
||
928 | } |
||
929 | EXPORT_SYMBOL(drm_crtc_vblank_get); |
||
930 | |||
931 | /** |
||
6084 | serge | 932 | * drm_vblank_put - release ownership of vblank events |
5271 | serge | 933 | * @dev: DRM device |
6084 | serge | 934 | * @pipe: index of CRTC to release |
5271 | serge | 935 | * |
936 | * Release ownership of a given vblank counter, turning off interrupts |
||
937 | * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. |
||
938 | * |
||
939 | * This is the legacy version of drm_crtc_vblank_put(). |
||
940 | */ |
||
6084 | serge | 941 | void drm_vblank_put(struct drm_device *dev, unsigned int pipe) |
5271 | serge | 942 | { |
6084 | serge | 943 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
5271 | serge | 944 | |
6084 | serge | 945 | if (WARN_ON(pipe >= dev->num_crtcs)) |
5271 | serge | 946 | return; |
947 | |||
6084 | serge | 948 | if (WARN_ON(atomic_read(&vblank->refcount) == 0)) |
5271 | serge | 949 | return; |
950 | |||
951 | /* Last user schedules interrupt disable */ |
||
952 | if (atomic_dec_and_test(&vblank->refcount)) { |
||
953 | if (drm_vblank_offdelay == 0) |
||
954 | return; |
||
955 | else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) |
||
956 | vblank_disable_fn((unsigned long)vblank); |
||
957 | else |
||
958 | mod_timer(&vblank->disable_timer, |
||
959 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); |
||
960 | } |
||
961 | } |
||
962 | EXPORT_SYMBOL(drm_vblank_put); |
||
963 | |||
964 | /** |
||
965 | * drm_crtc_vblank_put - give up ownership of vblank events |
||
966 | * @crtc: which counter to give up |
||
967 | * |
||
968 | * Release ownership of a given vblank counter, turning off interrupts |
||
969 | * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. |
||
970 | * |
||
971 | * This is the native kms version of drm_vblank_put(). |
||
972 | */ |
||
973 | void drm_crtc_vblank_put(struct drm_crtc *crtc) |
||
974 | { |
||
975 | drm_vblank_put(crtc->dev, drm_crtc_index(crtc)); |
||
976 | } |
||
977 | EXPORT_SYMBOL(drm_crtc_vblank_put); |
||
978 | |||
979 | /** |
||
980 | * drm_wait_one_vblank - wait for one vblank |
||
981 | * @dev: DRM device |
||
6084 | serge | 982 | * @pipe: CRTC index |
5271 | serge | 983 | * |
6084 | serge | 984 | * This waits for one vblank to pass on @pipe, using the irq driver interfaces. |
985 | * It is a failure to call this when the vblank irq for @pipe is disabled, e.g. |
||
5271 | serge | 986 | * due to lack of driver support or because the crtc is off. |
987 | */ |
||
6084 | serge | 988 | void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) |
5271 | serge | 989 | { |
990 | #if 0 |
||
991 | int ret; |
||
992 | u32 last; |
||
993 | |||
994 | ret = drm_vblank_get(dev, crtc); |
||
995 | if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret)) |
||
996 | return; |
||
997 | |||
998 | last = drm_vblank_count(dev, crtc); |
||
999 | |||
1000 | ret = wait_event_timeout(dev->vblank[crtc].queue, |
||
1001 | last != drm_vblank_count(dev, crtc), |
||
1002 | msecs_to_jiffies(100)); |
||
1003 | |||
1004 | WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc); |
||
1005 | |||
1006 | drm_vblank_put(dev, crtc); |
||
1007 | #endif |
||
1008 | } |
||
1009 | EXPORT_SYMBOL(drm_wait_one_vblank); |
||
1010 | |||
1011 | /** |
||
1012 | * drm_crtc_wait_one_vblank - wait for one vblank |
||
1013 | * @crtc: DRM crtc |
||
1014 | * |
||
1015 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. |
||
1016 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. |
||
1017 | * due to lack of driver support or because the crtc is off. |
||
1018 | */ |
||
1019 | void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) |
||
1020 | { |
||
1021 | drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); |
||
1022 | } |
||
1023 | EXPORT_SYMBOL(drm_crtc_wait_one_vblank); |
||
1024 | |||
1025 | /** |
||
5060 | serge | 1026 | * drm_vblank_off - disable vblank events on a CRTC |
1027 | * @dev: DRM device |
||
6084 | serge | 1028 | * @pipe: CRTC index |
5060 | serge | 1029 | * |
1030 | * Drivers can use this function to shut down the vblank interrupt handling when |
||
1031 | * disabling a crtc. This function ensures that the latest vblank frame count is |
||
1032 | * stored so that drm_vblank_on() can restore it again. |
||
1033 | * |
||
1034 | * Drivers must use this function when the hardware vblank counter can get |
||
1035 | * reset, e.g. when suspending. |
||
1036 | * |
||
1037 | * This is the legacy version of drm_crtc_vblank_off(). |
||
1038 | */ |
||
6084 | serge | 1039 | void drm_vblank_off(struct drm_device *dev, unsigned int pipe) |
5060 | serge | 1040 | { |
6084 | serge | 1041 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
5060 | serge | 1042 | struct drm_pending_vblank_event *e, *t; |
1043 | struct timeval now; |
||
1044 | unsigned long irqflags; |
||
1045 | unsigned int seq; |
||
4293 | Serge | 1046 | |
5060 | serge | 1047 | |
1048 | } |
||
1049 | EXPORT_SYMBOL(drm_vblank_off); |
||
1050 | |||
3031 | serge | 1051 | /** |
5060 | serge | 1052 | * drm_crtc_vblank_off - disable vblank events on a CRTC |
1053 | * @crtc: CRTC in question |
||
1054 | * |
||
1055 | * Drivers can use this function to shut down the vblank interrupt handling when |
||
1056 | * disabling a crtc. This function ensures that the latest vblank frame count is |
||
1057 | * stored so that drm_vblank_on can restore it again. |
||
1058 | * |
||
1059 | * Drivers must use this function when the hardware vblank counter can get |
||
1060 | * reset, e.g. when suspending. |
||
1061 | * |
||
1062 | * This is the native kms version of drm_vblank_off(). |
||
1063 | */ |
||
1064 | void drm_crtc_vblank_off(struct drm_crtc *crtc) |
||
1065 | { |
||
1066 | drm_vblank_off(crtc->dev, drm_crtc_index(crtc)); |
||
1067 | } |
||
1068 | EXPORT_SYMBOL(drm_crtc_vblank_off); |
||
1069 | |||
1070 | /** |
||
6084 | serge | 1071 | * drm_crtc_vblank_reset - reset vblank state to off on a CRTC |
1072 | * @crtc: CRTC in question |
||
1073 | * |
||
1074 | * Drivers can use this function to reset the vblank state to off at load time. |
||
1075 | * Drivers should use this together with the drm_crtc_vblank_off() and |
||
1076 | * drm_crtc_vblank_on() functions. The difference compared to |
||
1077 | * drm_crtc_vblank_off() is that this function doesn't save the vblank counter |
||
1078 | * and hence doesn't need to call any driver hooks. |
||
1079 | */ |
||
1080 | void drm_crtc_vblank_reset(struct drm_crtc *crtc) |
||
1081 | { |
||
1082 | struct drm_device *dev = crtc->dev; |
||
1083 | unsigned long irqflags; |
||
1084 | unsigned int pipe = drm_crtc_index(crtc); |
||
1085 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
||
1086 | |||
1087 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
||
1088 | /* |
||
1089 | * Prevent subsequent drm_vblank_get() from enabling the vblank |
||
1090 | * interrupt by bumping the refcount. |
||
1091 | */ |
||
1092 | if (!vblank->inmodeset) { |
||
1093 | atomic_inc(&vblank->refcount); |
||
1094 | vblank->inmodeset = 1; |
||
1095 | } |
||
1096 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
||
1097 | |||
1098 | WARN_ON(!list_empty(&dev->vblank_event_list)); |
||
1099 | } |
||
1100 | EXPORT_SYMBOL(drm_crtc_vblank_reset); |
||
1101 | |||
1102 | /** |
||
5060 | serge | 1103 | * drm_vblank_on - enable vblank events on a CRTC |
1104 | * @dev: DRM device |
||
6084 | serge | 1105 | * @pipe: CRTC index |
5060 | serge | 1106 | * |
1107 | * This functions restores the vblank interrupt state captured with |
||
1108 | * drm_vblank_off() again. Note that calls to drm_vblank_on() and |
||
5271 | serge | 1109 | * drm_vblank_off() can be unbalanced and so can also be unconditionally called |
5060 | serge | 1110 | * in driver load code to reflect the current hardware state of the crtc. |
1111 | * |
||
1112 | * This is the legacy version of drm_crtc_vblank_on(). |
||
1113 | */ |
||
6084 | serge | 1114 | void drm_vblank_on(struct drm_device *dev, unsigned int pipe) |
5060 | serge | 1115 | { |
6084 | serge | 1116 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
5060 | serge | 1117 | unsigned long irqflags; |
1118 | |||
6084 | serge | 1119 | dbgprintf("%s pipe %d dev->num_crtcs %d\n", pipe,dev->num_crtcs);\ |
1120 | |||
1121 | if (WARN_ON(pipe >= dev->num_crtcs)) |
||
1122 | return; |
||
1123 | |||
1124 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
||
1125 | /* Drop our private "prevent drm_vblank_get" refcount */ |
||
1126 | if (vblank->inmodeset) { |
||
1127 | atomic_dec(&vblank->refcount); |
||
1128 | vblank->inmodeset = 0; |
||
1129 | } |
||
1130 | |||
1131 | drm_reset_vblank_timestamp(dev, pipe); |
||
1132 | |||
1133 | /* |
||
1134 | * re-enable interrupts if there are users left, or the |
||
1135 | * user wishes vblank interrupts to be enabled all the time. |
||
1136 | */ |
||
1137 | if (atomic_read(&vblank->refcount) != 0 || |
||
1138 | (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0)) |
||
1139 | WARN_ON(drm_vblank_enable(dev, pipe)); |
||
1140 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
||
5060 | serge | 1141 | } |
1142 | EXPORT_SYMBOL(drm_vblank_on); |
||
1143 | |||
1144 | /** |
||
1145 | * drm_crtc_vblank_on - enable vblank events on a CRTC |
||
1146 | * @crtc: CRTC in question |
||
1147 | * |
||
1148 | * This functions restores the vblank interrupt state captured with |
||
1149 | * drm_vblank_off() again. Note that calls to drm_vblank_on() and |
||
5271 | serge | 1150 | * drm_vblank_off() can be unbalanced and so can also be unconditionally called |
5060 | serge | 1151 | * in driver load code to reflect the current hardware state of the crtc. |
1152 | * |
||
1153 | * This is the native kms version of drm_vblank_on(). |
||
1154 | */ |
||
1155 | void drm_crtc_vblank_on(struct drm_crtc *crtc) |
||
1156 | { |
||
1157 | drm_vblank_on(crtc->dev, drm_crtc_index(crtc)); |
||
1158 | } |
||
1159 | EXPORT_SYMBOL(drm_crtc_vblank_on); |
||
1160 | |||
1161 | /** |
||
3031 | serge | 1162 | * drm_vblank_pre_modeset - account for vblanks across mode sets |
1163 | * @dev: DRM device |
||
6084 | serge | 1164 | * @pipe: CRTC index |
3031 | serge | 1165 | * |
1166 | * Account for vblank events across mode setting events, which will likely |
||
1167 | * reset the hardware frame counter. |
||
5060 | serge | 1168 | * |
1169 | * This is done by grabbing a temporary vblank reference to ensure that the |
||
1170 | * vblank interrupt keeps running across the modeset sequence. With this the |
||
1171 | * software-side vblank frame counting will ensure that there are no jumps or |
||
1172 | * discontinuities. |
||
1173 | * |
||
1174 | * Unfortunately this approach is racy and also doesn't work when the vblank |
||
1175 | * interrupt stops running, e.g. across system suspend resume. It is therefore |
||
1176 | * highly recommended that drivers use the newer drm_vblank_off() and |
||
1177 | * drm_vblank_on() instead. drm_vblank_pre_modeset() only works correctly when |
||
1178 | * using "cooked" software vblank frame counters and not relying on any hardware |
||
1179 | * counters. |
||
1180 | * |
||
1181 | * Drivers must call drm_vblank_post_modeset() when re-enabling the same crtc |
||
1182 | * again. |
||
3031 | serge | 1183 | */ |
6084 | serge | 1184 | void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe) |
3031 | serge | 1185 | { |
6084 | serge | 1186 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
5271 | serge | 1187 | |
6084 | serge | 1188 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1189 | if (!dev->num_crtcs) |
||
5271 | serge | 1190 | return; |
1191 | |||
6084 | serge | 1192 | if (WARN_ON(pipe >= dev->num_crtcs)) |
1193 | return; |
||
1194 | |||
1195 | /* |
||
1196 | * To avoid all the problems that might happen if interrupts |
||
1197 | * were enabled/disabled around or between these calls, we just |
||
1198 | * have the kernel take a reference on the CRTC (just once though |
||
1199 | * to avoid corrupting the count if multiple, mismatch calls occur), |
||
1200 | * so that interrupts remain enabled in the interim. |
||
1201 | */ |
||
5271 | serge | 1202 | if (!vblank->inmodeset) { |
1203 | vblank->inmodeset = 0x1; |
||
6084 | serge | 1204 | if (drm_vblank_get(dev, pipe) == 0) |
5271 | serge | 1205 | vblank->inmodeset |= 0x2; |
6084 | serge | 1206 | } |
3031 | serge | 1207 | } |
1208 | EXPORT_SYMBOL(drm_vblank_pre_modeset); |
||
1209 | |||
5060 | serge | 1210 | /** |
1211 | * drm_vblank_post_modeset - undo drm_vblank_pre_modeset changes |
||
1212 | * @dev: DRM device |
||
6084 | serge | 1213 | * @pipe: CRTC index |
5060 | serge | 1214 | * |
1215 | * This function again drops the temporary vblank reference acquired in |
||
1216 | * drm_vblank_pre_modeset. |
||
1217 | */ |
||
6084 | serge | 1218 | void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) |
3031 | serge | 1219 | { |
6084 | serge | 1220 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; |
1221 | unsigned long irqflags; |
||
3031 | serge | 1222 | |
4075 | Serge | 1223 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1224 | if (!dev->num_crtcs) |
||
1225 | return; |
||
1226 | |||
6084 | serge | 1227 | if (WARN_ON(pipe >= dev->num_crtcs)) |
1228 | return; |
||
1229 | |||
5271 | serge | 1230 | if (vblank->inmodeset) { |
6084 | serge | 1231 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
4560 | Serge | 1232 | dev->vblank_disable_allowed = true; |
6084 | serge | 1233 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
3031 | serge | 1234 | |
5271 | serge | 1235 | if (vblank->inmodeset & 0x2) |
6084 | serge | 1236 | drm_vblank_put(dev, pipe); |
3031 | serge | 1237 | |
5271 | serge | 1238 | vblank->inmodeset = 0; |
6084 | serge | 1239 | } |
3031 | serge | 1240 | } |
1241 | EXPORT_SYMBOL(drm_vblank_post_modeset); |
||
5271 | serge | 1242 | |
1243 | |||
6084 | serge | 1244 | u64 div64_u64(u64 dividend, u64 divisor) |
1245 | { |
||
1246 | u32 high, d; |
||
1247 | |||
1248 | high = divisor >> 32; |
||
1249 | if (high) { |
||
1250 | unsigned int shift = fls(high); |
||
1251 | |||
1252 | d = divisor >> shift; |
||
1253 | dividend >>= shift; |
||
1254 | } else |
||
1255 | d = divisor; |
||
1256 | |||
1257 | return div_u64(dividend, d); |
||
1258 | }>>=>>>10); |