Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[powerpc.git] / drivers / char / drm / via_irq.c
index e8027f3..1ac5941 100644 (file)
 #define VIA_IRQ_HQV1_ENABLE     (1 << 25)
 #define VIA_IRQ_HQV0_PENDING    (1 << 9)
 #define VIA_IRQ_HQV1_PENDING    (1 << 10)
+#define VIA_IRQ_DMA0_DD_ENABLE  (1 << 20)
+#define VIA_IRQ_DMA0_TD_ENABLE  (1 << 21)
+#define VIA_IRQ_DMA1_DD_ENABLE  (1 << 22)
+#define VIA_IRQ_DMA1_TD_ENABLE  (1 << 23)
+#define VIA_IRQ_DMA0_DD_PENDING (1 << 4)
+#define VIA_IRQ_DMA0_TD_PENDING (1 << 5)
+#define VIA_IRQ_DMA1_DD_PENDING (1 << 6)
+#define VIA_IRQ_DMA1_TD_PENDING (1 << 7)
+
 
 /*
  * Device-specific IRQs go here. This type might need to be extended with
  * the register if there are multiple IRQ control registers.
- * Currently we activate the HQV interrupts of  Unichrome Pro group A. 
+ * Currently we activate the HQV interrupts of  Unichrome Pro group A.
  */
 
 static maskarray_t via_pro_group_a_irqs[] = {
-       {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 },
-       {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }};
-static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t);
-
-static maskarray_t via_unichrome_irqs[] = {};
-static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t);
-
-
-static unsigned time_diff(struct timeval *now,struct timeval *then) 
+       {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
+        0x00000000},
+       {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
+        0x00000000},
+       {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
+        VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
+       {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
+        VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
+};
+static int via_num_pro_group_a =
+    sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
+static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
+
+static maskarray_t via_unichrome_irqs[] = {
+       {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
+        VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
+       {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
+        VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
+};
+static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t);
+static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
+
+static unsigned time_diff(struct timeval *now, struct timeval *then)
 {
-    return (now->tv_usec >= then->tv_usec) ?
-        now->tv_usec - then->tv_usec :
-        1000000 - (then->tv_usec - now->tv_usec);
+       return (now->tv_usec >= then->tv_usec) ?
+           now->tv_usec - then->tv_usec :
+           1000000 - (then->tv_usec - now->tv_usec);
 }
 
 irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
@@ -86,38 +109,42 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
        status = VIA_READ(VIA_REG_INTERRUPT);
        if (status & VIA_IRQ_VBLANK_PENDING) {
                atomic_inc(&dev->vbl_received);
-                if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+               if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
                        do_gettimeofday(&cur_vblank);
-                        if (dev_priv->last_vblank_valid) {
-                               dev_priv->usec_per_vblank = 
-                                       time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4;
+                       if (dev_priv->last_vblank_valid) {
+                               dev_priv->usec_per_vblank =
+                                   time_diff(&cur_vblank,
+                                             &dev_priv->last_vblank) >> 4;
                        }
                        dev_priv->last_vblank = cur_vblank;
                        dev_priv->last_vblank_valid = 1;
-                }
-                if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+               }
+               if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
                        DRM_DEBUG("US per vblank is: %u\n",
-                               dev_priv->usec_per_vblank);
+                                 dev_priv->usec_per_vblank);
                }
                DRM_WAKEUP(&dev->vbl_queue);
                drm_vbl_send_signals(dev);
                handled = 1;
        }
-       
 
-       for (i=0; i<dev_priv->num_irqs; ++i) {
+       for (i = 0; i < dev_priv->num_irqs; ++i) {
                if (status & cur_irq->pending_mask) {
-                       atomic_inc( &cur_irq->irq_received );
-                       DRM_WAKEUP( &cur_irq->irq_queue );
+                       atomic_inc(&cur_irq->irq_received);
+                       DRM_WAKEUP(&cur_irq->irq_queue);
                        handled = 1;
+                       if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) {
+                               via_dmablit_handler(dev, 0, 1);
+                       } else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) {
+                               via_dmablit_handler(dev, 1, 1);
+                       }
                }
                cur_irq++;
        }
-       
+
        /* Acknowlege interrupts */
        VIA_WRITE(VIA_REG_INTERRUPT, status);
 
-
        if (handled)
                return IRQ_HANDLED;
        else
@@ -131,7 +158,7 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
        if (dev_priv) {
                /* Acknowlege interrupts */
                status = VIA_READ(VIA_REG_INTERRUPT);
-               VIA_WRITE(VIA_REG_INTERRUPT, status | 
+               VIA_WRITE(VIA_REG_INTERRUPT, status |
                          dev_priv->irq_pending_mask);
        }
 }
@@ -158,20 +185,21 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
        DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
                    (((cur_vblank = atomic_read(&dev->vbl_received)) -
                      *sequence) <= (1 << 23)));
-       
+
        *sequence = cur_vblank;
        return ret;
 }
 
-static int 
+static int
 via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
                    unsigned int *sequence)
 {
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        unsigned int cur_irq_sequence;
-       drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+       drm_via_irq_t *cur_irq;
        int ret = 0;
-       maskarray_t *masks = dev_priv->irq_masks;
+       maskarray_t *masks;
+       int real_irq;
 
        DRM_DEBUG("%s\n", __FUNCTION__);
 
@@ -180,27 +208,38 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
                return DRM_ERR(EINVAL);
        }
 
