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;
|
int vblank_crtc;
|
||||||
uint32_t irq_enable_reg;
|
uint32_t irq_enable_reg;
|
||||||
int irq_enabled;
|
int irq_enabled;
|
||||||
|
uint32_t r500_disp_irq_reg;
|
||||||
|
|
||||||
struct radeon_surface surfaces[RADEON_MAX_SURFACES];
|
struct radeon_surface surfaces[RADEON_MAX_SURFACES];
|
||||||
struct radeon_virt_surface virt_surfaces[2 * 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 (1 << 25)
|
||||||
# define RADEON_SW_INT_TEST_ACK (1 << 25)
|
# define RADEON_SW_INT_TEST_ACK (1 << 25)
|
||||||
# define RADEON_SW_INT_FIRE (1 << 26)
|
# define RADEON_SW_INT_FIRE (1 << 26)
|
||||||
|
# define R500_DISPLAY_INT_STATUS (1 << 0)
|
||||||
|
|
||||||
|
|
||||||
#define RADEON_HOST_PATH_CNTL 0x0130
|
#define RADEON_HOST_PATH_CNTL 0x0130
|
||||||
# define RADEON_HDP_SOFT_RESET (1 << 26)
|
# 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_BACKFRAME0_OFF_V_2 0x1894
|
||||||
#define RADEON_VHA_BACKFRAME1_OFF_PITCH_V_2 0x1898
|
#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 */
|
/* Constants */
|
||||||
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
||||||
|
|
|
@ -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);
|
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)
|
int radeon_enable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
switch (crtc) {
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
case 0:
|
|
||||||
radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
break;
|
switch (crtc) {
|
||||||
case 1:
|
case 0:
|
||||||
radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
|
r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
|
||||||
break;
|
break;
|
||||||
default:
|
case 1:
|
||||||
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 1);
|
||||||
crtc);
|
break;
|
||||||
return EINVAL;
|
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;
|
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)
|
void radeon_disable_vblank(struct drm_device *dev, int crtc)
|
||||||
{
|
{
|
||||||
switch (crtc) {
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
case 0:
|
|
||||||
radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
break;
|
switch (crtc) {
|
||||||
case 1:
|
case 0:
|
||||||
radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
|
r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
case 1:
|
||||||
DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
r500_vbl_irq_set_state(dev, R500_D2MODE_INT_MASK, 0);
|
||||||
crtc);
|
break;
|
||||||
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) &
|
u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS);
|
||||||
(RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
|
u32 irq_mask = RADEON_SW_INT_TEST;
|
||||||
RADEON_CRTC2_VBLANK_STAT);
|
|
||||||
|
*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)
|
if (irqs)
|
||||||
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
|
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
|
||||||
|
|
||||||
return 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_priv =
|
||||||
(drm_radeon_private_t *) dev->dev_private;
|
(drm_radeon_private_t *) dev->dev_private;
|
||||||
u32 stat;
|
u32 stat;
|
||||||
|
u32 r500_disp_int;
|
||||||
|
|
||||||
/* Only consider the bits we're interested in - others could be used
|
/* Only consider the bits we're interested in - others could be used
|
||||||
* outside the DRM
|
* outside the DRM
|
||||||
*/
|
*/
|
||||||
stat = radeon_acknowledge_irqs(dev_priv);
|
stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int);
|
||||||
if (!stat)
|
if (!stat)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
@ -132,11 +202,17 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
|
||||||
DRM_WAKEUP(&dev_priv->swi_queue);
|
DRM_WAKEUP(&dev_priv->swi_queue);
|
||||||
|
|
||||||
/* VBLANK interrupt */
|
/* VBLANK interrupt */
|
||||||
if (stat & RADEON_CRTC_VBLANK_STAT)
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
drm_handle_vblank(dev, 0);
|
if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
|
||||||
if (stat & RADEON_CRTC2_VBLANK_STAT)
|
drm_handle_vblank(dev, 0);
|
||||||
drm_handle_vblank(dev, 1);
|
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;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,17 +261,29 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crtc == 0) {
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
|
if (crtc == 0) {
|
||||||
crtc_status_reg = RADEON_CRTC_STATUS;
|
crtc_cnt_reg = R500_D1CRTC_FRAME_COUNT;
|
||||||
} else if (crtc == 1) {
|
crtc_status_reg = R500_D1CRTC_STATUS;
|
||||||
crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
|
} else if (crtc == 1) {
|
||||||
crtc_status_reg = RADEON_CRTC2_STATUS;
|
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 {
|
} 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.
|
/* 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_priv =
|
||||||
(drm_radeon_private_t *) dev->dev_private;
|
(drm_radeon_private_t *) dev->dev_private;
|
||||||
|
u32 dummy;
|
||||||
|
|
||||||
/* Disable *all* interrupts */
|
/* 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);
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
||||||
|
|
||||||
/* Clear bits if they're already high */
|
/* 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)
|
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;
|
dev_priv->irq_enabled = 0;
|
||||||
|
|
||||||
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
|
||||||
|
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
|
||||||
/* Disable *all* interrupts */
|
/* Disable *all* interrupts */
|
||||||
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
|
||||||
}
|
}
|
||||||
|
@ -292,14 +385,23 @@ int radeon_vblank_crtc_get(struct drm_device *dev)
|
||||||
u32 flag;
|
u32 flag;
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
flag = RADEON_READ(RADEON_GEN_INT_CNTL);
|
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
|
||||||
value = 0;
|
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)
|
if (flag & R500_D2MODE_INT_MASK)
|
||||||
value |= DRM_RADEON_VBLANK_CRTC1;
|
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)
|
if (flag & RADEON_CRTC2_VBLANK_MASK)
|
||||||
value |= DRM_RADEON_VBLANK_CRTC2;
|
value |= DRM_RADEON_VBLANK_CRTC2;
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue