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