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 | ||
fae7043c DA |
47 | if (!dev->irq_enabled) |
48 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | |
0a3e67a4 JB |
49 | } |
50 | ||
51 | static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state) | |
52 | { | |
53 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
54 | ||
55 | if (state) | |
56 | dev_priv->r500_disp_irq_reg |= mask; | |
57 | else | |
58 | dev_priv->r500_disp_irq_reg &= ~mask; | |
59 | ||
fae7043c DA |
60 | if (!dev->irq_enabled) |
61 | RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); | |
0a3e67a4 JB |
62 | } |
63 | ||
64 | int radeon_enable_vblank(struct drm_device *dev, int crtc) | |
65 | { | |
66 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
67 | ||
68 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | |
69 | switch (crtc) { | |
70 | case 0: | |
71 | r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1); | |
72 | break; | |
73 | case 1: | |
74 | r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1); | |
75 | break; | |
76 | default: | |
77 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
78 | crtc); | |
79 | return EINVAL; | |
80 | } | |
81 | } else { | |
82 | switch (crtc) { | |
83 | case 0: | |
84 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); | |
85 | break; | |
86 | case 1: | |
87 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); | |
88 | break; | |
89 | default: | |
90 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
91 | crtc); | |
92 | return EINVAL; | |
93 | } | |
94 | } | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | void radeon_disable_vblank(struct drm_device *dev, int crtc) | |
100 | { | |
101 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
102 | ||
103 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | |
104 | switch (crtc) { | |
105 | case 0: | |
106 | r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0); | |
107 | break; | |
108 | case 1: | |
109 | r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0); | |
110 | break; | |
111 | default: | |
112 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
113 | crtc); | |
114 | break; | |
115 | } | |
116 | } else { | |
117 | switch (crtc) { | |
118 | case 0: | |
119 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); | |
120 | break; | |
121 | case 1: | |
122 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); | |
123 | break; | |
124 | default: | |
125 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | |
126 | crtc); | |
127 | break; | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int) | |
133 | { | |
134 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS); | |
135 | u32 irq_mask = RADEON_SW_INT_TEST; | |
136 | ||
137 | *r500_disp_int = 0; | |
138 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { | |
139 | /* vbl interrupts in a different place */ | |
140 | ||
141 | if (irqs & R500_DISPLAY_INT_STATUS) { | |
142 | /* if a display interrupt */ | |
143 | u32 disp_irq; | |
144 | ||
145 | disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS); | |
146 | ||
147 | *r500_disp_int = disp_irq; | |
148 | if (disp_irq & R500_D1_VBLANK_INTERRUPT) | |
149 | RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK); | |
150 | if (disp_irq & R500_D2_VBLANK_INTERRUPT) | |
151 | RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK); | |
152 | } | |
153 | irq_mask |= R500_DISPLAY_INT_STATUS; | |
154 | } else | |
155 | irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT; | |
156 | ||
157 | irqs &= irq_mask; | |
158 | ||
6921e331 DA |
159 | if (irqs) |
160 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); | |
0a3e67a4 | 161 | |
6921e331 DA |
162 | return irqs; |
163 | } | |
164 | ||
1da177e4 LT |
165 | /* Interrupts - Used for device synchronization and flushing in the |
166 | * following circumstances: | |
167 | * | |
168 | * - Exclusive FB access with hw idle: | |
169 | * - Wait for GUI Idle (?) interrupt, then do normal flush. | |
170 | * | |
171 | * - Frame throttling, NV_fence: | |
172 | * - Drop marker irq's into command stream ahead of time. | |
173 | * - Wait on irq's with lock *not held* | |
174 | * - Check each for termination condition | |
175 | * | |
176 | * - Internally in cp_getbuffer, etc: | |
177 | * - as above, but wait with lock held??? | |
178 | * | |
179 | * NOTE: These functions are misleadingly named -- the irq's aren't | |
180 | * tied to dma at all, this is just a hangover from dri prehistory. | |
181 | */ | |
182 | ||
b5e89ed5 | 183 | irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) |
1da177e4 | 184 | { |
84b1fd10 | 185 | struct drm_device *dev = (struct drm_device *) arg; |
b5e89ed5 DA |
186 | drm_radeon_private_t *dev_priv = |
187 | (drm_radeon_private_t *) dev->dev_private; | |
188 | u32 stat; | |
0a3e67a4 | 189 | u32 r500_disp_int; |
1da177e4 LT |
190 | |
191 | /* Only consider the bits we're interested in - others could be used | |
192 | * outside the DRM | |
193 | */ | |
0a3e67a4 | 194 | stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int); |
1da177e4 LT |
195 | if (!stat) |
196 | return IRQ_NONE; | |
197 | ||
ddbee333 DA |
198 | stat &= dev_priv->irq_enable_reg; |
199 | ||
1da177e4 | 200 | /* SW interrupt */ |
0a3e67a4 | 201 | if (stat & RADEON_SW_INT_TEST) |
b5e89ed5 | 202 | DRM_WAKEUP(&dev_priv->swi_queue); |
1da177e4 LT |
203 | |
204 | /* VBLANK interrupt */ | |
0a3e67a4 JB |
205 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { |
206 | if (r500_disp_int & R500_D1_VBLANK_INTERRUPT) | |
207 | drm_handle_vblank(dev, 0); | |
208 | if (r500_disp_int & R500_D2_VBLANK_INTERRUPT) | |
209 | drm_handle_vblank(dev, 1); | |
210 | } else { | |
211 | if (stat & RADEON_CRTC_VBLANK_STAT) | |
212 | drm_handle_vblank(dev, 0); | |
213 | if (stat & RADEON_CRTC2_VBLANK_STAT) | |
214 | drm_handle_vblank(dev, 1); | |
af6061af | 215 | } |
1da177e4 LT |
216 | return IRQ_HANDLED; |
217 | } | |
218 | ||
84b1fd10 | 219 | static int radeon_emit_irq(struct drm_device * dev) |
1da177e4 LT |
220 | { |
221 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
222 | unsigned int ret; | |
223 | RING_LOCALS; | |
224 | ||
225 | atomic_inc(&dev_priv->swi_emitted); | |
226 | ret = atomic_read(&dev_priv->swi_emitted); | |
227 | ||
b5e89ed5 DA |
228 | BEGIN_RING(4); |
229 | OUT_RING_REG(RADEON_LAST_SWI_REG, ret); | |
230 | OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); | |
231 | ADVANCE_RING(); | |
232 | COMMIT_RING(); | |
1da177e4 LT |
233 | |
234 | return ret; | |
235 | } | |
236 | ||
84b1fd10 | 237 | static int radeon_wait_irq(struct drm_device * dev, int swi_nr) |
1da177e4 | 238 | { |
b5e89ed5 DA |
239 | drm_radeon_private_t *dev_priv = |
240 | (drm_radeon_private_t *) dev->dev_private; | |
1da177e4 LT |
241 | int ret = 0; |
242 | ||
b5e89ed5 DA |
243 | if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) |
244 | return 0; | |
1da177e4 LT |
245 | |
246 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | |
247 | ||
b5e89ed5 DA |
248 | DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, |
249 | RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); | |
1da177e4 LT |
250 | |
251 | return ret; | |
252 | } | |
253 | ||
0a3e67a4 | 254 | u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) |
1da177e4 | 255 | { |
0a3e67a4 JB |
256 | drm_radeon_private_t *dev_priv = dev->dev_private; |
257 | ||
b5e89ed5 | 258 | if (!dev_priv) { |
3e684eae | 259 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 260 | return -EINVAL; |
1da177e4 LT |
261 | } |
262 | ||
0a3e67a4 JB |
263 | if (crtc < 0 || crtc > 1) { |
264 | DRM_ERROR("Invalid crtc %d\n", crtc); | |
20caafa6 | 265 | return -EINVAL; |
0a3e67a4 | 266 | } |
ddbee333 | 267 | |
0a3e67a4 JB |
268 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { |
269 | if (crtc == 0) | |
270 | return RADEON_READ(R500_D1CRTC_FRAME_COUNT); | |
271 | else | |
272 | return RADEON_READ(R500_D2CRTC_FRAME_COUNT); | |
273 | } else { | |
274 | if (crtc == 0) | |
275 | return RADEON_READ(RADEON_CRTC_CRNT_FRAME); | |
276 | else | |
277 | return RADEON_READ(RADEON_CRTC2_CRNT_FRAME); | |
278 | } | |
ddbee333 DA |
279 | } |
280 | ||
1da177e4 LT |
281 | /* Needs the lock as it touches the ring. |
282 | */ | |
c153f45f | 283 | int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 284 | { |
1da177e4 | 285 | drm_radeon_private_t *dev_priv = dev->dev_private; |
c153f45f | 286 | drm_radeon_irq_emit_t *emit = data; |
1da177e4 LT |
287 | int result; |
288 | ||
6c340eac | 289 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1da177e4 | 290 | |
b5e89ed5 | 291 | if (!dev_priv) { |
3e684eae | 292 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 293 | return -EINVAL; |
1da177e4 LT |
294 | } |
295 | ||
b5e89ed5 | 296 | result = radeon_emit_irq(dev); |
1da177e4 | 297 | |
c153f45f | 298 | if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { |
b5e89ed5 | 299 | DRM_ERROR("copy_to_user\n"); |
20caafa6 | 300 | return -EFAULT; |
1da177e4 LT |
301 | } |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
1da177e4 LT |
306 | /* Doesn't need the hardware lock. |
307 | */ | |
c153f45f | 308 | int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 309 | { |
1da177e4 | 310 | drm_radeon_private_t *dev_priv = dev->dev_private; |
c153f45f | 311 | drm_radeon_irq_wait_t *irqwait = data; |
1da177e4 | 312 | |
b5e89ed5 | 313 | if (!dev_priv) { |
3e684eae | 314 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 315 | return -EINVAL; |
1da177e4 LT |
316 | } |
317 | ||
c153f45f | 318 | return radeon_wait_irq(dev, irqwait->irq_seq); |
1da177e4 LT |
319 | } |
320 | ||
1da177e4 LT |
321 | /* drm_dma.h hooks |
322 | */ | |
84b1fd10 | 323 | void radeon_driver_irq_preinstall(struct drm_device * dev) |
b5e89ed5 | 324 | { |
1da177e4 | 325 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 326 | (drm_radeon_private_t *) dev->dev_private; |
0a3e67a4 | 327 | u32 dummy; |
1da177e4 | 328 | |
b5e89ed5 | 329 | /* Disable *all* interrupts */ |
0a3e67a4 JB |
330 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) |
331 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); | |
b5e89ed5 | 332 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
1da177e4 LT |
333 | |
334 | /* Clear bits if they're already high */ | |
0a3e67a4 | 335 | radeon_acknowledge_irqs(dev_priv, &dummy); |
1da177e4 LT |
336 | } |
337 | ||
0a3e67a4 | 338 | int radeon_driver_irq_postinstall(struct drm_device *dev) |
b5e89ed5 | 339 | { |
1da177e4 | 340 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 341 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 | 342 | |
b5e89ed5 DA |
343 | atomic_set(&dev_priv->swi_emitted, 0); |
344 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | |
1da177e4 | 345 | |
0a3e67a4 JB |
346 | dev->max_vblank_count = 0x001fffff; |
347 | ||
348 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); | |
349 | ||
350 | return 0; | |
1da177e4 LT |
351 | } |
352 | ||
84b1fd10 | 353 | void radeon_driver_irq_uninstall(struct drm_device * dev) |
b5e89ed5 | 354 | { |
1da177e4 | 355 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 356 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 LT |
357 | if (!dev_priv) |
358 | return; | |
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 | } |