void psb_irq_uninstall(struct drm_device *dev) { struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); dev_priv->sgx_irq_mask = 0x00000000; dev_priv->sgx2_irq_mask = 0x00000000; dev_priv->vdc_irq_mask = 0x00000000; PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); PSB_WSGX32(dev_priv->sgx_irq_mask, PSB_CR_EVENT_HOST_ENABLE); PSB_WSGX32(dev_priv->sgx2_irq_mask, PSB_CR_EVENT_HOST_ENABLE2); wmb(); PSB_WVDC32(PSB_RVDC32(PSB_INT_IDENTITY_R), PSB_INT_IDENTITY_R); PSB_WSGX32(PSB_RSGX32(PSB_CR_EVENT_STATUS), PSB_CR_EVENT_HOST_CLEAR); PSB_WSGX32(PSB_RSGX32(PSB_CR_EVENT_STATUS2), PSB_CR_EVENT_HOST_CLEAR2); /****MSVDX IRQ Setup...*****/ /* Clear interrupt enabled flag */ PSB_WMSVDX32(0, MSVDX_HOST_INTERRUPT_ENABLE); dev_priv->irq_enabled = 0; spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); }
irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *)arg; struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; uint32_t vdc_stat; uint32_t sgx_stat; uint32_t sgx_stat2; uint32_t msvdx_stat; int handled = 0; spin_lock(&dev_priv->irqmask_lock); vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R); sgx_stat = PSB_RSGX32(PSB_CR_EVENT_STATUS); sgx_stat2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); msvdx_stat = PSB_RMSVDX32(MSVDX_INTERRUPT_STATUS); sgx_stat2 &= dev_priv->sgx2_irq_mask; sgx_stat &= dev_priv->sgx_irq_mask; PSB_WSGX32(sgx_stat2, PSB_CR_EVENT_HOST_CLEAR2); PSB_WSGX32(sgx_stat, PSB_CR_EVENT_HOST_CLEAR); (void)PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR); vdc_stat &= dev_priv->vdc_irq_mask; spin_unlock(&dev_priv->irqmask_lock); if (msvdx_stat) { psb_msvdx_interrupt(dev, msvdx_stat); handled = 1; } if (vdc_stat) { #ifdef PSB_DETEAR if(psb_blit_info.cmd_ready) { psb_blit_info.cmd_ready = 0; psb_blit_2d_reg_write(dev_priv, psb_blit_info.cmdbuf); /* to resume the blocked psb_cmdbuf_2d() */ set_bit(0, &psb_blit_info.vdc_bit); } #endif /* PSB_DETEAR */ /* MSVDX IRQ status is part of vdc_irq_mask */ psb_vdc_interrupt(dev, vdc_stat); handled = 1; } if (sgx_stat || sgx_stat2) { psb_sgx_interrupt(dev, sgx_stat, sgx_stat2); handled = 1; } if (!handled) { return IRQ_NONE; } return IRQ_HANDLED; }
static int psb_2d_wait_available(struct drm_psb_private *dev_priv, unsigned size) { uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF); unsigned long t = jiffies + HZ; while(avail < size) { avail = PSB_RSGX32(PSB_CR_2D_SOCIF); if (time_after(jiffies, t)) { psb_spank(dev_priv); return -EIO; } } return 0; }
/** * psb_2d_submit - submit a 2D command * @dev_priv: our DRM device * @cmdbuf: command to issue * @size: length (in dwords) * * Issue one or more 2D commands to the accelerator. This needs to be * serialized later when we add the GEM interfaces for acceleration */ static int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, unsigned size) { int ret = 0; int i; unsigned submit_size; unsigned long flags; spin_lock_irqsave(&dev_priv->lock_2d, flags); while (size > 0) { submit_size = (size < 0x60) ? size : 0x60; size -= submit_size; ret = psb_2d_wait_available(dev_priv, submit_size); if (ret) break; submit_size <<= 2; for (i = 0; i < submit_size; i += 4) PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i); (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4); } spin_unlock_irqrestore(&dev_priv->lock_2d, flags); return ret; }
void psb_irq_postinstall(struct drm_device *dev) { struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); PSB_WSGX32(dev_priv->sgx2_irq_mask, PSB_CR_EVENT_HOST_ENABLE2); PSB_WSGX32(dev_priv->sgx_irq_mask, PSB_CR_EVENT_HOST_ENABLE); (void)PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); /****MSVDX IRQ Setup...*****/ /* Enable Mtx Interupt to host */ { unsigned long enables = 0; PSB_DEBUG_GENERAL("Setting up MSVDX IRQs.....\n"); REGIO_WRITE_FIELD_LITE(enables, MSVDX_INTERRUPT_STATUS, CR_MTX_IRQ, 1); PSB_WMSVDX32(enables, MSVDX_HOST_INTERRUPT_ENABLE); } dev_priv->irq_enabled = 1; uint32_t hotplug_stat = PSB_RVDC32(PORT_HOTPLUG_ENABLE_REG); PSB_WVDC32(hotplug_stat | SDVOB_HOTPLUG_DETECT_ENABLE, PORT_HOTPLUG_ENABLE_REG); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); }
void psb_fence_handler(struct drm_device *dev, uint32_t fence_class) { struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; #ifdef FIX_TG_16 if (fence_class == 0) { struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; if ((atomic_read(&dev_priv->ta_wait_2d_irq) == 1) && (PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) psb_resume_ta_2d_idle(dev_priv); } #endif write_lock(&fm->lock); psb_fence_poll(dev, fence_class, fc->waiting_types); write_unlock(&fm->lock); }
void psb_msvdx_irq_on(struct drm_psb_private *dev_priv) { unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); if (dev_priv->irq_enabled) { dev_priv->vdc_irq_mask |= _PSB_IRQ_MSVDX_FLAG; PSB_WSGX32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); (void)PSB_RSGX32(PSB_INT_ENABLE_R); } spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); }
void psb_2D_irq_off(struct drm_psb_private *dev_priv) { unsigned long irqflags; uint32_t old_mask; uint32_t cleared_mask; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); --dev_priv->irqen_count_2d; if (dev_priv->irq_enabled && dev_priv->irqen_count_2d == 0) { old_mask = dev_priv->sgx_irq_mask; dev_priv->sgx_irq_mask &= ~_PSB_CE_TWOD_COMPLETE; PSB_WSGX32(dev_priv->sgx_irq_mask, PSB_CR_EVENT_HOST_ENABLE); (void)PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); cleared_mask = (old_mask ^ dev_priv->sgx_irq_mask) & old_mask; PSB_WSGX32(cleared_mask, PSB_CR_EVENT_HOST_CLEAR); (void)PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR); } spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); }
void psb_2D_irq_on(struct drm_psb_private *dev_priv) { unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); if (dev_priv->irq_enabled && dev_priv->irqen_count_2d == 0) { dev_priv->sgx_irq_mask |= _PSB_CE_TWOD_COMPLETE; PSB_WSGX32(dev_priv->sgx_irq_mask, PSB_CR_EVENT_HOST_ENABLE); (void)PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); } ++dev_priv->irqen_count_2d; spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); }
void psb_spank(struct drm_psb_private *dev_priv) { PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET | _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET | _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET); (void) PSB_RSGX32(PSB_CR_SOFT_RESET); msleep(1); PSB_WSGX32(0, PSB_CR_SOFT_RESET); wmb(); PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT, PSB_CR_BIF_CTRL); wmb(); (void) PSB_RSGX32(PSB_CR_BIF_CTRL); msleep(1); PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT, PSB_CR_BIF_CTRL); (void) PSB_RSGX32(PSB_CR_BIF_CTRL); PSB_WSGX32(dev_priv->pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); }
int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, unsigned size) { int ret = 0; int i; unsigned submit_size; while (size > 0) { submit_size = (size < 0x60) ? size : 0x60; size -= submit_size; ret = psb_2d_wait_available(dev_priv, submit_size); if (ret) return ret; submit_size <<= 2; for (i = 0; i < submit_size; i += 4) { PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i); } (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4); } return 0; }
int psbfb_sync(struct fb_info *info) { struct psb_fbdev *fbdev = info->par; struct psb_framebuffer *psbfb = fbdev->pfb; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; unsigned long _end = jiffies + DRM_HZ; int busy = 0; #if 0 /* Just a way to quickly test if cmd issue explodes */ u32 test[2] = { PSB_2D_FENCE_BH, }; psbfb_2d_submit(dev_priv, test, 1); #endif /* * First idle the 2D engine. */ if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) goto out; do { busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); cpu_relax(); } while (busy && !time_after_eq(jiffies, _end)); if (busy) busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); if (busy) goto out; do { busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) != 0); cpu_relax(); } while (busy && !time_after_eq(jiffies, _end)); if (busy) busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) != 0); out: return (busy) ? -EBUSY : 0; }
void psb_irq_preinstall(struct drm_device *dev) { struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; spin_lock(&dev_priv->irqmask_lock); PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); PSB_WVDC32(0x00000000, PSB_INT_MASK_R); PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE); (void)PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); dev_priv->sgx_irq_mask = _PSB_CE_PIXELBE_END_RENDER | _PSB_CE_DPM_3D_MEM_FREE | _PSB_CE_TA_FINISHED | _PSB_CE_DPM_REACHED_MEM_THRESH | _PSB_CE_DPM_OUT_OF_MEMORY_GBL | _PSB_CE_DPM_OUT_OF_MEMORY_MT | _PSB_CE_TA_TERMINATE | _PSB_CE_SW_EVENT; dev_priv->sgx2_irq_mask = _PSB_CE2_BIF_REQUESTER_FAULT; dev_priv->vdc_irq_mask = _PSB_IRQ_SGX_FLAG | _PSB_IRQ_MSVDX_FLAG | _PSB_HOTPLUG_INTERRUPT_ENABLE; if (!drm_psb_disable_vsync || drm_psb_detear) dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG | _PSB_VSYNC_PIPEB_FLAG; /*Clear MTX interrupt */ { unsigned long mtx_int = 0; REGIO_WRITE_FIELD_LITE(mtx_int, MSVDX_INTERRUPT_STATUS, CR_MTX_IRQ, 1); PSB_WMSVDX32(mtx_int, MSVDX_INTERRUPT_CLEAR); } spin_unlock(&dev_priv->irqmask_lock); }
/** * psbfb_sync - synchronize 2D * @info: our framebuffer * * Wait for the 2D engine to quiesce so that we can do CPU * access to the framebuffer again */ int psbfb_sync(struct fb_info *info) { struct psb_fbdev *fbdev = info->par; struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; unsigned long _end = jiffies + HZ; int busy = 0; unsigned long flags; spin_lock_irqsave(&dev_priv->lock_2d, flags); /* * First idle the 2D engine. */ if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) goto out; do { busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); cpu_relax(); } while (busy && !time_after_eq(jiffies, _end)); if (busy) busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); if (busy) goto out; do { busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) != 0); cpu_relax(); } while (busy && !time_after_eq(jiffies, _end)); if (busy) busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) != 0); out: spin_unlock_irqrestore(&dev_priv->lock_2d, flags); return (busy) ? -EBUSY : 0; }