radeon: add support for vblank on crtc2
authorDave Airlie <airlied@linux.ie>
Wed, 11 Jul 2007 02:16:01 +0000 (12:16 +1000)
committerDave Airlie <airlied@linux.ie>
Wed, 11 Jul 2007 02:16:01 +0000 (12:16 +1000)
This adds support for CRTC2 vblank on radeon similiar to the i915.

Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/radeon_cp.c
drivers/char/drm/radeon_drm.h
drivers/char/drm/radeon_drv.c
drivers/char/drm/radeon_drv.h
drivers/char/drm/radeon_irq.c
drivers/char/drm/radeon_state.c

index aac5db3a0eb063f32c9ef66dbde2787c18a5955d..7dd9800552293a6833e10169b9a626caa2fe5f17 100644 (file)
@@ -1420,6 +1420,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
                return DRM_ERR(EINVAL);
        }
 
+       /* Enable vblank on CRTC1 for older X servers
+        */
+       dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
+
        switch(init->func) {
        case RADEON_INIT_R200_CP:
                dev_priv->microcode_version = UCODE_R200;
index 66c4b6fed04f092a1f20dfacb09374128b49a555..04de7a15df9910f307fa4b86f4521209dbb8c233 100644 (file)
@@ -655,6 +655,7 @@ typedef struct drm_radeon_indirect {
 #define RADEON_PARAM_GART_TEX_HANDLE       10
 #define RADEON_PARAM_SCRATCH_OFFSET        11
 #define RADEON_PARAM_CARD_TYPE             12
+#define RADEON_PARAM_VBLANK_CRTC           13   /* VBLANK CRTC */
 
 typedef struct drm_radeon_getparam {
        int param;
@@ -708,7 +709,7 @@ typedef struct drm_radeon_setparam {
 #define RADEON_SETPARAM_PCIGART_LOCATION 3     /* PCI Gart Location */
 #define RADEON_SETPARAM_NEW_MEMMAP 4           /* Use new memory map */
 #define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5    /* PCI GART Table Size */
-
+#define RADEON_SETPARAM_VBLANK_CRTC 6           /* VBLANK CRTC */
 /* 1.14: Clients can allocate/free a surface
  */
 typedef struct drm_radeon_surface_alloc {
@@ -721,4 +722,7 @@ typedef struct drm_radeon_surface_free {
        unsigned int address;
 } drm_radeon_surface_free_t;
 
+#define        DRM_RADEON_VBLANK_CRTC1         1
+#define        DRM_RADEON_VBLANK_CRTC2         2
+
 #endif
index 2eb652ec674578c97f24cf1ca6c40b0d58a4454e..349ac3d3b8480c13d91c850f917819774f92edbf 100644 (file)
@@ -60,7 +60,7 @@ static struct drm_driver driver = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
            DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
-           DRIVER_IRQ_VBL,
+           DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
        .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
        .load = radeon_driver_load,
        .firstopen = radeon_driver_firstopen,
@@ -70,6 +70,7 @@ static struct drm_driver driver = {
        .lastclose = radeon_driver_lastclose,
        .unload = radeon_driver_unload,
        .vblank_wait = radeon_driver_vblank_wait,
+       .vblank_wait2 = radeon_driver_vblank_wait2,
        .dri_library_name = dri_library_name,
        .irq_preinstall = radeon_driver_irq_preinstall,
        .irq_postinstall = radeon_driver_irq_postinstall,
index 54f49ef4bef084b8ae816a301596b8833c58e961..4422ae3a68bcb3ac8edf8980950ea8bcdfaed9cb 100644 (file)
  *       new packet type)
  * 1.26- Add support for variable size PCI(E) gart aperture
  * 1.27- Add support for IGP GART
+ * 1.28- Add support for VBL on CRTC2
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           27
+#define DRIVER_MINOR           28
 #define DRIVER_PATCHLEVEL      0
 
 /*
@@ -277,6 +278,9 @@ typedef struct drm_radeon_private {
        /* SW interrupt */
        wait_queue_head_t swi_queue;
        atomic_t swi_emitted;
+       int vblank_crtc;
+       uint32_t irq_enable_reg;
+       int irq_enabled;
 
        struct radeon_surface surfaces[RADEON_MAX_SURFACES];
        struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
@@ -356,10 +360,14 @@ extern int radeon_irq_wait(DRM_IOCTL_ARGS);
 extern void radeon_do_release(drm_device_t * dev);
 extern int radeon_driver_vblank_wait(drm_device_t * dev,
                                     unsigned int *sequence);
+extern int radeon_driver_vblank_wait2(drm_device_t * dev,
+                                     unsigned int *sequence);
 extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
 extern void radeon_driver_irq_preinstall(drm_device_t * dev);
 extern void radeon_driver_irq_postinstall(drm_device_t * dev);
 extern void radeon_driver_irq_uninstall(drm_device_t * dev);
+extern int radeon_vblank_crtc_get(drm_device_t *dev);
+extern int radeon_vblank_crtc_set(drm_device_t *dev, int64_t value);
 
 extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
 extern int radeon_driver_unload(struct drm_device *dev);
@@ -496,12 +504,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
 
 #define RADEON_GEN_INT_CNTL            0x0040
 #      define RADEON_CRTC_VBLANK_MASK          (1 << 0)
+#      define RADEON_CRTC2_VBLANK_MASK         (1 << 9)
 #      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_CRTC2_VBLANK_STAT         (1 << 9)
+#      define RADEON_CRTC2_VBLANK_STAT_ACK     (1 << 9)
 #      define RADEON_GUI_IDLE_INT_TEST_ACK     (1 << 19)
 #      define RADEON_SW_INT_TEST               (1 << 25)
 #      define RADEON_SW_INT_TEST_ACK           (1 << 25)
index 3ff0baa2fbfa201f7c37c20df5d6c601afc009d7..a4be86e3812127744408fb052cdc5116d552f662 100644 (file)
@@ -73,18 +73,35 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
         * outside the DRM
         */
        stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
-                                                 RADEON_CRTC_VBLANK_STAT));
+                                                 RADEON_CRTC_VBLANK_STAT |
+                                                 RADEON_CRTC2_VBLANK_STAT));
        if (!stat)
                return IRQ_NONE;
 
+       stat &= dev_priv->irq_enable_reg;
+
        /* SW interrupt */
        if (stat & RADEON_SW_INT_TEST) {
                DRM_WAKEUP(&dev_priv->swi_queue);
        }
 
        /* VBLANK interrupt */
-       if (stat & RADEON_CRTC_VBLANK_STAT) {
-               atomic_inc(&dev->vbl_received);
+       if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
+               int vblank_crtc = dev_priv->vblank_crtc;
+
+               if ((vblank_crtc &
+                    (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
+                   (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
+                       if (stat & RADEON_CRTC_VBLANK_STAT)
+                               atomic_inc(&dev->vbl_received);
+                       if (stat & RADEON_CRTC2_VBLANK_STAT)
+                               atomic_inc(&dev->vbl_received2);
+               } else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
+                          (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
+                          ((stat & RADEON_CRTC2_VBLANK_STAT) &&
+                           (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
+                       atomic_inc(&dev->vbl_received);
+
                DRM_WAKEUP(&dev->vbl_queue);
                drm_vbl_send_signals(dev);
        }
@@ -127,19 +144,30 @@ static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
        return ret;
 }
 
-int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+int radeon_driver_vblank_do_wait(drm_device_t * dev, unsigned int *sequence,
+                                int crtc)
 {
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
        unsigned int cur_vblank;
        int ret = 0;
-
+       int ack = 0;
+       atomic_t *counter;
        if (!dev_priv) {
                DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
                return DRM_ERR(EINVAL);
        }
 
-       radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT);
+       if (crtc == DRM_RADEON_VBLANK_CRTC1) {
+               counter = &dev->vbl_received;
+               ack |= RADEON_CRTC_VBLANK_STAT;
+       } else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
+               counter = &dev->vbl_received2;
+               ack |= RADEON_CRTC2_VBLANK_STAT;
+       } else
+               return DRM_ERR(EINVAL);
+
+       radeon_acknowledge_irqs(dev_priv, ack);
 
        dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
@@ -148,7 +176,7 @@ int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
         * using vertical blanks...
         */
        DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(&dev->vbl_received))
+                   (((cur_vblank = atomic_read(counter))
                      - *sequence) <= (1 << 23)));
 
        *sequence = cur_vblank;
@@ -156,6 +184,16 @@ int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
        return ret;
 }
 
+int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+{
+       return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
+}
+
+int radeon_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
+{
+       return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
+}
+
 /* Needs the lock as it touches the ring.
  */
 int radeon_irq_emit(DRM_IOCTL_ARGS)
@@ -204,6 +242,21 @@ int radeon_irq_wait(DRM_IOCTL_ARGS)
        return radeon_wait_irq(dev, irqwait.irq_seq);
 }
 
+static void radeon_enable_interrupt(drm_device_t *dev)
+{
+       drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+
+       dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
+       if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
+               dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
+
+       if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
+               dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
+
+       RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+       dev_priv->irq_enabled = 1;
+}
+
 /* drm_dma.h hooks
 */
 void radeon_driver_irq_preinstall(drm_device_t * dev)
@@ -216,7 +269,8 @@ void radeon_driver_irq_preinstall(drm_device_t * dev)
 
        /* Clear bits if they're already high */
        radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
-                                          RADEON_CRTC_VBLANK_STAT));
+                                          RADEON_CRTC_VBLANK_STAT |
+                                          RADEON_CRTC2_VBLANK_STAT));
 }
 
 void radeon_driver_irq_postinstall(drm_device_t * dev)
