rs690/r500: vblank support.
The new display controller has the vblank interrupts in a different place. Add support for vbl interrupts for these chipsmain
parent
8399656106
commit
91c6c4b240
|
@ -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 */
|
||||
|
|
|
@ -47,8 +47,36 @@ 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)
|
||||
{
|
||||
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);
|
||||
|
@ -61,12 +89,29 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
|
|||
crtc);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void radeon_disable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
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);
|
||||
|
@ -80,12 +125,36 @@ void radeon_disable_vblank(struct drm_device *dev, int 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);
|
||||
|
@ -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 ((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,6 +261,18 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
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 {
|
||||
if (crtc == 0) {
|
||||
crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
|
||||
crtc_status_reg = RADEON_CRTC_STATUS;
|
||||
|
@ -194,9 +282,9 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
|
|||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 & 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;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue