Rev 6938 | 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 | |||
7146 | serge | 33 | #include |
6105 | serge | 34 | #include |
35 | #include |
||
36 | |||
37 | #include "radeon_kfd.h" |
||
38 | |||
39 | #if defined(CONFIG_VGA_SWITCHEROO) |
||
40 | bool radeon_has_atpx(void); |
||
41 | #else |
||
42 | static inline bool radeon_has_atpx(void) { return false; } |
||
43 | #endif |
||
44 | |||
45 | |||
46 | /* |
||
47 | * VBlank related functions. |
||
48 | */ |
||
49 | /** |
||
50 | * radeon_get_vblank_counter_kms - get frame count |
||
51 | * |
||
52 | * @dev: drm dev pointer |
||
6938 | serge | 53 | * @pipe: crtc to get the frame count from |
6105 | serge | 54 | * |
55 | * Gets the frame count on the requested crtc (all asics). |
||
56 | * Returns frame count on success, -EINVAL on failure. |
||
57 | */ |
||
6938 | serge | 58 | u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) |
6105 | serge | 59 | { |
60 | int vpos, hpos, stat; |
||
61 | u32 count; |
||
62 | struct radeon_device *rdev = dev->dev_private; |
||
63 | |||
6938 | serge | 64 | if (pipe >= rdev->num_crtc) { |
65 | DRM_ERROR("Invalid crtc %u\n", pipe); |
||
6105 | serge | 66 | return -EINVAL; |
67 | } |
||
68 | |||
69 | /* The hw increments its frame counter at start of vsync, not at start |
||
70 | * of vblank, as is required by DRM core vblank counter handling. |
||
71 | * Cook the hw count here to make it appear to the caller as if it |
||
72 | * incremented at start of vblank. We measure distance to start of |
||
73 | * vblank in vpos. vpos therefore will be >= 0 between start of vblank |
||
74 | * and start of vsync, so vpos >= 0 means to bump the hw frame counter |
||
75 | * result by 1 to give the proper appearance to caller. |
||
76 | */ |
||
6938 | serge | 77 | if (rdev->mode_info.crtcs[pipe]) { |
6105 | serge | 78 | /* Repeat readout if needed to provide stable result if |
79 | * we cross start of vsync during the queries. |
||
80 | */ |
||
81 | do { |
||
6938 | serge | 82 | count = radeon_get_vblank_counter(rdev, pipe); |
6105 | serge | 83 | /* Ask radeon_get_crtc_scanoutpos to return vpos as |
84 | * distance to start of vblank, instead of regular |
||
85 | * vertical scanout pos. |
||
86 | */ |
||
87 | stat = radeon_get_crtc_scanoutpos( |
||
6938 | serge | 88 | dev, pipe, GET_DISTANCE_TO_VBLANKSTART, |
6105 | serge | 89 | &vpos, &hpos, NULL, NULL, |
6938 | serge | 90 | &rdev->mode_info.crtcs[pipe]->base.hwmode); |
91 | } while (count != radeon_get_vblank_counter(rdev, pipe)); |
||
6105 | serge | 92 | |
93 | if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != |
||
94 | (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { |
||
95 | DRM_DEBUG_VBL("Query failed! stat %d\n", stat); |
||
96 | } |
||
97 | else { |
||
6938 | serge | 98 | DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n", |
99 | pipe, vpos); |
||
6105 | serge | 100 | |
101 | /* Bump counter if we are at >= leading edge of vblank, |
||
102 | * but before vsync where vpos would turn negative and |
||
103 | * the hw counter really increments. |
||
104 | */ |
||
105 | if (vpos >= 0) |
||
106 | count++; |
||
107 | } |
||
108 | } |
||
109 | else { |
||
110 | /* Fallback to use value as is. */ |
||
6938 | serge | 111 | count = radeon_get_vblank_counter(rdev, pipe); |
6105 | serge | 112 | DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); |
113 | } |
||
114 | |||
115 | return count; |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * radeon_enable_vblank_kms - enable vblank interrupt |
||
120 | * |
||
121 | * @dev: drm dev pointer |
||
122 | * @crtc: crtc to enable vblank interrupt for |
||
123 | * |
||
124 | * Enable the interrupt on the requested crtc (all asics). |
||
125 | * Returns 0 on success, -EINVAL on failure. |
||
126 | */ |
||
127 | int radeon_enable_vblank_kms(struct drm_device *dev, int crtc) |
||
128 | { |
||
129 | struct radeon_device *rdev = dev->dev_private; |
||
130 | unsigned long irqflags; |
||
131 | int r; |
||
132 | |||
133 | if (crtc < 0 || crtc >= rdev->num_crtc) { |
||
134 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
135 | return -EINVAL; |
||
136 | } |
||
137 | |||
138 | spin_lock_irqsave(&rdev->irq.lock, irqflags); |
||
139 | rdev->irq.crtc_vblank_int[crtc] = true; |
||
140 | r = radeon_irq_set(rdev); |
||
141 | spin_unlock_irqrestore(&rdev->irq.lock, irqflags); |
||
142 | return r; |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * radeon_disable_vblank_kms - disable vblank interrupt |
||
147 | * |
||
148 | * @dev: drm dev pointer |
||
149 | * @crtc: crtc to disable vblank interrupt for |
||
150 | * |
||
151 | * Disable the interrupt on the requested crtc (all asics). |
||
152 | */ |
||
153 | void radeon_disable_vblank_kms(struct drm_device *dev, int crtc) |
||
154 | { |
||
155 | struct radeon_device *rdev = dev->dev_private; |
||
156 | unsigned long irqflags; |
||
157 | |||
158 | if (crtc < 0 || crtc >= rdev->num_crtc) { |
||
159 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
160 | return; |
||
161 | } |
||
162 | |||
163 | spin_lock_irqsave(&rdev->irq.lock, irqflags); |
||
164 | rdev->irq.crtc_vblank_int[crtc] = false; |
||
165 | radeon_irq_set(rdev); |
||
166 | spin_unlock_irqrestore(&rdev->irq.lock, irqflags); |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * radeon_get_vblank_timestamp_kms - get vblank timestamp |
||
171 | * |
||
172 | * @dev: drm dev pointer |
||
173 | * @crtc: crtc to get the timestamp for |
||
174 | * @max_error: max error |
||
175 | * @vblank_time: time value |
||
176 | * @flags: flags passed to the driver |
||
177 | * |
||
178 | * Gets the timestamp on the requested crtc based on the |
||
179 | * scanout position. (all asics). |
||
180 | * Returns postive status flags on success, negative error on failure. |
||
181 | */ |
||
182 | int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, |
||
183 | int *max_error, |
||
184 | struct timeval *vblank_time, |
||
185 | unsigned flags) |
||
186 | { |
||
187 | struct drm_crtc *drmcrtc; |
||
188 | struct radeon_device *rdev = dev->dev_private; |
||
189 | |||
190 | if (crtc < 0 || crtc >= dev->num_crtcs) { |
||
191 | DRM_ERROR("Invalid crtc %d\n", crtc); |
||
192 | return -EINVAL; |
||
193 | } |
||
194 | |||
195 | /* Get associated drm_crtc: */ |
||
196 | drmcrtc = &rdev->mode_info.crtcs[crtc]->base; |
||
197 | if (!drmcrtc) |
||
198 | return -EINVAL; |
||
199 | |||
200 | /* Helper routine in DRM core does all the work: */ |
||
201 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, |
||
202 | vblank_time, flags, |
||
203 | &drmcrtc->hwmode); |
||
204 | }>>> |
||
205 |