Rev 6105 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6105 | serge | 1 | /* |
2 | * Copyright 2008 Advanced Micro Devices, Inc. |
||
3 | * Copyright 2008 Red Hat Inc. |
||
4 | * Copyright 2009 Jerome Glisse. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included in |
||
14 | * all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
22 | * OTHER DEALINGS IN THE SOFTWARE. |
||
23 | * |
||
24 | * Authors: Dave Airlie |
||
25 | * Alex Deucher |
||
26 | * Jerome Glisse |
||
27 | */ |
||
28 | #include |
||
29 | #include "radeon.h" |
||
30 | #include |
||
31 | #include "radeon_asic.h" |
||
32 | |||
33 | #include |
||
34 | #include |
||
35 | |||
36 | #include "radeon_kfd.h" |
||
37 | |||
38 | #if defined(CONFIG_VGA_SWITCHEROO) |
||
39 | bool radeon_has_atpx(void); |
||
40 | #else |
||
41 | static inline bool radeon_has_atpx(void) { return false; } |
||
42 | #endif |
||
43 | |||
44 | |||
45 | /* |
||
46 | * VBlank related functions. |
||
47 | */ |
||
48 | /** |
||
49 | * radeon_get_vblank_counter_kms - get frame count |
||
50 | * |
||
51 | * @dev: drm dev pointer |
||
6938 | serge | 52 | * @pipe: crtc to get the frame count from |
6105 | serge | 53 | * |
54 | * Gets the frame count on the requested crtc (all asics). |
||
55 | * Returns frame count on success, -EINVAL on failure. |
||
56 | */ |
||
6938 | serge | 57 | u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) |
6105 | serge | 58 | { |
59 | int vpos, hpos, stat; |
||
60 | u32 count; |
||
61 | struct radeon_device *rdev = dev->dev_private; |
||
62 | |||
6938 | serge | 63 | if (pipe >= rdev->num_crtc) { |
64 | DRM_ERROR("Invalid crtc %u\n", pipe); |
||
6105 | serge | 65 | return -EINVAL; |
66 | } |
||
67 | |||
68 | /* The hw increments its frame counter at start of vsync, not at start |
||
69 | * of vblank, as is required by DRM core vblank counter handling. |
||
70 | * Cook the hw count here to make it appear to the caller as if it |
||
71 | * incremented at start of vblank. We measure distance to start of |
||
72 | * vblank in vpos. vpos therefore will be >= 0 between start of vblank |
||
73 | * and start of vsync, so vpos >= 0 means to bump the hw frame counter |
||
74 | * result by 1 to give the proper appearance to caller. |
||
75 | */ |
||
6938 | serge | 76 | if (rdev->mode_info.crtcs[pipe]) { |
6105 | serge | 77 | /* Repeat readout if needed to provide stable result if |
78 | * we cross start of vsync during the queries. |
||
79 | */ |
||
80 | do { |
||
6938 | serge | 81 | count = radeon_get_vblank_counter(rdev, pipe); |
6105 | serge | 82 | /* Ask radeon_get_crtc_scanoutpos to return vpos as |
83 | * distance to start of vblank, instead of regular |
||
84 | * vertical scanout pos. |
||
85 | */ |
||
86 | stat = radeon_get_crtc_scanoutpos( |
||
6938 | serge | 87 | dev, pipe, GET_DISTANCE_TO_VBLANKSTART, |
6105 | serge | 88 | &vpos, &hpos, NULL, NULL, |
6938 | serge | 89 | &rdev->mode_info.crtcs[pipe]->base.hwmode); |
90 | } while (count != radeon_get_vblank_counter(rdev, pipe)); |
||
6105 | serge | 91 | |
92 | if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != |
||
93 | (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { |
||
94 | DRM_DEBUG_VBL("Query failed! stat %d\n", stat); |
||
95 | } |
||
96 | else { |
||
6938 | serge | 97 | DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n", |
98 | pipe, vpos); |
||
6105 | serge | 99 | |
100 | /* Bump counter if we are at >= leading edge of vblank, |
||
101 | * but before vsync where vpos would turn negative and |
||
102 | * the hw counter really increments. |
||
103 | */ |
||
104 | if (vpos >= 0) |
||
105 | count++; |
||
106 | } |
||
107 | } |
||
108 | else { |
||
109 | /* Fallback to use value as is. */ |
||
6938 | serge | 110 | count = radeon_get_vblank_counter(rdev, pipe); |
6105 | serge | 111 | DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); |
112 | } |
||
113 | |||
114 | return count; |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * radeon_enable_vblank_kms - enable vblank interrupt |
||
119 | * |
||
120 | * @dev: drm dev pointer |
||
121 | * @crtc: crtc to enable vblank interrupt for |
||
122 | * |
||
123 | * Enable the interrupt on the requested crtc (all asics). |
||
124 | * Returns 0 on success, -EINVAL on failure. |
||
125 | */ |
||
126 | int radeon_enable_vblank_kms(struct drm_device *dev, int crtc) |
||
127 | { |
||
128 | struct radeon_device *rdev = dev->dev_private; |
||
129 | unsigned long irqflags; |
||
130 | int r; |
||
131 | |||
132 | if (crtc < 0 || crtc >= rdev->num_crtc) { |
||
133 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
134 | return -EINVAL; |
||
135 | } |
||
136 | |||
137 | spin_lock_irqsave(&rdev->irq.lock, irqflags); |
||
138 | rdev->irq.crtc_vblank_int[crtc] = true; |
||
139 | r = radeon_irq_set(rdev); |
||
140 | spin_unlock_irqrestore(&rdev->irq.lock, irqflags); |
||
141 | return r; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * radeon_disable_vblank_kms - disable vblank interrupt |
||
146 | * |
||
147 | * @dev: drm dev pointer |
||
148 | * @crtc: crtc to disable vblank interrupt for |
||
149 | * |
||
150 | * Disable the interrupt on the requested crtc (all asics). |
||
151 | */ |
||
152 | void radeon_disable_vblank_kms(struct drm_device *dev, int crtc) |
||
153 | { |
||
154 | struct radeon_device *rdev = dev->dev_private; |
||
155 | unsigned long irqflags; |
||
156 | |||
157 | if (crtc < 0 || crtc >= rdev->num_crtc) { |
||
158 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
159 | return; |
||
160 | } |
||
161 | |||
162 | spin_lock_irqsave(&rdev->irq.lock, irqflags); |
||
163 | rdev->irq.crtc_vblank_int[crtc] = false; |
||
164 | radeon_irq_set(rdev); |
||
165 | spin_unlock_irqrestore(&rdev->irq.lock, irqflags); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * radeon_get_vblank_timestamp_kms - get vblank timestamp |
||
170 | * |
||
171 | * @dev: drm dev pointer |
||
172 | * @crtc: crtc to get the timestamp for |
||
173 | * @max_error: max error |
||
174 | * @vblank_time: time value |
||
175 | * @flags: flags passed to the driver |
||
176 | * |
||
177 | * Gets the timestamp on the requested crtc based on the |
||
178 | * scanout position. (all asics). |
||
179 | * Returns postive status flags on success, negative error on failure. |
||
180 | */ |
||
181 | int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, |
||
182 | int *max_error, |
||
183 | struct timeval *vblank_time, |
||
184 | unsigned flags) |
||
185 | { |
||
186 | struct drm_crtc *drmcrtc; |
||
187 | struct radeon_device *rdev = dev->dev_private; |
||
188 | |||
189 | if (crtc < 0 || crtc >= dev->num_crtcs) { |
||
190 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
191 | return -EINVAL; |
||
192 | } |
||
193 | |||
194 | /* Get associated drm_crtc: */ |
||
195 | drmcrtc = &rdev->mode_info.crtcs[crtc]->base; |
||
196 | if (!drmcrtc) |
||
197 | return -EINVAL; |
||
198 | |||
199 | /* Helper routine in DRM core does all the work: */ |
||
200 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, |
||
201 | vblank_time, flags, |
||
202 | &drmcrtc->hwmode); |
||
203 | }>>> |
||
204 |