diff options
Diffstat (limited to 'shared-core/radeon_irq.c')
-rw-r--r-- | shared-core/radeon_irq.c | 200 |
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; } |