static int pxa168fb_ovly_ioctl(struct fb_info *fi, unsigned int cmd,
			unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	struct pxa168fb_info *fbi = (struct pxa168fb_info *)fi->par;
	struct pxa168fb_mach_info *mi = fbi->dev->platform_data;
	int vid_on = 1;
	int val = 0, mask = 0;
	unsigned char param;
	int blendval = 0;
	int res, tmp;
	int ret = 0;
	unsigned long flags;

#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
	debug_identify_called_ioctl(fi, cmd, arg);
#endif

	switch (cmd) {
	case FB_IOCTL_CLEAR_FRAMEBUFFER:
		if (!mi->mmap)
			return -EINVAL;
		pxa168fb_clear_framebuffer(fi);
		return 0;
		break;
	case FB_IOCTL_WAIT_VSYNC:
		param = (arg & 0x3);
		wait_for_vsync(fbi, param);
		break;
	case FB_IOCTL_GET_VIEWPORT_INFO:/*if rotate 90/270, w/h swap*/
		mutex_lock(&fbi->access_ok);
		if (fbi->surface.viewPortInfo.rotation == 90 ||
			fbi->surface.viewPortInfo.rotation == 270) {
			tmp = fbi->surface.viewPortInfo.srcWidth;
			fbi->surface.viewPortInfo.srcWidth =
			fbi->surface.viewPortInfo.srcHeight;
			fbi->surface.viewPortInfo.srcHeight = tmp;
			fbi->surface.viewPortInfo.rotation = 360 -
			fbi->surface.viewPortInfo.rotation;
		}
		res = copy_to_user(argp, &fbi->surface.viewPortInfo,
			sizeof(struct _sViewPortInfo)) ? -EFAULT : 0;
		if (fbi->surface.viewPortInfo.rotation == 90 ||
			fbi->surface.viewPortInfo.rotation == 270) {
			tmp = fbi->surface.viewPortInfo.srcWidth;
			fbi->surface.viewPortInfo.srcWidth =
			fbi->surface.viewPortInfo.srcHeight;
			fbi->surface.viewPortInfo.srcHeight = tmp;
			fbi->surface.viewPortInfo.rotation = 360 -
			fbi->surface.viewPortInfo.rotation;
		}
		mutex_unlock(&fbi->access_ok);
		return res;
	case FB_IOCTL_SET_VIEWPORT_INFO:/*if rotate 90/270, w/h swap*/
		mutex_lock(&fbi->access_ok);
		memset(&gOvlySurface, 0, sizeof(gOvlySurface));
		gOvlySurface.videoMode = -1;
		if (copy_from_user(&gOvlySurface.viewPortInfo, argp,
				sizeof(gOvlySurface.viewPortInfo))) {
			mutex_unlock(&fbi->access_ok);
			return -EFAULT;
		}
		if (unsupport_format(fbi, gOvlySurface.viewPortInfo, -1)) {
			mutex_unlock(&fbi->access_ok);
			return -EFAULT;
		}
		gOvlySurface.viewPortInfo.rotation =
		 (360 - gOvlySurface.viewPortInfo.rotation) % 360;
		if (gOvlySurface.viewPortInfo.rotation == 90 ||
			gOvlySurface.viewPortInfo.rotation == 270) {
			tmp = gOvlySurface.viewPortInfo.srcWidth;
			gOvlySurface.viewPortInfo.srcWidth =
			gOvlySurface.viewPortInfo.srcHeight;
			gOvlySurface.viewPortInfo.srcHeight = tmp;
		}

		ret = check_surface(fi, &gOvlySurface);
		if (ret > 0) {
			pxa168fb_set_par(fi);
			ret = 0;
		} else if (ret < 0) {
			pr_err("fbi %d (line %d): vid %d, check surface"
				"return error\n", fbi->id, __LINE__, fbi->vid);
			ret = -EFAULT;
		}
		mutex_unlock(&fbi->access_ok);
		return ret;
		break;
	case FB_IOCTL_SET_VIDEO_MODE:
		/*
		 * Get data from user space.
		 */
		memset(&gOvlySurface, 0, sizeof(gOvlySurface));
		if (copy_from_user(&gOvlySurface.videoMode, argp,
				 sizeof(gOvlySurface.videoMode)))
			return -EFAULT;

		if (unsupport_format(fbi, gOvlySurface.viewPortInfo,
			 gOvlySurface.videoMode))
			return -EFAULT;
		ret = check_surface(fi, &gOvlySurface);
		if (ret > 0) {
			pxa168fb_set_par(fi);
			ret = 0;
		} else if (ret < 0) {
			pr_err("fbi %d (line %d): vid %d, check surface"
				"return error\n", fbi->id, __LINE__, fbi->vid);
			ret = -EFAULT;
		}
		return ret;
		break;
	case FB_IOCTL_GET_VIDEO_MODE:
		return copy_to_user(argp, &fbi->surface.videoMode,
			sizeof(u32)) ? -EFAULT : 0;
	case FB_IOCTL_FLIP_VID_BUFFER:
		return flip_buffer(fi, arg);
	case FB_IOCTL_GET_FREELIST:
		return get_freelist(fi, arg);
	case FB_IOCTL_FLIP_VSYNC:
		return flip_buffer_vsync(fi, arg);
	case FB_IOCTL_GET_BUFF_ADDR:
	{
		return copy_to_user(argp, &fbi->surface.videoBufferAddr,
			sizeof(struct _sVideoBufferAddr)) ? -EFAULT : 0;
	}
	case FB_IOCTL_SET_VID_OFFSET:
		mutex_lock(&fbi->access_ok);
		memset(&gOvlySurface, 0, sizeof(gOvlySurface));
		gOvlySurface.videoMode = -1;
		if (copy_from_user(&gOvlySurface.viewPortOffset, argp,
				sizeof(gOvlySurface.viewPortOffset))) {
			mutex_unlock(&fbi->access_ok);
			return -EFAULT;
		}

		ret = check_surface(fi, &gOvlySurface);
		if (ret > 0) {
			pxa168fb_set_par(fi);
			ret = 0;
		} else if (ret < 0) {
			pr_err("fbi %d (line %d): vid %d, check surface"
				"return error\n", fbi->id, __LINE__, fbi->vid);
			ret = -EFAULT;
		}
		mutex_unlock(&fbi->access_ok);
		return ret;
		break;
	case FB_IOCTL_GET_VID_OFFSET:
		return copy_to_user(argp, &fbi->surface.viewPortOffset,
			sizeof(struct _sViewPortOffset)) ? -EFAULT : 0;

	case FB_IOCTL_SET_SURFACE:
	{
		mutex_lock(&fbi->access_ok);
		/* Get user-mode data. */
		if (copy_from_user(&fbi->surface_bak, argp,
					sizeof(struct _sOvlySurface))) {
			mutex_unlock(&fbi->access_ok);
			return -EFAULT;
		}
		fbi->surface_set = 1;

		mutex_unlock(&fbi->access_ok);
		return 0;
	}
	case FB_IOCTL_GET_SURFACE:
	{
		mutex_lock(&fbi->access_ok);
		if (fbi->surface_set) {
			ret = copy_to_user(argp, &fbi->surface_bak,
				sizeof(struct _sOvlySurface));
		} else {
		    ret = copy_to_user(argp, &fbi->surface,
				sizeof(struct _sOvlySurface));
		}

		ret = (ret ? -EFAULT : 0);
		mutex_unlock(&fbi->access_ok);
		return ret;
	}

	case FB_IOCTL_SET_COLORKEYnALPHA:
		if (copy_from_user(&fbi->ckey_alpha, argp,
		    sizeof(struct _sColorKeyNAlpha)))
			return -EFAULT;

		pxa168fb_ovly_set_colorkeyalpha(fbi);
		break;

	case FB_IOCTL_GET_COLORKEYnALPHA:
		if (copy_to_user(argp, &fbi->ckey_alpha,
		    sizeof(struct _sColorKeyNAlpha)))
			return -EFAULT;
		break;
	case FB_IOCTL_SWITCH_VID_OVLY:
		if (copy_from_user(&vid_on, argp, sizeof(int)))
			return -EFAULT;
		spin_lock_irqsave(&fbi->var_lock, flags);
		mask = CFG_DMA_ENA_MASK;

		fbi->dma_on = vid_on ? 1 : 0;
		val = CFG_DMA_ENA(check_modex_active(fbi));
		if (!val && gfx_info.fbi[0]->active) {
			pxa688_vdma_release(fbi->id, fbi->vid);
			/* switch off, disable DMA */
			dma_ctrl_set(fbi->id, 0, mask, val);
		} else if (list_empty(&fbi->buf_waitlist.dma_queue) &&
			!fbi->buf_current)
			/* switch on, but no buf flipped, return error */
			; /* ret = -EAGAIN; */

		printk(KERN_DEBUG "SWITCH_VID_OVLY fbi %d dma_on %d,"
			" val %d, waitlist empty %d buf_current %p, ret %d\n",
			fbi->id, fbi->dma_on, val,
			list_empty(&fbi->buf_waitlist.dma_queue),
			fbi->buf_current, ret);

		pxa688fb_vsmooth_set(fbi->id, 1, vid_vsmooth & vid_on);

		spin_unlock_irqrestore(&fbi->var_lock, flags);
		return ret;
		break;

	case FB_IOCTL_SWAP_VIDEO_RED_BLUE:
		param = (arg & 0x1);
		dma_ctrl_set(fbi->id, 0, CFG_DMA_SWAPRB_MASK,
				 CFG_DMA_SWAPRB(param));
		return 0;
		break;

	case FB_IOCTL_SWAP_VIDEO_U_V:
		param = (arg & 0x1);
		dma_ctrl_set(fbi->id, 0, CFG_DMA_SWAPUV_MASK,
				 CFG_DMA_SWAPUV(param));
		return 0;
		break;

	case FB_IOCTL_SWAP_VIDEO_Y_UV:
		param = (arg & 0x1);
		dma_ctrl_set(fbi->id, 0, CFG_DMA_SWAPYU_MASK,
				 CFG_DMA_SWAPYU(param));
		return 0;
		break;

	case FB_IOCTL_PUT_VIDEO_ALPHABLEND:
		/*
		 *  This puts the blending control to the Video layer.
		 */
		mask = CFG_ALPHA_MODE_MASK | CFG_ALPHA_MASK;
		val = CFG_ALPHA_MODE(0) | CFG_ALPHA(0xff);
		dma_ctrl_set(fbi->id, 1, mask, val);
		return 0;
		break;

	case FB_IOCTL_PUT_GLOBAL_ALPHABLEND:
		/*
		 *  The userspace application can specify a byte value for the
		 *  amount of global blend between the video layer and thei
		 *  graphic layer.
		 *
		 *  The alpha blending is per the formula below:
		 *  P = (V[P] * blendval/255) + (G[P] * (1 - blendval/255))
		 *  where: P = Pixel value, V = Video Layer,
		 *  and G = Graphic Layer
		 */
		blendval = (arg & 0xff);
		mask = CFG_ALPHA_MODE_MASK | CFG_ALPHA_MASK;
		val = CFG_ALPHA_MODE(2) | CFG_ALPHA(blendval);
		dma_ctrl_set(fbi->id, 1, mask, val);
		return 0;
		break;

	case FB_IOCTL_PUT_GRAPHIC_ALPHABLEND:
		/*
		 *  This puts the blending back to the default mode of allowing
		 *  the graphic layer to do pixel level blending.
		 */
		mask = CFG_ALPHA_MODE_MASK | CFG_ALPHA_MASK;
		val = CFG_ALPHA_MODE(1) | CFG_ALPHA(0x0);
		dma_ctrl_set(fbi->id, 1, mask, val);
		return 0;
		break;

	default:
		break;
	}

	return 0;
}
Exemplo n.º 2
0
static u32 dovefb_ovly_set_colorkeyalpha(struct dovefb_layer_info *dfli)
{
	unsigned int rb;
	unsigned int temp;
	unsigned int x, x_ckey;
	struct _sColorKeyNAlpha *color_a = &dfli->ckey_alpha;

	/* reset to 0x0 to disable color key. */
	x = readl(dfli->reg_base + LCD_SPU_DMA_CTRL1) &
		~(CFG_COLOR_KEY_MASK | CFG_ALPHA_MODE_MASK | CFG_ALPHA_MASK);

	/* switch to color key mode */
	switch (color_a->mode) {
	case DOVEFB_DISABLE_COLORKEY_MODE:
		/* do nothing */
		break;
	case DOVEFB_ENABLE_Y_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x1);
		break;
	case DOVEFB_ENABLE_U_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x2);
		break;
	case DOVEFB_ENABLE_V_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x4);
		break;
	case DOVEFB_ENABLE_RGB_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x3);
		/* check whether h/w turn on RB swap. */
		rb = readl(dfli->reg_base + LCD_SPU_DMA_CTRL0);
		if (rb & CFG_DMA_SWAPRB_MASK) {
			/* exchange r b fields. */
			temp = color_a->Y_ColorAlpha;
			color_a->Y_ColorAlpha = color_a->V_ColorAlpha;
			color_a->V_ColorAlpha = temp;
		}
		break;
	case DOVEFB_ENABLE_R_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x5);
		break;
	case DOVEFB_ENABLE_G_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x6);
	break;
	case DOVEFB_ENABLE_B_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x7);
		break;
	default:
		pr_debug("unknown mode");
		return -1;
	}

	/* switch to alpha path selection */
	switch (color_a->alphapath) {
	case DOVEFB_VID_PATH_ALPHA:
		x |= CFG_ALPHA_MODE(0x0);
		break;
	case DOVEFB_GRA_PATH_ALPHA:
		x |= CFG_ALPHA_MODE(0x1);
		break;
	case DOVEFB_CONFIG_ALPHA:
		x |= CFG_ALPHA_MODE(0x2);
		break;
	default:
		pr_debug("unknown alpha path");
		return -1;
	}

	/* configure alpha */
	x |= CFG_ALPHA((color_a->config & 0xff));

	/* Have to program new regs to enable color key for new chip. */
	x_ckey = readl(dfli->reg_base + LCD_SPU_ADV_REG);
	writel(x_ckey | (0x1 << 19), dfli->reg_base + LCD_SPU_ADV_REG);

	writel(x, dfli->reg_base + LCD_SPU_DMA_CTRL1);
	writel(color_a->Y_ColorAlpha, dfli->reg_base + LCD_SPU_COLORKEY_Y);
	writel(color_a->U_ColorAlpha, dfli->reg_base + LCD_SPU_COLORKEY_U);
	writel(color_a->V_ColorAlpha, dfli->reg_base + LCD_SPU_COLORKEY_V);

	return 0;
}
static u32 pxa168fb_ovly_set_colorkeyalpha(struct pxa168fb_info *fbi)
{
	struct _sColorKeyNAlpha color_a = fbi->ckey_alpha;
	unsigned int rb, x, layer, dma0, shift, r, b;
	struct pxa168fb_mach_info *mi;
	struct lcd_regs *regs;

	dev_dbg(fbi->fb_info->dev, "Enter %s\n", __func__);

	mi = fbi->dev->platform_data;
	regs = get_regs(fbi->id);
	dma0 = dma_ctrl_read(fbi->id, 0);
	shift = fbi->id ? 20 : 18;
	rb = layer = 0;
	r = color_a.Y_ColorAlpha;
	b = color_a.V_ColorAlpha;

	/* reset to 0x0 to disable color key. */
	x = dma_ctrl_read(fbi->id, 1) & ~(CFG_COLOR_KEY_MASK |
			CFG_ALPHA_MODE_MASK | CFG_ALPHA_MASK);

	/* switch to color key mode */
	switch (color_a.mode) {
	case FB_DISABLE_COLORKEY_MODE:
		/* do nothing */
		break;
	case FB_ENABLE_Y_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x1);
		break;
	case FB_ENABLE_U_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x2);
		break;
	case FB_ENABLE_V_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x4);
		pr_info("V colorkey not supported, Chroma key instead\n");
		break;
	case FB_ENABLE_RGB_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x3);
		rb = 1;
		break;
	case FB_ENABLE_R_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x1);
		rb = 1;
		break;
	case FB_ENABLE_G_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x6);
		pr_info("G colorkey not supported, Luma key instead\n");
		break;
	case FB_ENABLE_B_COLORKEY_MODE:
		x |= CFG_COLOR_KEY_MODE(0x7);
		rb = 1;
		break;
	default:
		pr_info("unknown mode");
		return -1;
	}


	/* switch to alpha path selection */
	switch (color_a.alphapath) {
	case FB_VID_PATH_ALPHA:
		x |= CFG_ALPHA_MODE(0x0);
		layer = CFG_CKEY_DMA;
		if (rb)
			rb = ((dma0 & CFG_DMA_SWAPRB_MASK) >> 4) ^
				(mi->panel_rbswap);
		break;
	case FB_GRA_PATH_ALPHA:
		x |= CFG_ALPHA_MODE(0x1);
		layer = CFG_CKEY_GRA;
		if (rb)
			rb = ((dma0 & CFG_GRA_SWAPRB_MASK) >> 12) ^
				(mi->panel_rbswap);
		break;
	case FB_CONFIG_ALPHA:
		x |= CFG_ALPHA_MODE(0x2);
		rb = 0;
		break;
	default:
		pr_info("unknown alpha path");
		return -1;
	}

	/* check whether DMA turn on RB swap for this pixelformat. */
	if (rb) {
		if (color_a.mode == FB_ENABLE_R_COLORKEY_MODE) {
			x &= ~CFG_COLOR_KEY_MODE(0x1);
			x |= CFG_COLOR_KEY_MODE(0x7);
		}

		if (color_a.mode == FB_ENABLE_B_COLORKEY_MODE) {
			x &= ~CFG_COLOR_KEY_MODE(0x7);
			x |= CFG_COLOR_KEY_MODE(0x1);
		}

		/* exchange r b fields. */
		r = color_a.V_ColorAlpha;
		b = color_a.Y_ColorAlpha;

		/* only alpha_Y take effect, switch back from V */
		if (color_a.mode == FB_ENABLE_RGB_COLORKEY_MODE) {
			r &= 0xffffff00;
			r |= (color_a.Y_ColorAlpha & 0xff);
		}
	}

	/* configure alpha */
	x |= CFG_ALPHA((color_a.config & 0xff));
	dma_ctrl_write(fbi->id, 1, x);
	writel(r, &regs->v_colorkey_y);
	writel(color_a.U_ColorAlpha, &regs->v_colorkey_u);
	writel(b, &regs->v_colorkey_v);

	if (fbi->id != 2) {
		/* enable DMA colorkey on graphics/video layer
		 * in panel/TV path */
		x = readl(fbi->reg_base + LCD_TV_CTRL1);
		x &= ~(3<<shift); x |= layer<<shift;
		writel(x, fbi->reg_base + LCD_TV_CTRL1);
	}

	return 0;
}