aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/via_irq.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-05-28 20:09:59 -0400
committerDave Airlie <airlied@redhat.com>2008-07-13 20:45:01 -0400
commitc0e09200dc0813972442e550a5905a132768e56c (patch)
treed38e635a30ff8b0a2b98b9d7f97cab1501f8209e /drivers/char/drm/via_irq.c
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
drm: reorganise drm tree to be more future proof.
With the coming of kernel based modesetting and the memory manager stuff, the everything in one directory approach was getting very ugly and starting to be unmanageable. This restructures the drm along the lines of other kernel components. It creates a drivers/gpu/drm directory and moves the hw drivers into subdirectores. It moves the includes into an include/drm, and sets up the unifdef for the userspace headers we should be exporting. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/char/drm/via_irq.c')
-rw-r--r--drivers/char/drm/via_irq.c377
1 files changed, 0 insertions, 377 deletions
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
deleted file mode 100644
index c6bb978a1106..000000000000
--- a/drivers/char/drm/via_irq.c
+++ /dev/null
@@ -1,377 +0,0 @@
1/* via_irq.c
2 *
3 * Copyright 2004 BEAM Ltd.
4 * Copyright 2002 Tungsten Graphics, Inc.
5 * Copyright 2005 Thomas Hellstrom.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * 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 * Terry Barnaby <terry1@beam.ltd.uk>
30 * Keith Whitwell <keith@tungstengraphics.com>
31 * Thomas Hellstrom <unichrome@shipmail.org>
32 *
33 * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
34 * interrupt, as well as an infrastructure to handle other interrupts of the chip.
35 * The refresh rate is also calculated for video playback sync purposes.
36 */
37
38#include "drmP.h"
39#include "drm.h"
40#include "via_drm.h"
41#include "via_drv.h"
42
43#define VIA_REG_INTERRUPT 0x200
44
45/* VIA_REG_INTERRUPT */
46#define VIA_IRQ_GLOBAL (1 << 31)
47#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
48#define VIA_IRQ_VBLANK_PENDING (1 << 3)
49#define VIA_IRQ_HQV0_ENABLE (1 << 11)
50#define VIA_IRQ_HQV1_ENABLE (1 << 25)
51#define VIA_IRQ_HQV0_PENDING (1 << 9)
52#define VIA_IRQ_HQV1_PENDING (1 << 10)
53#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20)
54#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21)
55#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22)
56#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23)
57#define VIA_IRQ_DMA0_DD_PENDING (1 << 4)
58#define VIA_IRQ_DMA0_TD_PENDING (1 << 5)
59#define VIA_IRQ_DMA1_DD_PENDING (1 << 6)
60#define VIA_IRQ_DMA1_TD_PENDING (1 << 7)
61
62
63/*
64 * Device-specific IRQs go here. This type might need to be extended with
65 * the register if there are multiple IRQ control registers.
66 * Currently we activate the HQV interrupts of Unichrome Pro group A.
67 */
68
69static maskarray_t via_pro_group_a_irqs[] = {
70 {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
71 0x00000000},
72 {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
73 0x00000000},
74 {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
75 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
76 {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
77 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
78};
79static int via_num_pro_group_a =
80 sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
81static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
82
83static maskarray_t via_unichrome_irqs[] = {
84 {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
85 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
86 {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
87 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
88};
89static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t);
90static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
91
92static unsigned time_diff(struct timeval *now, struct timeval *then)
93{
94 return (now->tv_usec >= then->tv_usec) ?
95 now->tv_usec - then->tv_usec :
96 1000000 - (then->tv_usec - now->tv_usec);
97}
98
99irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
100{
101 struct drm_device *dev = (struct drm_device *) arg;
102 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
103 u32 status;
104 int handled = 0;
105 struct timeval cur_vblank;
106 drm_via_irq_t *cur_irq = dev_priv->via_irqs;
107 int i;
108
109 status = VIA_READ(VIA_REG_INTERRUPT);
110 if (status & VIA_IRQ_VBLANK_PENDING) {
111 atomic_inc(&dev->vbl_received);
112 if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
113 do_gettimeofday(&cur_vblank);
114 if (dev_priv->last_vblank_valid) {
115 dev_priv->usec_per_vblank =
116 time_diff(&cur_vblank,
117 &dev_priv->last_vblank) >> 4;
118 }
119 dev_priv->last_vblank = cur_vblank;
120 dev_priv->last_vblank_valid = 1;
121 }
122 if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
123 DRM_DEBUG("US per vblank is: %u\n",
124 dev_priv->usec_per_vblank);
125 }
126 DRM_WAKEUP(&dev->vbl_queue);
127 drm_vbl_send_signals(dev);
128 handled = 1;
129 }
130
131 for (i = 0; i < dev_priv->num_irqs; ++i) {
132 if (status & cur_irq->pending_mask) {
133 atomic_inc(&cur_irq->irq_received);
134 DRM_WAKEUP(&cur_irq->irq_queue);
135 handled = 1;
136 if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) {
137 via_dmablit_handler(dev, 0, 1);
138 } else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) {
139 via_dmablit_handler(dev, 1, 1);
140 }
141 }
142 cur_irq++;
143 }
144
145 /* Acknowlege interrupts */
146 VIA_WRITE(VIA_REG_INTERRUPT, status);
147
148 if (handled)
149 return IRQ_HANDLED;
150 else
151 return IRQ_NONE;
152}
153
154static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
155{
156 u32 status;
157
158 if (dev_priv) {
159 /* Acknowlege interrupts */
160 status = VIA_READ(VIA_REG_INTERRUPT);
161 VIA_WRITE(VIA_REG_INTERRUPT, status |
162 dev_priv->irq_pending_mask);
163 }
164}
165
166int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
167{
168 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
169 unsigned int cur_vblank;
170 int ret = 0;
171
172 DRM_DEBUG("\n");
173 if (!dev_priv) {
174 DRM_ERROR("called with no initialization\n");
175 return -EINVAL;
176 }
177
178 viadrv_acknowledge_irqs(dev_priv);
179
180 /* Assume that the user has missed the current sequence number
181 * by about a day rather than she wants to wait for years
182 * using vertical blanks...
183 */
184
185 DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
186 (((cur_vblank = atomic_read(&dev->vbl_received)) -
187 *sequence) <= (1 << 23)));
188
189 *sequence = cur_vblank;
190 return ret;
191}
192
193static int
194via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequence,
195 unsigned int *sequence)
196{
197 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
198 unsigned int cur_irq_sequence;
199 drm_via_irq_t *cur_irq;
200 int ret = 0;
201 maskarray_t *masks;
202 int real_irq;
203
204 DRM_DEBUG("\n");
205
206 if (!dev_priv) {
207 DRM_ERROR("called with no initialization\n");
208 return -EINVAL;
209 }
210
211 if (irq >= drm_via_irq_num) {
212 DRM_ERROR("Trying to wait on unknown irq %d\n", irq);
213 return -EINVAL;
214 }
215
216 real_irq = dev_priv->irq_map[irq];
217
218 if (real_irq < 0) {
219 DRM_ERROR("Video IRQ %d not available on this hardware.\n",
220 irq);
221 return -EINVAL;
222 }
223
224 masks = dev_priv->irq_masks;
225 cur_irq = dev_priv->via_irqs + real_irq;
226
227 if (masks[real_irq][2] && !force_sequence) {
228 DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
229 ((VIA_READ(masks[irq][2]) & masks[irq][3]) ==
230 masks[irq][4]));
231 cur_irq_sequence = atomic_read(&cur_irq->irq_received);
232 } else {
233 DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
234 (((cur_irq_sequence =
235 atomic_read(&cur_irq->irq_received)) -
236 *sequence) <= (1 << 23)));
237 }
238 *sequence = cur_irq_sequence;
239 return ret;
240}
241
242/*
243 * drm_dma.h hooks
244 */
245
246void via_driver_irq_preinstall(struct drm_device * dev)
247{
248 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
249 u32 status;
250 drm_via_irq_t *cur_irq;
251 int i;
252
253 DRM_DEBUG("dev_priv: %p\n", dev_priv);
254 if (dev_priv) {
255 cur_irq = dev_priv->via_irqs;
256
257 dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
258 dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
259
260 if (dev_priv->chipset == VIA_PRO_GROUP_A ||
261 dev_priv->chipset == VIA_DX9_0) {
262 dev_priv->irq_masks = via_pro_group_a_irqs;
263 dev_priv->num_irqs = via_num_pro_group_a;
264 dev_priv->irq_map = via_irqmap_pro_group_a;
265 } else {
266 dev_priv->irq_masks = via_unichrome_irqs;
267 dev_priv->num_irqs = via_num_unichrome;
268 dev_priv->irq_map = via_irqmap_unichrome;
269 }
270
271 for (i = 0; i < dev_priv->num_irqs; ++i) {
272 atomic_set(&cur_irq->irq_received, 0);
273 cur_irq->enable_mask = dev_priv->irq_masks[i][0];
274 cur_irq->pending_mask = dev_priv->irq_masks[i][1];
275 DRM_INIT_WAITQUEUE(&cur_irq->irq_queue);
276 dev_priv->irq_enable_mask |= cur_irq->enable_mask;
277 dev_priv->irq_pending_mask |= cur_irq->pending_mask;
278 cur_irq++;
279
280 DRM_DEBUG("Initializing IRQ %d\n", i);
281 }
282
283 dev_priv->last_vblank_valid = 0;
284
285 /* Clear VSync interrupt regs */
286 status = VIA_READ(VIA_REG_INTERRUPT);
287 VIA_WRITE(VIA_REG_INTERRUPT, status &
288 ~(dev_priv->irq_enable_mask));
289
290 /* Clear bits if they're already high */
291 viadrv_acknowledge_irqs(dev_priv);
292 }
293}
294
295void via_driver_irq_postinstall(struct drm_device * dev)
296{
297 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
298 u32 status;
299
300 DRM_DEBUG("\n");
301 if (dev_priv) {
302 status = VIA_READ(VIA_REG_INTERRUPT);
303 VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
304 | dev_priv->irq_enable_mask);
305
306 /* Some magic, oh for some data sheets ! */
307
308 VIA_WRITE8(0x83d4, 0x11);
309 VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
310
311 }
312}
313
314void via_driver_irq_uninstall(struct drm_device * dev)
315{
316 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
317 u32 status;
318
319 DRM_DEBUG("\n");
320 if (dev_priv) {
321
322 /* Some more magic, oh for some data sheets ! */
323
324 VIA_WRITE8(0x83d4, 0x11);
325 VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
326
327 status = VIA_READ(VIA_REG_INTERRUPT);
328 VIA_WRITE(VIA_REG_INTERRUPT, status &
329 ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
330 }
331}
332
333int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
334{
335 drm_via_irqwait_t *irqwait = data;
336 struct timeval now;
337 int ret = 0;
338 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
339 drm_via_irq_t *cur_irq = dev_priv->via_irqs;
340 int force_sequence;
341
342 if (!dev->irq)
343 return -EINVAL;
344
345 if (irqwait->request.irq >= dev_priv->num_irqs) {
346 DRM_ERROR("Trying to wait on unknown irq %d\n",
347 irqwait->request.irq);
348 return -EINVAL;
349 }
350
351 cur_irq += irqwait->request.irq;
352
353 switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
354 case VIA_IRQ_RELATIVE:
355 irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
356 irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
357 case VIA_IRQ_ABSOLUTE:
358 break;
359 default:
360 return -EINVAL;
361 }
362
363 if (irqwait->request.type & VIA_IRQ_SIGNAL) {
364 DRM_ERROR("Signals on Via IRQs not implemented yet.\n");
365 return -EINVAL;
366 }
367
368 force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
369
370 ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
371 &irqwait->request.sequence);
372 do_gettimeofday(&now);
373 irqwait->reply.tval_sec = now.tv_sec;
374 irqwait->reply.tval_usec = now.tv_usec;
375
376 return ret;
377}