summaryrefslogtreecommitdiff
path: root/shared-core
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core')
-rw-r--r--shared-core/drm.h15
-rw-r--r--shared-core/radeon_drv.h15
-rw-r--r--shared-core/radeon_irq.c102
3 files changed, 96 insertions, 36 deletions
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 376568e0..f26d4442 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -345,6 +345,19 @@ typedef struct drm_irq_busid {
int funcnum;
} drm_irq_busid_t;
+typedef enum {
+ _DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
+ _DRM_VBLANK_RELATIVE = 0x1 /* Wait for given number of vblanks */
+} drm_vblank_seq_type_t;
+
+typedef struct drm_radeon_vbl_wait {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+} drm_wait_vblank_t;
+
+
typedef struct drm_agp_mode {
unsigned long mode;
} drm_agp_mode_t;
@@ -439,6 +452,8 @@ typedef struct drm_scatter_gather {
#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t)
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+
/* Device specfic ioctls should only be in their respective headers
* The device specific ioctl range is 0x40 to 0x79. */
#define DRM_COMMAND_BASE 0x40
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index efe3020c..5c43ebc6 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -139,9 +139,10 @@ typedef struct drm_radeon_private {
struct mem_block *agp_heap;
struct mem_block *fb_heap;
- wait_queue_head_t irq_queue;
- atomic_t irq_received;
- atomic_t irq_emitted;
+ /* SW interrupt */
+ wait_queue_head_t swi_queue;
+ atomic_t swi_received;
+ atomic_t swi_emitted;
} drm_radeon_private_t;
@@ -187,12 +188,14 @@ extern int radeon_mem_init_heap( DRM_IOCTL_ARGS );
extern void radeon_mem_takedown( struct mem_block **heap );
extern void radeon_mem_release( struct mem_block *heap );
+ /* radeon_irq.c */
extern int radeon_irq_emit( DRM_IOCTL_ARGS );
extern int radeon_irq_wait( DRM_IOCTL_ARGS );
extern int radeon_emit_and_wait_irq(drm_device_t *dev);
-extern int radeon_wait_irq(drm_device_t *dev, int irq_nr);
+extern int radeon_wait_irq(drm_device_t *dev, int swi_nr);
extern int radeon_emit_irq(drm_device_t *dev);
+extern int radeon_vblank_wait(drm_device_t *dev, unsigned int *vbl_seq);
/* Flags for stats.boxes
@@ -271,11 +274,15 @@ extern int radeon_emit_irq(drm_device_t *dev);
#define RADEON_GEN_INT_CNTL 0x0040
+# define RADEON_CRTC_VBLANK_MASK (1 << 0)
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
# define RADEON_SW_INT_ENABLE (1 << 25)
#define RADEON_GEN_INT_STATUS 0x0044
+# define RADEON_CRTC_VBLANK_STAT (1 << 0)
+# define RADEON_CRTC_VBLANK_STAT_ACK (1 << 0)
# define RADEON_GUI_IDLE_INT_TEST_ACK (1 << 19)
+# define RADEON_SW_INT_TEST (1 << 25)
# define RADEON_SW_INT_TEST_ACK (1 << 25)
# define RADEON_SW_INT_FIRE (1 << 26)
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 11609393..7b170389 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -1,4 +1,4 @@
-/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*-
+/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-
*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
@@ -58,46 +58,47 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
drm_device_t *dev = (drm_device_t *) arg;
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *)dev->dev_private;
- u32 temp;
+ u32 stat, ack = 0;
/* Need to wait for fifo to drain?
*/
- temp = RADEON_READ(RADEON_GEN_INT_STATUS);
- temp = temp & RADEON_SW_INT_TEST_ACK;
- if (temp == 0) return;
- RADEON_WRITE(RADEON_GEN_INT_STATUS, temp);
+ stat = RADEON_READ(RADEON_GEN_INT_STATUS);
- atomic_inc(&dev_priv->irq_received);
+ /* SW interrupt */
+ if (stat & RADEON_SW_INT_TEST) {
+ ack |= RADEON_SW_INT_TEST_ACK;
+ atomic_inc(&dev_priv->swi_received);
#ifdef __linux__
- queue_task(&dev->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-#endif /* __linux__ */
+ wake_up_interruptible(&dev_priv->swi_queue);
+#endif
#ifdef __FreeBSD__
- taskqueue_enqueue(taskqueue_swi, &dev->task);
-#endif /* __FreeBSD__ */
-}
-
-void DRM(dma_immediate_bh)( DRM_TASKQUEUE_ARGS )
-{
- drm_device_t *dev = (drm_device_t *) arg;
- drm_radeon_private_t *dev_priv =
- (drm_radeon_private_t *)dev->dev_private;
+ wakeup(&dev->vbl_queue);
+#endif
+ }
+ /* VBLANK interrupt */
+ if (stat & RADEON_CRTC_VBLANK_STAT) {
+ ack |= RADEON_CRTC_VBLANK_STAT_ACK;
+ atomic_inc(&dev->vbl_received);
#ifdef __linux__
- wake_up_interruptible(&dev_priv->irq_queue);
-#endif /* __linux__ */
+ wake_up_interruptible(&dev->vbl_queue);
+#endif
#ifdef __FreeBSD__
- wakeup( &dev_priv->irq_queue );
+ wakeup(&dev->vbl_queue);
#endif
-}
+ }
+ if (ack)
+ RADEON_WRITE(RADEON_GEN_INT_STATUS, ack);
+}
+
int radeon_emit_irq(drm_device_t *dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- atomic_inc(&dev_priv->irq_emitted);
+ atomic_inc(&dev_priv->swi_emitted);
BEGIN_RING(2);
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) );
@@ -105,11 +106,11 @@ int radeon_emit_irq(drm_device_t *dev)
ADVANCE_RING();
COMMIT_RING();
- return atomic_read(&dev_priv->irq_emitted);
+ return atomic_read(&dev_priv->swi_emitted);
}
-int radeon_wait_irq(drm_device_t *dev, int irq_nr)
+int radeon_wait_irq(drm_device_t *dev, int swi_nr)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *)dev->dev_private;
@@ -119,17 +120,17 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
#endif /* __linux__ */
int ret = 0;
- if (atomic_read(&dev_priv->irq_received) >= irq_nr)
+ if (atomic_read(&dev_priv->swi_received) >= swi_nr)
return 0;
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
#ifdef __linux__
- add_wait_queue(&dev_priv->irq_queue, &entry);
+ add_wait_queue(&dev_priv->swi_queue, &entry);
for (;;) {
current->state = TASK_INTERRUPTIBLE;
- if (atomic_read(&dev_priv->irq_received) >= irq_nr)
+ if (atomic_read(&dev_priv->swi_received) >= swi_nr)
break;
if((signed)(end - jiffies) <= 0) {
ret = -EBUSY; /* Lockup? Missed irq? */
@@ -143,12 +144,12 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
}
current->state = TASK_RUNNING;
- remove_wait_queue(&dev_priv->irq_queue, &entry);
+ remove_wait_queue(&dev_priv->swi_queue, &entry);
return ret;
#endif /* __linux__ */
#ifdef __FreeBSD__
- ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \
+ ret = tsleep( &dev_priv->swi_queue, PZERO | PCATCH, \
"rdnirq", 3*hz );
if ( (ret == EWOULDBLOCK) || (ret == EINTR) )
return DRM_ERR(EBUSY);
@@ -156,7 +157,6 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
#endif /* __FreeBSD__ */
}
-
int radeon_emit_and_wait_irq(drm_device_t *dev)
{
return radeon_wait_irq( dev, radeon_emit_irq(dev) );
@@ -212,3 +212,41 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )
return radeon_wait_irq( dev, irqwait.irq_seq );
}
+
+void DRM(driver_irq_preinstall)( drm_device_t *dev ) {
+ drm_radeon_private_t *dev_priv =
+ (drm_radeon_private_t *)dev->dev_private;
+ u32 tmp;
+
+ /* Disable *all* interrupts */
+ RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
+
+ /* Clear bits if they're already high */
+ tmp = RADEON_READ( RADEON_GEN_INT_STATUS );
+ RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
+}
+
+void DRM(driver_irq_postinstall)( drm_device_t *dev ) {
+ drm_radeon_private_t *dev_priv =
+ (drm_radeon_private_t *)dev->dev_private;
+
+ atomic_set(&dev_priv->swi_received, 0);
+ atomic_set(&dev_priv->swi_emitted, 0);
+#ifdef __linux__
+ init_waitqueue_head(&dev_priv->swi_queue);
+#endif
+
+ /* Turn on SW and VBL ints */
+ RADEON_WRITE( RADEON_GEN_INT_CNTL,
+ RADEON_CRTC_VBLANK_MASK |
+ RADEON_SW_INT_ENABLE );
+}
+
+void DRM(driver_irq_uninstall)( drm_device_t *dev ) {
+ drm_radeon_private_t *dev_priv =
+ (drm_radeon_private_t *)dev->dev_private;
+ if ( dev_priv ) {
+ /* Disable *all* interrupts */
+ RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
+ }
+}