rs690/r500: vblank support.
authorDave Airlie <airlied@redhat.com>
Wed, 21 May 2008 10:14:45 +0000 (20:14 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 21 May 2008 11:27:33 +0000 (21:27 +1000)
The new display controller has the vblank interrupts in a different place.

Add support for vbl interrupts for these chips

shared-core/radeon_drv.h
shared-core/radeon_irq.c

index c5a8443..4f04f30 100644 (file)
@@ -296,6 +296,7 @@ typedef struct drm_radeon_private {
        int vblank_crtc;
        uint32_t irq_enable_reg;
        int irq_enabled;
+       uint32_t r500_disp_irq_reg;
 
        struct radeon_surface surfaces[RADEON_MAX_SURFACES];
        struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
@@ -620,6 +621,8 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #      define RADEON_SW_INT_TEST               (1 << 25)
 #      define RADEON_SW_INT_TEST_ACK           (1 << 25)
 #      define RADEON_SW_INT_FIRE               (1 << 26)
+#       define R500_DISPLAY_INT_STATUS          (1 << 0)
+
 
 #define RADEON_HOST_PATH_CNTL          0x0130
 #      define RADEON_HDP_SOFT_RESET            (1 << 26)
@@ -1139,7 +1142,30 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
 #define RADEON_VHA_BACKFRAME0_OFF_V_2            0x1894
 #define RADEON_VHA_BACKFRAME1_OFF_PITCH_V_2      0x1898
 
+#define R500_D1CRTC_STATUS 0x609c
+#define R500_D2CRTC_STATUS 0x689c
+#define R500_CRTC_V_BLANK (1<<0)
+
+#define R500_D1CRTC_FRAME_COUNT 0x60a4
+#define R500_D2CRTC_FRAME_COUNT 0x68a4
+
+#define R500_D1MODE_V_COUNTER 0x6530
+#define R500_D2MODE_V_COUNTER 0x6d30
+
+#define R500_D1MODE_VBLANK_STATUS 0x6534
+#define R500_D2MODE_VBLANK_STATUS 0x6d34
+#define R500_VBLANK_OCCURED (1<<0)
+#define R500_VBLANK_ACK     (1<<4)
+#define R500_VBLANK_STAT    (1<<12)
+#define R500_VBLANK_INT     (1<<16)
+
+#define R500_DxMODE_INT_MASK 0x6540
+#define R500_D1MODE_INT_MASK (1<<0)
+#define R500_D2MODE_INT_MASK (1<<8)
 
+#define R500_DISP_INTERRUPT_STATUS 0x7edc
+#define R500_D1_VBLANK_INTERRUPT (1 << 4)
+#define R500_D2_VBLANK_INTERRUPT (1 << 5)
 
 /* Constants */
 #define RADEON_MAX_USEC_TIMEOUT                100000  /* 100 ms */
index 79e4e86..d21761f 100644 (file)
@@ -47,19 +47,48 @@ static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
        RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
 }
 
+static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
+{
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if (state)
+               dev_priv->r500_disp_irq_reg |= mask;
+       else
+               dev_priv->r500_disp_irq_reg &= ~mask;
+
+       RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
+}
+
 int radeon_enable_vblank(struct drm_device *dev, int crtc)
 {
-       switch (crtc) {
-       case 0:
-               radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
-               break;
-       case 1:
-               radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
-               break;
-       default:
-               DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
-                         crtc);
-               return EINVAL;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {     
+               switch (crtc) {
+               case 0:
+                       r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
+                       break;
+               case 1:
+                       r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       return EINVAL;
+               }
+       } else {
+               switch (crtc) {
+               case 0:
+                       radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
+                       break;
+               case 1:
+                       radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       return EINVAL;
+               }
        }
 
        return 0;
@@ -67,29 +96,69 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
 
 void radeon_disable_vblank(struct drm_device *dev, int crtc)
 {
-       switch (crtc) {
-       case 0:
-               radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
-               break;
-       case 1:
-               radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
-               break;
-       default:
-               DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
-                         crtc);
-               break;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {     
+               switch (crtc) {
+               case 0:
+                       r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
+                       break;
+               case 1:
+                       r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       break;
+               }
+       } else {
+               switch (crtc) {
+               case 0:
+                       radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
+                       break;
+               case 1:
+                       radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
+                       break;
+               default:
+                       DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                                 crtc);
+                       break;
+               }
        }
 }
 
-static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)
+static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, u32 *r500_disp_int)
 {
-       u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
-               (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
-                RADEON_CRTC2_VBLANK_STAT);
+       u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS);
+       u32 irq_mask = RADEON_SW_INT_TEST;
+
+       *r500_disp_int = 0;
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               /* vbl interrupts in a different place */
+
+               if (irqs & R500_DISPLAY_INT_STATUS) {
+                       /* if a display interrupt */
+                       u32 disp_irq;
+
+                       disp_irq = RADEON_READ(R500_DISP_INTERRUPT_STATUS);
+
+                       *r500_disp_int = disp_irq;
+                       if (disp_irq & R500_D1_VBLANK_INTERRUPT) {
+                               RADEON_WRITE(R500_D1MODE_VBLANK_STATUS, R500_VBLANK_ACK);
+                       }
+                       if (disp_irq & R500_D2_VBLANK_INTERRUPT) {
+                               RADEON_WRITE(R500_D2MODE_VBLANK_STATUS, R500_VBLANK_ACK);
+                       }
+               }
+               irq_mask |= R500_DISPLAY_INT_STATUS;
+       } else
+               irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT;
+
+       irqs &= irq_mask;
 
        if (irqs)
                RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
