static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat) { struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; uint32_t pipestat; int wake = 0; int vsync_a = 0; int vsync_b = 0; static int pipe_a_on = 0; static int pipe_b_on = 0; int trigger_2d_blit = 0; pipestat = PSB_RVDC32(PSB_PIPEASTAT); if (pipestat & (1<<31)) { printk("buffer underrun 0x%x\n",underrun++); PSB_WVDC32(1<<31 | 1<<15, PSB_PIPEASTAT); } if ((!drm_psb_disable_vsync) && (vdc_stat & _PSB_VSYNC_PIPEA_FLAG)) { atomic_inc(&dev->vbl_received); wake = 1; PSB_WVDC32(_PSB_VBLANK_INTERRUPT_ENABLE | _PSB_VBLANK_CLEAR, PSB_PIPEASTAT); } if ((!drm_psb_disable_vsync) && (vdc_stat & _PSB_VSYNC_PIPEB_FLAG)) { atomic_inc(&dev->vbl_received2); wake = 1; PSB_WVDC32(_PSB_VBLANK_INTERRUPT_ENABLE | _PSB_VBLANK_CLEAR, PSB_PIPEBSTAT); } if (vdc_stat & _PSB_HOTPLUG_INTERRUPT_FLAG) { // Clear 2nd status register spin_lock(&dev_priv->irqmask_lock); uint32_t hotplugstat = PSB_RVDC32(PORT_HOTPLUG_STATUS_REG); PSB_WVDC32(hotplugstat, PORT_HOTPLUG_STATUS_REG); spin_unlock(&dev_priv->irqmask_lock); hotplug_env = '1'; wake_up_interruptible(&hotplug_queue); } PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R); (void)PSB_RVDC32(PSB_INT_IDENTITY_R); DRM_READMEMORYBARRIER(); if (wake) { DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); } }
/* * MSVDX interrupt. */ static void psb_msvdx_interrupt(struct drm_device *dev, uint32_t msvdx_stat) { struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; if (msvdx_stat & MSVDX_INTERRUPT_STATUS_CR_MMU_FAULT_IRQ_MASK) { /*Ideally we should we should never get to this */ PSB_DEBUG_GENERAL ("******MSVDX: msvdx_stat: 0x%x fence2_irq_on=%d ***** (MMU FAULT)\n", msvdx_stat, dev_priv->fence2_irq_on); /* Pause MMU */ PSB_WMSVDX32(MSVDX_MMU_CONTROL0_CR_MMU_PAUSE_MASK, MSVDX_MMU_CONTROL0); DRM_WRITEMEMORYBARRIER(); /* Clear this interupt bit only */ PSB_WMSVDX32(MSVDX_INTERRUPT_STATUS_CR_MMU_FAULT_IRQ_MASK, MSVDX_INTERRUPT_CLEAR); PSB_RMSVDX32(MSVDX_INTERRUPT_CLEAR); DRM_READMEMORYBARRIER(); dev_priv->msvdx_needs_reset = 1; } else if (msvdx_stat & MSVDX_INTERRUPT_STATUS_CR_MTX_IRQ_MASK) { PSB_DEBUG_GENERAL ("******MSVDX: msvdx_stat: 0x%x fence2_irq_on=%d ***** (MTX)\n", msvdx_stat, dev_priv->fence2_irq_on); /* Clear all interupt bits */ PSB_WMSVDX32(0xffff, MSVDX_INTERRUPT_CLEAR); PSB_RMSVDX32(MSVDX_INTERRUPT_CLEAR); DRM_READMEMORYBARRIER(); psb_msvdx_mtx_interrupt(dev); } }
/** * drm_vblank_count_and_time - retrieve "cooked" vblank counter value * and the system timestamp corresponding to that vblank counter value. * * @dev: DRM device * @crtc: which counter to retrieve * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. * * Fetches the "cooked" vblank count value that represents the number of * vblank events since the system was booted, including lost events due to * modesetting activity. Returns corresponding system timestamp of the time * of the vblank interval that corresponds to the current value vblank counter * value. */ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime) { u32 cur_vblank; /* Read timestamp from slot of _vblank_time ringbuffer * that corresponds to current vblank count. Retry if * count has incremented during readout. This works like * a seqlock. */ do { cur_vblank = atomic_read(&dev->_vblank_count[crtc]); *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); DRM_READMEMORYBARRIER(); } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); return cur_vblank; }