summaryrefslogtreecommitdiff
path: root/shared-core/radeon_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core/radeon_irq.c')
-rw-r--r--shared-core/radeon_irq.c200
1 files changed, 151 insertions, 49 deletions
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 79e4e866..d21761fb 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -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;
}