-       if (irq >= dev_priv->num_irqs ) {
-               DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq);
+       if (irq >= drm_via_irq_num) {
+               DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
+                         irq);
                return DRM_ERR(EINVAL);
        }
-               
-       cur_irq += irq;
 
-       if (masks[irq][2] && !force_sequence) {
+       real_irq = dev_priv->irq_map[irq];
+
+       if (real_irq < 0) {
+               DRM_ERROR("%s Video IRQ %d not available on this hardware.\n",
+                         __FUNCTION__, irq);
+               return DRM_ERR(EINVAL);
+       }
+
+       masks = dev_priv->irq_masks;
+       cur_irq = dev_priv->via_irqs + real_irq;
+
+       if (masks[real_irq][2] && !force_sequence) {
                DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
-                           ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4]));
+                           ((VIA_READ(masks[irq][2]) & masks[irq][3]) ==
+                            masks[irq][4]));
                cur_irq_sequence = atomic_read(&cur_irq->irq_received);
        } else {
                DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
-                           (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) -
-                             *sequence) <= (1 << 23)));                
+                           (((cur_irq_sequence =
+                              atomic_read(&cur_irq->irq_received)) -
+                             *sequence) <= (1 << 23)));
        }
        *sequence = cur_irq_sequence;
        return ret;
 }
 
-
 /*
  * drm_dma.h hooks
  */
@@ -209,39 +248,46 @@ void via_driver_irq_preinstall(drm_device_t * dev)
 {
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
        u32 status;
-       drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+       drm_via_irq_t *cur_irq;
        int i;
 
        DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
        if (dev_priv) {
+               cur_irq = dev_priv->via_irqs;
 
                dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
                dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
 
-               dev_priv->irq_masks = (dev_priv->pro_group_a) ?
-                       via_pro_group_a_irqs : via_unichrome_irqs;
-               dev_priv->num_irqs = (dev_priv->pro_group_a) ?
-                       via_num_pro_group_a : via_num_unichrome;
-               
-               for(i=0; i < dev_priv->num_irqs; ++i) {
+               if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+                   dev_priv->chipset == VIA_DX9_0) {
+                       dev_priv->irq_masks = via_pro_group_a_irqs;
+                       dev_priv->num_irqs = via_num_pro_group_a;
+                       dev_priv->irq_map = via_irqmap_pro_group_a;
+               } else {
+                       dev_priv->irq_masks = via_unichrome_irqs;
+                       dev_priv->num_irqs = via_num_unichrome;
+                       dev_priv->irq_map = via_irqmap_unichrome;
+               }
+
+               for (i = 0; i < dev_priv->num_irqs; ++i) {
                        atomic_set(&cur_irq->irq_received, 0);
-                       cur_irq->enable_mask = dev_priv->irq_masks[i][0]; 
+                       cur_irq->enable_mask = dev_priv->irq_masks[i][0];
                        cur_irq->pending_mask = dev_priv->irq_masks[i][1];
-                       DRM_INIT_WAITQUEUE( &cur_irq->irq_queue );
+                       DRM_INIT_WAITQUEUE(&cur_irq->irq_queue);
                        dev_priv->irq_enable_mask |= cur_irq->enable_mask;
                        dev_priv->irq_pending_mask |= cur_irq->pending_mask;
                        cur_irq++;
-                       
+
                        DRM_DEBUG("Initializing IRQ %d\n", i);
                }
-                       
-               dev_priv->last_vblank_valid = 0;
 
-               // Clear VSync interrupt regs
+               dev_priv->last_vblank_valid = 0;
+
+               /* Clear VSync interrupt regs */
                status = VIA_READ(VIA_REG_INTERRUPT);
-               VIA_WRITE(VIA_REG_INTERRUPT, status & 
+               VIA_WRITE(VIA_REG_INTERRUPT, status &
                          ~(dev_priv->irq_enable_mask));
-               
+
                /* Clear bits if they're already high */
                viadrv_acknowledge_irqs(dev_priv);
        }
@@ -262,7 +308,7 @@ void via_driver_irq_postinstall(drm_device_t * dev)
 
                VIA_WRITE8(0x83d4, 0x11);
                VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
-               
+
        }
 }
 
@@ -280,15 +326,14 @@ void via_driver_irq_uninstall(drm_device_t * dev)
                VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
 
                status = VIA_READ(VIA_REG_INTERRUPT);
-               VIA_WRITE(VIA_REG_INTERRUPT, status & 
+               VIA_WRITE(VIA_REG_INTERRUPT, status &
                          ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
        }
 }
 
 int via_wait_irq(DRM_IOCTL_ARGS)
 {
-       drm_file_t *priv = filp->private_data;
-       drm_device_t *dev = priv->head->dev;
+       DRM_DEVICE;
        drm_via_irqwait_t __user *argp = (void __user *)data;
        drm_via_irqwait_t irqwait;
        struct timeval now;
@@ -302,7 +347,7 @@ int via_wait_irq(DRM_IOCTL_ARGS)
 
        DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
        if (irqwait.request.irq >= dev_priv->num_irqs) {
-               DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, 
+               DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
                          irqwait.request.irq);
                return DRM_ERR(EINVAL);
        }
@@ -320,7 +365,7 @@ int via_wait_irq(DRM_IOCTL_ARGS)
        }
 
        if (irqwait.request.type & VIA_IRQ_SIGNAL) {
-               DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n", 
+               DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
                          __FUNCTION__);
                return DRM_ERR(EINVAL);
        }