aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/radeon_irq.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2008-04-22 02:03:07 -0400
committerDave Airlie <airlied@linux.ie>2008-04-26 04:01:07 -0400
commitac741ab71bb39e6977694ac0cc26678d8673cda4 (patch)
treef82e08399a0da5accba930444744b269479185dd /drivers/char/drm/radeon_irq.c
parent2c14f28be2a3f2a2e9861b156d64fbe2bc7000c3 (diff)
drm/vbl rework: rework how the drm deals with vblank.
Other Authors: Michel Dänzer <michel@tungstengraphics.com> mga: Ian Romanick <idr@us.ibm.com> via: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> This re-works the DRM internals to provide a better interface for drivers to expose vblank on multiple crtcs. It also includes work done by Michel on making i915 triple buffering and pageflipping work properly. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/char/drm/radeon_irq.c')
-rw-r--r--drivers/char/drm/radeon_irq.c171
1 files changed, 83 insertions, 88 deletions
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index 009af3814b6f..507d6b747a13 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -35,12 +35,61 @@
35#include "radeon_drm.h" 35#include "radeon_drm.h"
36#include "radeon_drv.h" 36#include "radeon_drv.h"
37 37
38static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, 38static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
39 u32 mask)
40{ 39{
41 u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; 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
50int radeon_enable_vblank(struct drm_device *dev, int crtc)
51{
52 switch (crtc) {
53 case 0:
54 radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
55 break;
56 case 1:
57 radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
58 break;
59 default:
60 DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
61 crtc);
62 return EINVAL;
63 }
64
65 return 0;
66}
67
68void radeon_disable_vblank(struct drm_device *dev, int crtc)
69{
70 switch (crtc) {
71 case 0:
72 radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
73 break;
74 case 1:
75 radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
76 break;
77 default:
78 DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
79 crtc);
80 break;
81 }
82}
83
84static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)
85{
86 u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
87 (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
88 RADEON_CRTC2_VBLANK_STAT);
89
42 if (irqs) 90 if (irqs)
43 RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); 91 RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
92
44 return irqs; 93 return irqs;
45} 94}
46 95
@@ -72,39 +121,21 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
72 /* Only consider the bits we're interested in - others could be used 121 /* Only consider the bits we're interested in - others could be used
73 * outside the DRM 122 * outside the DRM
74 */ 123 */
75 stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | 124 stat = radeon_acknowledge_irqs(dev_priv);
76 RADEON_CRTC_VBLANK_STAT |
77 RADEON_CRTC2_VBLANK_STAT));
78 if (!stat) 125 if (!stat)
79 return IRQ_NONE; 126 return IRQ_NONE;
80 127
81 stat &= dev_priv->irq_enable_reg; 128 stat &= dev_priv->irq_enable_reg;
82 129
83 /* SW interrupt */ 130 /* SW interrupt */
84 if (stat & RADEON_SW_INT_TEST) { 131 if (stat & RADEON_SW_INT_TEST)
85 DRM_WAKEUP(&dev_priv->swi_queue); 132 DRM_WAKEUP(&dev_priv->swi_queue);
86 }
87 133
88 /* VBLANK interrupt */ 134 /* VBLANK interrupt */
89 if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) { 135 if (stat & RADEON_CRTC_VBLANK_STAT)
90 int vblank_crtc = dev_priv->vblank_crtc; 136 drm_handle_vblank(dev, 0);
91 137 if (stat & RADEON_CRTC2_VBLANK_STAT)
92 if ((vblank_crtc & 138 drm_handle_vblank(dev, 1);
93 (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
94 (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
95 if (stat & RADEON_CRTC_VBLANK_STAT)
96 atomic_inc(&dev->vbl_received);
97 if (stat & RADEON_CRTC2_VBLANK_STAT)
98 atomic_inc(&dev->vbl_received2);
99 } else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
100 (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
101 ((stat & RADEON_CRTC2_VBLANK_STAT) &&
102 (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
103 atomic_inc(&dev->vbl_received);
104
105 DRM_WAKEUP(&dev->vbl_queue);
106 drm_vbl_send_signals(dev);
107 }
108 139
109 return IRQ_HANDLED; 140 return IRQ_HANDLED;
110} 141}
@@ -144,54 +175,27 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
144 return ret; 175 return ret;
145} 176}
146 177
147static int radeon_driver_vblank_do_wait(struct drm_device * dev, 178u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
148 unsigned int *sequence, int crtc)
149{ 179{
150 drm_radeon_private_t *dev_priv = 180 drm_radeon_private_t *dev_priv = dev->dev_private;
151 (drm_radeon_private_t *) dev->dev_private; 181 u32 crtc_cnt_reg, crtc_status_reg;
152 unsigned int cur_vblank; 182
153 int ret = 0;
154 int ack = 0;
155 atomic_t *counter;
156 if (!dev_priv) { 183 if (!dev_priv) {
157 DRM_ERROR("called with no initialization\n"); 184 DRM_ERROR("called with no initialization\n");
158 return -EINVAL; 185 return -EINVAL;
159 } 186 }
160 187
161 if (crtc == DRM_RADEON_VBLANK_CRTC1) { 188 if (crtc == 0) {
162 counter = &dev->vbl_received; 189 crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
163 ack |= RADEON_CRTC_VBLANK_STAT; 190 crtc_status_reg = RADEON_CRTC_STATUS;
164 } else if (crtc == DRM_RADEON_VBLANK_CRTC2) { 191 } else if (crtc == 1) {
165 counter = &dev->vbl_received2; 192 crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
166 ack |= RADEON_CRTC2_VBLANK_STAT; 193 crtc_status_reg = RADEON_CRTC2_STATUS;
167 } else 194 } else {
168 return -EINVAL; 195 return -EINVAL;
196 }
169 197
170 radeon_acknowledge_irqs(dev_priv, ack); 198 return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
171
172 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
173
174 /* Assume that the user has missed the current sequence number
175 * by about a day rather than she wants to wait for years
176 * using vertical blanks...
177 */
178 DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
179 (((cur_vblank = atomic_read(counter))
180 - *sequence) <= (1 << 23)));
181
182 *sequence = cur_vblank;
183
184 return ret;
185}
186
187int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
188{
189 return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
190}
191
192int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
193{
194 return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
195} 199}
196 200
197/* Needs the lock as it touches the ring. 201/* Needs the lock as it touches the ring.
@@ -234,21 +238,6 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
234 return radeon_wait_irq(dev, irqwait->irq_seq); 238 return radeon_wait_irq(dev, irqwait->irq_seq);
235} 239}
236 240
237static void radeon_enable_interrupt(struct drm_device *dev)
238{
239 drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
240
241 dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
242 if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
243 dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
244
245 if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
246 dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
247
248 RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
249 dev_priv->irq_enabled = 1;
250}
251
252/* drm_dma.h hooks 241/* drm_dma.h hooks
253*/ 242*/
254void radeon_driver_irq_preinstall(struct drm_device * dev) 243void radeon_driver_irq_preinstall(struct drm_device * dev)
@@ -260,20 +249,27 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
260 RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); 249 RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
261 250
262 /* Clear bits if they're already high */ 251 /* Clear bits if they're already high */
263 radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | 252 radeon_acknowledge_irqs(dev_priv);
264 RADEON_CRTC_VBLANK_STAT |
265 RADEON_CRTC2_VBLANK_STAT));
266} 253}
267 254
268void radeon_driver_irq_postinstall(struct drm_device * dev) 255int radeon_driver_irq_postinstall(struct drm_device * dev)
269{ 256{
270 drm_radeon_private_t *dev_priv = 257 drm_radeon_private_t *dev_priv =
271 (drm_radeon_private_t *) dev->dev_private; 258 (drm_radeon_private_t *) dev->dev_private;
259 int ret;
272 260
273 atomic_set(&dev_priv->swi_emitted, 0); 261 atomic_set(&dev_priv->swi_emitted, 0);
274 DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); 262 DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
275 263
276 radeon_enable_interrupt(dev); 264 ret = drm_vblank_init(dev, 2);
265 if (ret)
266 return ret;
267
268 dev->max_vblank_count = 0x001fffff;
269
270 radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
271
272 return 0;
277} 273}
278 274
279void radeon_driver_irq_uninstall(struct drm_device * dev) 275void radeon_driver_irq_uninstall(struct drm_device * dev)
@@ -315,6 +311,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
315 return -EINVAL; 311 return -EINVAL;
316 } 312 }
317 dev_priv->vblank_crtc = (unsigned int)value; 313 dev_priv->vblank_crtc = (unsigned int)value;
318 radeon_enable_interrupt(dev);
319 return 0; 314 return 0;
320} 315}