예제 #1
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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);

}
예제 #2
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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;
}
예제 #3
0
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;
}
예제 #4
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;
}
예제 #5
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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);
}
예제 #6
0
파일: psb_fence.c 프로젝트: gregkh/psb-kmp
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);
}
예제 #7
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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);
}
예제 #8
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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);
}
예제 #9
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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);
}
예제 #10
0
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);
}
예제 #11
0
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;
}
예제 #12
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;
}
예제 #13
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
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);
}
예제 #14
0
/**
 *	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;
}