-
+       
        return irqs;
 }
 
@@ -117,11 +186,12 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
        u32 stat;
+       u32 r500_disp_int;
 
        /* Only consider the bits we're interested in - others could be used
         * outside the DRM
         */
-       stat = radeon_acknowledge_irqs(dev_priv);
+       stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
        if (!stat)
                return IRQ_NONE;
 
@@ -132,11 +202,17 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
                DRM_WAKEUP(&dev_priv->swi_queue);
 
        /* VBLANK interrupt */
-       if (stat & RADEON_CRTC_VBLANK_STAT)
-               drm_handle_vblank(dev, 0);
-       if (stat & RADEON_CRTC2_VBLANK_STAT)
-               drm_handle_vblank(dev, 1);
-
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
+                       drm_handle_vblank(dev, 0);
+               if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
+                       drm_handle_vblank(dev, 1);
+       } else {
+               if (stat & RADEON_CRTC_VBLANK_STAT)
+                       drm_handle_vblank(dev, 0);
+               if (stat & RADEON_CRTC2_VBLANK_STAT)
+                       drm_handle_vblank(dev, 1);
+       }
        return IRQ_HANDLED;
 }
 
@@ -185,17 +261,29 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
                return -EINVAL;
        }
 
-       if (crtc == 0) {
-               crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
-               crtc_status_reg = RADEON_CRTC_STATUS;
-       } else if (crtc == 1) {
-               crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
-               crtc_status_reg = RADEON_CRTC2_STATUS;
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               if (crtc == 0) {
+                       crtc_cnt_reg = R500_D1CRTC_FRAME_COUNT;
+                       crtc_status_reg = R500_D1CRTC_STATUS;
+               } else if (crtc == 1) {
+                       crtc_cnt_reg = R500_D2CRTC_FRAME_COUNT;
+                       crtc_status_reg = R500_D2CRTC_STATUS;
+               } else
+                       return -EINVAL;
+               return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
+                       
        } else {
-               return -EINVAL;
+               if (crtc == 0) {
+                       crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
+                       crtc_status_reg = RADEON_CRTC_STATUS;
+               } else if (crtc == 1) {
+                       crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
+                       crtc_status_reg = RADEON_CRTC2_STATUS;
+               } else {
+                       return -EINVAL;
+               }
+               return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
        }
-
-       return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
 }
 
 /* Needs the lock as it touches the ring.
@@ -244,12 +332,15 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
+       u32 dummy;
 
        /* Disable *all* interrupts */
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+               RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 
        /* Clear bits if they're already high */
-       radeon_acknowledge_irqs(dev_priv);
+       radeon_acknowledge_irqs(dev_priv, &dummy);
 }
 
 int radeon_driver_irq_postinstall(struct drm_device * dev)
@@ -281,6 +372,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->irq_enabled = 0;
 
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
+               RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
        /* Disable *all* interrupts */
        RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 }
@@ -292,14 +385,23 @@ int radeon_vblank_crtc_get(struct drm_device *dev)
        u32 flag;
        u32 value;
 
-       flag = RADEON_READ(RADEON_GEN_INT_CNTL);
-       value = 0;
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
+               flag = RADEON_READ(R500_DxMODE_INT_MASK);
+               value = 0;
+               if (flag & R500_D1MODE_INT_MASK)
+                       value |= DRM_RADEON_VBLANK_CRTC1;
 
-       if (flag & RADEON_CRTC_VBLANK_MASK)
-               value |= DRM_RADEON_VBLANK_CRTC1;
+               if (flag & R500_D2MODE_INT_MASK)
+                       value |= DRM_RADEON_VBLANK_CRTC2;
+       } else {
+               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;
+               if (flag & RADEON_CRTC2_VBLANK_MASK)
+                       value |= DRM_RADEON_VBLANK_CRTC2;
+       }
        return value;
 }