int radeondrm_activate(struct device *arg, int act) { struct drm_radeon_private *dev_priv = (struct drm_radeon_private *)arg; struct drm_device *dev = (struct drm_device *)dev_priv->drmdev; switch (act) { case DVACT_SUSPEND: /* Interrupts still not supported on r600 */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600 || dev->irq_enabled == 0) break; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) RADEON_WRITE(R500_DxMODE_INT_MASK, 0); RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); break; case DVACT_RESUME: /* Interrupts still not supported on r600 */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600 || dev->irq_enabled == 0) break; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); break; } return (0); }
static u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int) { 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_RS600) { /* 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; }
static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) { u32 ret; RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK)); ret = RADEON_READ(RS690_MC_DATA); RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_MASK); return ret; }
static u32 RS480_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) { u32 ret; RADEON_WRITE(RS480_NB_MC_INDEX, addr & 0xff); ret = RADEON_READ(RS480_NB_MC_DATA); RADEON_WRITE(RS480_NB_MC_INDEX, 0xff); return ret; }
static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) { u32 ret; RADEON_WRITE(R520_MC_IND_INDEX, 0x7f0000 | (addr & 0xff)); ret = RADEON_READ(R520_MC_IND_DATA); RADEON_WRITE(R520_MC_IND_INDEX, 0); return ret; }
void radeon_driver_irq_uninstall(struct drm_device * dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; if (!dev_priv) return; 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); }
static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return 0; /* Disable *all* interrupts */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) RADEON_WRITE(R500_DxMODE_INT_MASK, 0); RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); return 0; }
static int radeon_resume(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return 0; /* Restore interrupt registers */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); return 0; }
/* drm_dma.h hooks */ 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, &dummy); }
static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv) { u32 tmp; int i; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT); tmp |= RADEON_RB3D_DC_FLUSH_ALL; RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp); for (i = 0; i < dev_priv->usec_timeout; i++) { if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY)) { return 0; } DRM_UDELAY(1); } } else { /* don't flush or purge cache here or lockup */ return 0; } #if RADEON_FIFO_DEBUG DRM_ERROR("failed!\n"); radeon_status(dev_priv); #endif return -EBUSY; }
static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv) { u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS ) & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT); if (tmp) RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); }
void DRM(dma_service)( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; u32 stat; /* Only consider the bits we're interested in - others could be used * outside the DRM */ stat = RADEON_READ(RADEON_GEN_INT_STATUS) & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT); if (!stat) return; /* SW interrupt */ if (stat & RADEON_SW_INT_TEST) { DRM_WAKEUP( &dev_priv->swi_queue ); } /* VBLANK interrupt */ if (stat & RADEON_CRTC_VBLANK_STAT) { atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); DRM(vbl_send_signals)( dev ); } /* Acknowledge interrupts we handle */ RADEON_WRITE(RADEON_GEN_INT_STATUS, stat); }
static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, u32 mask) { u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; if (irqs) RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); return irqs; }
void DRM(driver_irq_uninstall)( drm_device_t *dev ) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; if ( dev_priv ) { /* Disable *all* interrupts */ RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); } }
void radeon_driver_irq_preinstall(struct drm_device * dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; u32 dummy; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) RADEON_WRITE(R500_DxMODE_INT_MASK, 0); RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); radeon_acknowledge_irqs(dev_priv, &dummy); }
/* drm_dma.h hooks */ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; /* Disable *all* interrupts */ RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); /* Clear bits if they're already high */ radeon_acknowledge_irqs( dev_priv ); }
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); }
void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) { drm_radeon_private_t *dev_priv = dev->dev_private; if (state) dev_priv->irq_enable_reg |= mask; else dev_priv->irq_enable_reg &= ~mask; RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); }
static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc); else RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc); }
void DRM(driver_irq_postinstall)( drm_device_t *dev ) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; atomic_set(&dev_priv->swi_emitted, 0); DRM_INIT_WAITQUEUE( &dev_priv->swi_queue ); /* Turn on SW and VBL ints */ RADEON_WRITE( RADEON_GEN_INT_CNTL, RADEON_CRTC_VBLANK_MASK | RADEON_SW_INT_ENABLE ); }
void radeon_driver_irq_uninstall(struct drm_device * dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; if (!dev_priv) return; dev_priv->irq_enabled = 0; /* Disable *all* interrupts */ RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); }
/* drm_dma.h hooks */ void radeon_driver_irq_preinstall(struct drm_device * dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; /* Disable *all* interrupts */ RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); /* Clear bits if they're already high */ radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT)); }
static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) { u32 agp_base_hi = upper_32_bits(agp_base); u32 agp_base_lo = agp_base & 0xffffffff; if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) { R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo); R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi); } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) { RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo); RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi); } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) { R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo); R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi); } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) { RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); RADEON_WRITE(RS480_AGP_BASE_2, 0); } else { RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200) RADEON_WRITE(RADEON_AGP_BASE_2, agp_base_hi); } }
static void radeon_enable_interrupt(struct drm_device *dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE; if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1) dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK; if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2) dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK; RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; }
void radeondrm_commit_ring(struct drm_radeon_private *dev_priv) { int i, tail_aligned, num_p2; u_int32_t *ring; /* check if the ring is padded out to 16-dword alignment */ tail_aligned = dev_priv->ring.tail & (RADEON_RING_ALIGN - 1); if (tail_aligned) { num_p2 = RADEON_RING_ALIGN - tail_aligned; ring = dev_priv->ring.start; /* pad with some CP_PACKET2 */ for (i = 0; i < num_p2; i++) ring[dev_priv->ring.tail + i] = CP_PACKET2(); dev_priv->ring.tail += i; dev_priv->ring.space -= num_p2; } dev_priv->ring.tail &= dev_priv->ring.tail_mask; /* XXX 128byte aligned stuff */ /* flush write combining buffer and writes to ring */ DRM_MEMORYBARRIER(); radeondrm_get_ring_head(dev_priv); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) { RADEON_WRITE(R600_CP_RB_WPTR, dev_priv->ring.tail); /* read from PCI bus to ensure correct posting */ RADEON_READ(R600_CP_RB_RPTR); } else { RADEON_WRITE(RADEON_CP_RB_WPTR, dev_priv->ring.tail); /* read from PCI bus to ensure correct posting */ RADEON_READ(RADEON_CP_RB_RPTR); } }
irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; u32 stat; u32 r500_disp_int; u32 tmp; if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return IRQ_NONE; /* Only consider the bits we're interested in - others could be used * outside the DRM */ stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int); if (!stat) return IRQ_NONE; stat &= dev_priv->irq_enable_reg; /* SW interrupt */ if (stat & RADEON_SW_INT_TEST) DRM_WAKEUP(&dev_priv->swi_queue); /* VBLANK interrupt */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { 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); } if (dev->msi_enabled) { switch(dev_priv->flags & RADEON_FAMILY_MASK) { case CHIP_RS400: case CHIP_RS480: tmp = RADEON_READ(RADEON_AIC_CNTL) & ~RS400_MSI_REARM; RADEON_WRITE(RADEON_AIC_CNTL, tmp); RADEON_WRITE(RADEON_AIC_CNTL, tmp | RS400_MSI_REARM); break; case CHIP_RS600: case CHIP_RS690: case CHIP_RS740: tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_MSI_REARM; RADEON_WRITE(RADEON_BUS_CNTL, tmp); RADEON_WRITE(RADEON_BUS_CNTL, tmp | RS600_MSI_REARM); break; default: tmp = RADEON_READ(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN; RADEON_WRITE(RADEON_MSI_REARM_EN, tmp); RADEON_WRITE(RADEON_MSI_REARM_EN, tmp | RV370_MSI_REARM_EN); break; } } return IRQ_HANDLED; }