Commit | Line | Data |
---|---|---|
94bb598e DA |
1 | /* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */ |
2 | /* | |
1da177e4 | 3 | * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. |
b5e89ed5 | 4 | * |
1da177e4 LT |
5 | * The Weather Channel (TM) funded Tungsten Graphics to develop the |
6 | * initial release of the Radeon 8500 driver under the XFree86 license. | |
7 | * This notice must be preserved. | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | |
10 | * copy of this software and associated documentation files (the "Software"), | |
11 | * to deal in the Software without restriction, including without limitation | |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | * and/or sell copies of the Software, and to permit persons to whom the | |
14 | * Software is furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice (including the next | |
17 | * paragraph) shall be included in all copies or substantial portions of the | |
18 | * Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
23 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
24 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
25 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
26 | * DEALINGS IN THE SOFTWARE. | |
27 | * | |
28 | * Authors: | |
29 | * Keith Whitwell <keith@tungstengraphics.com> | |
0a3e67a4 | 30 | * Michel D�zer <michel@daenzer.net> |
1da177e4 LT |
31 | */ |
32 | ||
33 | #include "drmP.h" | |
34 | #include "drm.h" | |
35 | #include "radeon_drm.h" | |
36 | #include "radeon_drv.h" | |
37 | ||
0a3e67a4 | 38 | void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) |
6921e331 | 39 | { |
0a3e67a4 JB |
40 | drm_radeon_private_t *dev_priv = dev->dev_private; |
41 | ||
42 | if (state) | |
43 | dev_priv->irq_enable_reg |= mask; | |
44 | else | |
45 | dev_priv->irq_enable_reg &= ~mask; | |
46 | ||
47 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | |
48 | } | |
49 | ||
50 | static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state) | |
51 | { | |
52 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
53 | ||
54 | if (state) | |
55 | dev_priv->r500_disp_irq_reg |= mask; | |
56 | else | |
57 | dev_priv->r500_disp_irq_reg &= ~mask; | |
58 | ||
59 | RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); | |
60 | } | |
61 | ||
62 | int radeon_enable_vblank(struct drm_device *dev, int crtc) | |
63 | { | |
64 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
65 | ||
66 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | |
67 | switch (crtc) { | |
68 | case 0: | |
69 | r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1); | |
70 | break; | |
71 | case 1: | |
72 | r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1); | |
73 | break; | |
74 | default: | |
75 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
76 | crtc); | |
77 | return EINVAL; | |
78 | } | |
79 | } else { | |
80 | switch (crtc) { | |
81 | case 0: | |
82 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); | |
83 | break; | |
84 | case 1: | |
85 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); | |
86 | break; | |
87 | default: | |
88 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
89 | crtc); | |
90 | return EINVAL; | |
91 | } | |
92 | } | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | void radeon_disable_vblank(struct drm_device *dev, int crtc) | |
98 | { | |
99 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
100 | ||
101 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | |
102 | switch (crtc) { | |
103 | case 0: | |
104 | r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0); | |
105 | break; | |
106 | case 1: | |
107 | r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0); | |
108 | break; | |
109 | default: | |
110 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
111 | crtc); | |
112 | break; | |
113 | } | |
114 | } else { | |
115 | switch (crtc) { | |
116 | case 0: | |
117 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); | |
118 | break; | |
119 | case 1: | |
120 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); | |
121 | break; | |
122 | default: | |
123 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
124 | crtc); | |
125 | break; | |
126 | } | |
127 | } | |
128 | } | |
129 | ||
130 | static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int) | |
131 | { | |
132 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS); | |
133 | u32 irq_mask = RADEON_SW_INT_TEST; | |
134 | ||
135 | *r500_disp_int = 0; | |
136 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | |
137 | /* vbl interrupts in a different place */ | |
138 | ||
139 | if (irqs & R500_DISPLAY_INT_STATUS) { | |
140 | /* if a display interrupt */ | |
141 | u32 disp_irq; | |
142 | ||
143 | disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS); | |
144 | ||
145 | *r500_disp_int = disp_irq; | |
146 | if (disp_irq & R500_D1_VBLANK_INTERRUPT) | |
147 | RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK); | |
148 | if (disp_irq & R500_D2_VBLANK_INTERRUPT) | |
149 | RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK); | |
150 | } | |
151 | irq_mask |= R500_DISPLAY_INT_STATUS; | |
152 | } else | |
153 | irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT; | |
154 | ||
155 | irqs &= irq_mask; | |
156 | ||
6921e331 DA |
157 | if (irqs) |
158 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); | |
0a3e67a4 | 159 | |
6921e331 DA |
160 | return irqs; |
161 | } | |
162 | ||
1da177e4 LT |
163 | /* Interrupts - Used for device synchronization and flushing in the |
164 | * following circumstances: | |
165 | * | |
166 | * - Exclusive FB access with hw idle: | |
167 | * - Wait for GUI Idle (?) interrupt, then do normal flush. | |
168 | * | |
169 | * - Frame throttling, NV_fence: | |
170 | * - Drop marker irq's into command stream ahead of time. | |
171 | * - Wait on irq's with lock *not held* | |
172 | * - Check each for termination condition | |
173 | * | |
174 | * - Internally in cp_getbuffer, etc: | |
175 | * - as above, but wait with lock held??? | |
176 | * | |
177 | * NOTE: These functions are misleadingly named -- the irq's aren't | |
178 | * tied to dma at all, this is just a hangover from dri prehistory. | |
179 | */ | |
180 | ||
b5e89ed5 | 181 | irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) |
1da177e4 | 182 | { |
84b1fd10 | 183 | struct drm_device *dev = (struct drm_device *) arg; |
b5e89ed5 DA |
184 | drm_radeon_private_t *dev_priv = |
185 | (drm_radeon_private_t *) dev->dev_private; | |
186 | u32 stat; | |
0a3e67a4 | 187 | u32 r500_disp_int; |
1da177e4 LT |
188 | |
189 | /* Only consider the bits we're interested in - others could be used | |
190 | * outside the DRM | |
191 | */ | |
0a3e67a4 | 192 | stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int); |
1da177e4 LT |
193 | if (!stat) |
194 | return IRQ_NONE; | |
195 | ||
ddbee333 DA |
196 | stat &= dev_priv->irq_enable_reg; |
197 | ||
1da177e4 | 198 | /* SW interrupt */ |
0a3e67a4 | 199 | if (stat & RADEON_SW_INT_TEST) |
b5e89ed5 | 200 | DRM_WAKEUP(&dev_priv->swi_queue); |
1da177e4 LT |
201 | |
202 | /* VBLANK interrupt */ | |
0a3e67a4 JB |
203 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { |
204 | if (r500_disp_int & R500_D1_VBLANK_INTERRUPT) | |
205 | drm_handle_vblank(dev, 0); | |
206 | if (r500_disp_int & R500_D2_VBLANK_INTERRUPT) | |
207 | drm_handle_vblank(dev, 1); | |
208 | } else { | |
209 | if (stat & RADEON_CRTC_VBLANK_STAT) | |
210 | drm_handle_vblank(dev, 0); | |
211 | if (stat & RADEON_CRTC2_VBLANK_STAT) | |
212 | drm_handle_vblank(dev, 1); | |
af6061af | 213 | } |
1da177e4 LT |
214 | return IRQ_HANDLED; |
215 | } | |
216 | ||
84b1fd10 | 217 | static int radeon_emit_irq(struct drm_device * dev) |
1da177e4 LT |
218 | { |
219 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
220 | unsigned int ret; | |
221 | RING_LOCALS; | |
222 | ||
223 | atomic_inc(&dev_priv->swi_emitted); | |
224 | ret = atomic_read(&dev_priv->swi_emitted); | |
225 | ||
b5e89ed5 DA |
226 | BEGIN_RING(4); |
227 | OUT_RING_REG(RADEON_LAST_SWI_REG, ret); | |
228 | OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); | |
229 | ADVANCE_RING(); | |
230 | COMMIT_RING(); | |
1da177e4 LT |
231 | |
232 | return ret; | |
233 | } | |
234 | ||
84b1fd10 | 235 | static int radeon_wait_irq(struct drm_device * dev, int swi_nr) |
1da177e4 | 236 | { |
b5e89ed5 DA |
237 | drm_radeon_private_t *dev_priv = |
238 | (drm_radeon_private_t *) dev->dev_private; | |
1da177e4 LT |
239 | int ret = 0; |
240 | ||
b5e89ed5 DA |
241 | if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) |
242 | return 0; | |
1da177e4 LT |
243 | |
244 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | |
245 | ||
b5e89ed5 DA |
246 | DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, |
247 | RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); | |
1da177e4 LT |
248 | |
249 | return ret; | |
250 | } | |
251 | ||
0a3e67a4 | 252 | u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) |
1da177e4 | 253 | { |
0a3e67a4 JB |
254 | drm_radeon_private_t *dev_priv = dev->dev_private; |
255 | ||
b5e89ed5 | 256 | if (!dev_priv) { |
3e684eae | 257 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 258 | return -EINVAL; |
1da177e4 LT |
259 | } |
260 | ||
0a3e67a4 JB |
261 | if (crtc < 0 || crtc > 1) { |
262 | DRM_ERROR("Invalid crtc %d\n", crtc); | |
20caafa6 | 263 | return -EINVAL; |
0a3e67a4 | 264 | } |
ddbee333 | 265 | |
0a3e67a4 JB |
266 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { |
267 | if (crtc == 0) | |
268 | return RADEON_READ(R500_D1CRTC_FRAME_COUNT); | |
269 | else | |
270 | return RADEON_READ(R500_D2CRTC_FRAME_COUNT); | |
271 | } else { | |
272 | if (crtc == 0) | |
273 | return RADEON_READ(RADEON_CRTC_CRNT_FRAME); | |
274 | else | |
275 | return RADEON_READ(RADEON_CRTC2_CRNT_FRAME); | |
276 | } | |
ddbee333 DA |
277 | } |
278 | ||
1da177e4 LT |
279 | /* Needs the lock as it touches the ring. |
280 | */ | |
c153f45f | 281 | int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 282 | { |
1da177e4 | 283 | drm_radeon_private_t *dev_priv = dev->dev_private; |
c153f45f | 284 | drm_radeon_irq_emit_t *emit = data; |
1da177e4 LT |
285 | int result; |
286 | ||
6c340eac | 287 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 288 | |
b5e89ed5 | 289 | if (!dev_priv) { |
3e684eae | 290 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 291 | return -EINVAL; |
1da177e4 LT |
292 | } |
293 | ||
b5e89ed5 | 294 | result = radeon_emit_irq(dev); |
1da177e4 | 295 | |
c153f45f | 296 | if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { |
b5e89ed5 | 297 | DRM_ERROR("copy_to_user\n"); |
20caafa6 | 298 | return -EFAULT; |
1da177e4 LT |
299 | } |
300 | ||
301 | return 0; | |
302 | } | |
303 | ||
1da177e4 LT |
304 | /* Doesn't need the hardware lock. |
305 | */ | |
c153f45f | 306 | int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 307 | { |
1da177e4 | 308 | drm_radeon_private_t *dev_priv = dev->dev_private; |
c153f45f | 309 | drm_radeon_irq_wait_t *irqwait = data; |
1da177e4 | 310 | |
b5e89ed5 | 311 | if (!dev_priv) { |
3e684eae | 312 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 313 | return -EINVAL; |
1da177e4 LT |
314 | } |
315 | ||
c153f45f | 316 | return radeon_wait_irq(dev, irqwait->irq_seq); |
1da177e4 LT |
317 | } |
318 | ||
1da177e4 LT |
319 | /* drm_dma.h hooks |
320 | */ | |
84b1fd10 | 321 | void radeon_driver_irq_preinstall(struct drm_device * dev) |
b5e89ed5 | 322 | { |
1da177e4 | 323 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 324 | (drm_radeon_private_t *) dev->dev_private; |
0a3e67a4 | 325 | u32 dummy; |
1da177e4 | 326 | |
b5e89ed5 | 327 | /* Disable *all* interrupts */ |
0a3e67a4 JB |
328 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) |
329 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); | |
b5e89ed5 | 330 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
1da177e4 LT |
331 | |
332 | /* Clear bits if they're already high */ | |
0a3e67a4 | 333 | radeon_acknowledge_irqs(dev_priv, &dummy); |
1da177e4 LT |
334 | } |
335 | ||
0a3e67a4 | 336 | int radeon_driver_irq_postinstall(struct drm_device *dev) |
b5e89ed5 | 337 | { |
1da177e4 | 338 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 339 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 | 340 | |
b5e89ed5 DA |
341 | atomic_set(&dev_priv->swi_emitted, 0); |
342 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | |
1da177e4 | 343 | |
0a3e67a4 JB |
344 | dev->max_vblank_count = 0x001fffff; |
345 | ||
346 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); | |
347 | ||
348 | return 0; | |
1da177e4 LT |
349 | } |
350 | ||
84b1fd10 | 351 | void radeon_driver_irq_uninstall(struct drm_device * dev) |
b5e89ed5 | 352 | { |
1da177e4 | 353 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 354 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 LT |
355 | if (!dev_priv) |
356 | return; | |
357 | ||
ddbee333 DA |
358 | dev_priv->irq_enabled = 0; |
359 | ||
0a3e67a4 JB |
360 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) |
361 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); | |
1da177e4 | 362 | /* Disable *all* interrupts */ |
b5e89ed5 | 363 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
1da177e4 | 364 | } |
ddbee333 DA |
365 | |
366 | ||
84b1fd10 | 367 | int radeon_vblank_crtc_get(struct drm_device *dev) |
ddbee333 DA |
368 | { |
369 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
ddbee333 | 370 | |
0a3e67a4 | 371 | return dev_priv->vblank_crtc; |
ddbee333 DA |
372 | } |
373 | ||
84b1fd10 | 374 | int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) |
ddbee333 DA |
375 | { |
376 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
377 | if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | |
378 | DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value); | |
20caafa6 | 379 | return -EINVAL; |
ddbee333 DA |
380 | } |
381 | dev_priv->vblank_crtc = (unsigned int)value; | |
ddbee333 DA |
382 | return 0; |
383 | } |