]>
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 | ||
077ebed5 | 47 | if (dev->irq_enabled) |
fae7043c | 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 | ||
077ebed5 | 60 | if (dev->irq_enabled) |
fae7043c | 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 | ||
800b6995 | 68 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { |
0a3e67a4 JB |
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); | |
21e2eae4 | 79 | return -EINVAL; |
0a3e67a4 JB |
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); | |
21e2eae4 | 92 | return -EINVAL; |
0a3e67a4 JB |
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 | ||
800b6995 | 103 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { |
0a3e67a4 JB |
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; | |
800b6995 | 138 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { |
0a3e67a4 JB |
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 | 190 | |
b15591f3 AD |
191 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) |
192 | return IRQ_NONE; | |
193 | ||
1da177e4 LT |
194 | /* Only consider the bits we're interested in - others could be used |
195 | * outside the DRM | |
196 | */ | |
0a3e67a4 | 197 | stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int); |
1da177e4 LT |
198 | if (!stat) |
199 | return IRQ_NONE; | |
200 | ||
ddbee333 DA |
201 | stat &= dev_priv->irq_enable_reg; |
202 | ||
1da177e4 | 203 | /* SW interrupt */ |
0a3e67a4 | 204 | if (stat & RADEON_SW_INT_TEST) |
b5e89ed5 | 205 | DRM_WAKEUP(&dev_priv->swi_queue); |
1da177e4 LT |
206 | |
207 | /* VBLANK interrupt */ | |
800b6995 | 208 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { |
0a3e67a4 JB |
209 | if (r500_disp_int & R500_D1_VBLANK_INTERRUPT) |
210 | drm_handle_vblank(dev, 0); | |
211 | if (r500_disp_int & R500_D2_VBLANK_INTERRUPT) | |
212 | drm_handle_vblank(dev, 1); | |
213 | } else { | |
214 | if (stat & RADEON_CRTC_VBLANK_STAT) | |
215 | drm_handle_vblank(dev, 0); | |
216 | if (stat & RADEON_CRTC2_VBLANK_STAT) | |
217 | drm_handle_vblank(dev, 1); | |
af6061af | 218 | } |
1da177e4 LT |
219 | return IRQ_HANDLED; |
220 | } | |
221 | ||
84b1fd10 | 222 | static int radeon_emit_irq(struct drm_device * dev) |
1da177e4 LT |
223 | { |
224 | drm_radeon_private_t *dev_priv = dev->dev_private; | |
225 | unsigned int ret; | |
226 | RING_LOCALS; | |
227 | ||
228 | atomic_inc(&dev_priv->swi_emitted); | |
229 | ret = atomic_read(&dev_priv->swi_emitted); | |
230 | ||
b5e89ed5 DA |
231 | BEGIN_RING(4); |
232 | OUT_RING_REG(RADEON_LAST_SWI_REG, ret); | |
233 | OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); | |
234 | ADVANCE_RING(); | |
235 | COMMIT_RING(); | |
1da177e4 LT |
236 | |
237 | return ret; | |
238 | } | |
239 | ||
84b1fd10 | 240 | static int radeon_wait_irq(struct drm_device * dev, int swi_nr) |
1da177e4 | 241 | { |
b5e89ed5 DA |
242 | drm_radeon_private_t *dev_priv = |
243 | (drm_radeon_private_t *) dev->dev_private; | |
1da177e4 LT |
244 | int ret = 0; |
245 | ||
b5e89ed5 DA |
246 | if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) |
247 | return 0; | |
1da177e4 LT |
248 | |
249 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | |
250 | ||
b5e89ed5 DA |
251 | DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, |
252 | RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); | |
1da177e4 LT |
253 | |
254 | return ret; | |
255 | } | |
256 | ||
0a3e67a4 | 257 | u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) |
1da177e4 | 258 | { |
0a3e67a4 JB |
259 | drm_radeon_private_t *dev_priv = dev->dev_private; |
260 | ||
b5e89ed5 | 261 | if (!dev_priv) { |
3e684eae | 262 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 263 | return -EINVAL; |
1da177e4 LT |
264 | } |
265 | ||
0a3e67a4 JB |
266 | if (crtc < 0 || crtc > 1) { |
267 | DRM_ERROR("Invalid crtc %d\n", crtc); | |
20caafa6 | 268 | return -EINVAL; |
0a3e67a4 | 269 | } |
ddbee333 | 270 | |
800b6995 | 271 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { |
0a3e67a4 JB |
272 | if (crtc == 0) |
273 | return RADEON_READ(R500_D1CRTC_FRAME_COUNT); | |
274 | else | |
275 | return RADEON_READ(R500_D2CRTC_FRAME_COUNT); | |
276 | } else { | |
277 | if (crtc == 0) | |
278 | return RADEON_READ(RADEON_CRTC_CRNT_FRAME); | |
279 | else | |
280 | return RADEON_READ(RADEON_CRTC2_CRNT_FRAME); | |
281 | } | |
ddbee333 DA |
282 | } |
283 | ||
1da177e4 LT |
284 | /* Needs the lock as it touches the ring. |
285 | */ | |
c153f45f | 286 | int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 287 | { |
1da177e4 | 288 | drm_radeon_private_t *dev_priv = dev->dev_private; |
c153f45f | 289 | drm_radeon_irq_emit_t *emit = data; |
1da177e4 LT |
290 | int result; |
291 | ||
b5e89ed5 | 292 | if (!dev_priv) { |
3e684eae | 293 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 294 | return -EINVAL; |
1da177e4 LT |
295 | } |
296 | ||
65aa2f4e DJ |
297 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) |
298 | return -EINVAL; | |
299 | ||
300 | LOCK_TEST_WITH_RETURN(dev, file_priv); | |
301 | ||
b5e89ed5 | 302 | result = radeon_emit_irq(dev); |
1da177e4 | 303 | |
c153f45f | 304 | if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { |
b5e89ed5 | 305 | DRM_ERROR("copy_to_user\n"); |
20caafa6 | 306 | return -EFAULT; |
1da177e4 LT |
307 | } |
308 | ||
309 | return 0; | |
310 | } | |
311 | ||
1da177e4 LT |
312 | /* Doesn't need the hardware lock. |
313 | */ | |
c153f45f | 314 | int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1da177e4 | 315 | { |
1da177e4 | 316 | drm_radeon_private_t *dev_priv = dev->dev_private; |
c153f45f | 317 | drm_radeon_irq_wait_t *irqwait = data; |
1da177e4 | 318 | |
b5e89ed5 | 319 | if (!dev_priv) { |
3e684eae | 320 | DRM_ERROR("called with no initialization\n"); |
20caafa6 | 321 | return -EINVAL; |
1da177e4 LT |
322 | } |
323 | ||
b15591f3 AD |
324 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) |
325 | return -EINVAL; | |
326 | ||
c153f45f | 327 | return radeon_wait_irq(dev, irqwait->irq_seq); |
1da177e4 LT |
328 | } |
329 | ||
1da177e4 LT |
330 | /* drm_dma.h hooks |
331 | */ | |
84b1fd10 | 332 | void radeon_driver_irq_preinstall(struct drm_device * dev) |
b5e89ed5 | 333 | { |
1da177e4 | 334 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 335 | (drm_radeon_private_t *) dev->dev_private; |
0a3e67a4 | 336 | u32 dummy; |
1da177e4 | 337 | |
b15591f3 AD |
338 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) |
339 | return; | |
340 | ||
b5e89ed5 | 341 | /* Disable *all* interrupts */ |
800b6995 | 342 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) |
0a3e67a4 | 343 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); |
b5e89ed5 | 344 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
1da177e4 LT |
345 | |
346 | /* Clear bits if they're already high */ | |
0a3e67a4 | 347 | radeon_acknowledge_irqs(dev_priv, &dummy); |
1da177e4 LT |
348 | } |
349 | ||
0a3e67a4 | 350 | int radeon_driver_irq_postinstall(struct drm_device *dev) |
b5e89ed5 | 351 | { |
1da177e4 | 352 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 353 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 | 354 | |
b5e89ed5 DA |
355 | atomic_set(&dev_priv->swi_emitted, 0); |
356 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | |
1da177e4 | 357 | |
0a3e67a4 JB |
358 | dev->max_vblank_count = 0x001fffff; |
359 | ||
b15591f3 AD |
360 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) |
361 | return 0; | |
362 | ||
0a3e67a4 JB |
363 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); |
364 | ||
365 | return 0; | |
1da177e4 LT |
366 | } |
367 | ||
84b1fd10 | 368 | void radeon_driver_irq_uninstall(struct drm_device * dev) |
b5e89ed5 | 369 | { |
1da177e4 | 370 | drm_radeon_private_t *dev_priv = |
b5e89ed5 | 371 | (drm_radeon_private_t *) dev->dev_private; |
1da177e4 LT |
372 | if (!dev_priv) |
373 | return; | |
374 | ||
b15591f3 AD |
375 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) |
376 | return; | |
377 | ||
800b6995 | 378 | if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) |
0a3e67a4 | 379 | RADEON_WRITE(R500_DxMODE_INT_MASK, 0); |
1da177e4 | 380 | /* Disable *all* interrupts */ |
b5e89ed5 | 381 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
1da177e4 | 382 | } |
ddbee333 DA |
383 | |
384 | ||
84b1fd10 | 385 | int radeon_vblank_crtc_get(struct drm_device *dev) |
ddbee333 DA |
386 | { |
387 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
ddbee333 | 388 | |
0a3e67a4 | 389 | return dev_priv->vblank_crtc; |
ddbee333 DA |
390 | } |
391 | ||
84b1fd10 | 392 | int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) |
ddbee333 DA |
393 | { |
394 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | |
395 | if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | |
396 | DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value); | |
20caafa6 | 397 | return -EINVAL; |
ddbee333 DA |
398 | } |
399 | dev_priv->vblank_crtc = (unsigned int)value; | |
ddbee333 DA |
400 | return 0; |
401 | } |