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