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