From 91c6c4b2403caca80273e8010e9ced74cf900be3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 21 May 2008 20:14:45 +1000 Subject: [PATCH] rs690/r500: vblank support. 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 | 26 +++++ shared-core/radeon_irq.c | 200 +++++++++++++++++++++++++++++---------- 2 files changed, 177 insertions(+), 49 deletions(-) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index c5a84439..4f04f30f 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -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 */ 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; }