@@ -227,9 +281,7 @@ void radeon_driver_irq_postinstall(drm_device_t * dev)
        atomic_set(&dev_priv->swi_emitted, 0);
        DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
-       /* Turn on SW and VBL ints */
-       RADEON_WRITE(RADEON_GEN_INT_CNTL,
-                    RADEON_CRTC_VBLANK_MASK | RADEON_SW_INT_ENABLE);
+       radeon_enable_interrupt(dev);
 }
 
 void radeon_driver_irq_uninstall(drm_device_t * dev)
@@ -239,6 +291,38 @@ void radeon_driver_irq_uninstall(drm_device_t * dev)
        if (!dev_priv)
                return;
 
+       dev_priv->irq_enabled = 0;
+
        /* Disable *all* interrupts */
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 }
+
+
+int radeon_vblank_crtc_get(drm_device_t *dev)
+{
+       drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+       u32 flag;
+       u32 value;
+
+       flag = RADEON_READ(RADEON_GEN_INT_CNTL);
+       value = 0;
+
+       if (flag & RADEON_CRTC_VBLANK_MASK)
+               value |= DRM_RADEON_VBLANK_CRTC1;
+
+       if (flag & RADEON_CRTC2_VBLANK_MASK)
+               value |= DRM_RADEON_VBLANK_CRTC2;
+       return value;
+}
+
+int radeon_vblank_crtc_set(drm_device_t *dev, int64_t value)
+{
+       drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+       if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
+               DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
+               return DRM_ERR(EINVAL);
+       }
+       dev_priv->vblank_crtc = (unsigned int)value;
+       radeon_enable_interrupt(dev);
+       return 0;
+}
index 98c5f1d3a8e7282ba07e528ab1d96e8c3bd473a8..5b89e471bc71329cd6ebf7fefbe3ccabf0f0a243 100644 (file)
@@ -3085,6 +3085,9 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
                else
                        value = RADEON_CARD_PCI;
                break;
+       case RADEON_PARAM_VBLANK_CRTC:
+               value = radeon_vblank_crtc_get(dev);
+               break;
        default:
                DRM_DEBUG("Invalid parameter %d\n", param.param);
                return DRM_ERR(EINVAL);
@@ -3141,6 +3144,9 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
                if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
                        dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
                break;
+       case RADEON_SETPARAM_VBLANK_CRTC:
+               return radeon_vblank_crtc_set(dev, sp.value);
+               break;
        default:
                DRM_DEBUG("Invalid parameter %d\n", sp.param);
                return DRM_ERR(EINVAL);