* [PATCH v2] ARM: i.mx: mx3fb: add overlay support
@ 2012-04-22 13:31 ` Alex Gershgorin
0 siblings, 0 replies; 2+ messages in thread
From: Alex Gershgorin @ 2012-04-22 13:31 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: g.liakhovetski, s.hauer, laurent.pinchart, linux-fbdev,
linux-media, Alex Gershgorin
This work is based on some earlier patch series
"i.MX31: dmaengine and framebuffer drivers" from 2008
by Guennadi Liakhovetski, the patch initializes overlay channel,
adds ioctl for configuring transparency of the overlay and graphics
planes, CONFIG_FB_MX3_OVERLAY is also supported.
In case that CONFIG_FB_MX3_OVERLAY is not defined, mx3fb is completely
backward compatible.
Blend mode, only global alpha blending has been tested.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Alex Gershgorin <alexg@meprolight.com>
---
Applies to v3.4-rc4
Changes since v1:
*Some fixes after review
*Added ioctl for setting overlay windows position
---
drivers/video/Kconfig | 7 +
drivers/video/mx3fb.c | 346 ++++++++++++++++++++++++++++++++++++++++++++----
include/linux/mxcfb.h | 40 ++++++
3 files changed, 364 insertions(+), 29 deletions(-)
create mode 100644 include/linux/mxcfb.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a290be5..acbfccc 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2368,6 +2368,13 @@ config FB_MX3
far only synchronous displays are supported. If you plan to use
an LCD display with your i.MX31 system, say Y here.
+config FB_MX3_OVERLAY
+ bool "MX3 Overlay support"
+ default n
+ depends on FB_MX3
+ ---help---
+ Say Y here to enable overlay support
+
config FB_BROADSHEET
tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
depends on FB
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index eec0d7b..09d7885 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -26,6 +26,7 @@
#include <linux/console.h>
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <linux/mxcfb.h>
#include <mach/dma.h>
#include <mach/hardware.h>
@@ -238,6 +239,7 @@ static const struct fb_videomode mx3fb_modedb[] = {
struct mx3fb_data {
struct fb_info *fbi;
+ struct fb_info *fbi_ovl;
int backlight_level;
void __iomem *reg_base;
spinlock_t lock;
@@ -246,6 +248,9 @@ struct mx3fb_data {
uint32_t h_start_width;
uint32_t v_start_width;
enum disp_data_mapping disp_data_fmt;
+
+ /* IDMAC / dmaengine interface */
+ struct idmac_channel *idmac_channel[2]; /* We need 2 channels */
};
struct dma_chan_request {
@@ -268,10 +273,19 @@ struct mx3fb_info {
struct dma_async_tx_descriptor *txd;
dma_cookie_t cookie;
struct scatterlist sg[2];
+ struct list_head ovl_list; /* overlay buffer list */
u32 sync; /* preserve var->sync flags */
};
+/* Allocated overlay buffer */
+struct mx3fb_alloc_list {
+ struct list_head list;
+ dma_addr_t phy_addr;
+ void *cpu_addr;
+ size_t size;
+};
+
static void mx3fb_dma_done(void *);
/* Used fb-mode and bpp. Can be set on kernel command line, therefore file-static. */
@@ -303,7 +317,13 @@ static void sdc_fb_init(struct mx3fb_info *fbi)
struct mx3fb_data *mx3fb = fbi->mx3fb;
uint32_t reg;
- reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
+ reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF) & ~SDC_COM_GWSEL;
+
+ /* Also enable foreground for overlay graphic window is foreground */
+ if (mx3fb->fbi_ovl && fbi == mx3fb->fbi_ovl->par) {
+ reg |= SDC_COM_FG_EN | SDC_COM_GWSEL;
+ INIT_LIST_HEAD(&fbi->ovl_list);
+ }
mx3fb_write_reg(mx3fb, reg | SDC_COM_BG_EN, SDC_COM_CONF);
}
@@ -312,13 +332,24 @@ static void sdc_fb_init(struct mx3fb_info *fbi)
static uint32_t sdc_fb_uninit(struct mx3fb_info *fbi)
{
struct mx3fb_data *mx3fb = fbi->mx3fb;
- uint32_t reg;
+ uint32_t reg, chan_mask;
reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
- mx3fb_write_reg(mx3fb, reg & ~SDC_COM_BG_EN, SDC_COM_CONF);
+ /*
+ * Don't we have to automatically disable overlay when disabling
+ * background? Attention: cannot test mx3fb->fbi_ovl->par, must
+ * test mx3fb->fbi->par, because at the time this function is
+ * called for the first time fbi_ovl is not assigned yet.
+ */
+ if (fbi == mx3fb->fbi->par)
+ chan_mask = SDC_COM_BG_EN;
+ else
+ chan_mask = SDC_COM_FG_EN | SDC_COM_GWSEL;
+
+ mx3fb_write_reg(mx3fb, reg & ~chan_mask, SDC_COM_CONF);
- return reg & SDC_COM_BG_EN;
+ return reg & chan_mask;
}
static void sdc_enable_channel(struct mx3fb_info *mx3_fbi)
@@ -412,13 +443,33 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel,
int16_t x_pos, int16_t y_pos)
{
- if (channel != IDMAC_SDC_0)
- return -EINVAL;
-
x_pos += mx3fb->h_start_width;
y_pos += mx3fb->v_start_width;
- mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
+/*
+ If the overlay is defined, we just need to swap
+ the window position register relative to DMAC channel ID
+*/
+ switch (channel) {
+#ifndef CONFIG_FB_MX3_OVERLAY
+ case IDMAC_SDC_0:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
+ break;
+ case IDMAC_SDC_1:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_FG_POS);
+ break;
+#else
+ case IDMAC_SDC_0:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_FG_POS);
+ break;
+ case IDMAC_SDC_1:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
return 0;
}
@@ -482,14 +533,17 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
mx3fb->h_start_width = h_start_width;
mx3fb->v_start_width = v_start_width;
+ reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
+
switch (panel) {
case IPU_PANEL_SHARP_TFT:
mx3fb_write_reg(mx3fb, 0x00FD0102L, SDC_SHARP_CONF_1);
mx3fb_write_reg(mx3fb, 0x00F500F4L, SDC_SHARP_CONF_2);
- mx3fb_write_reg(mx3fb, SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
+ mx3fb_write_reg(mx3fb, reg | SDC_COM_SHARP |
+ SDC_COM_TFT_COLOR, SDC_COM_CONF);
break;
case IPU_PANEL_TFT:
- mx3fb_write_reg(mx3fb, SDC_COM_TFT_COLOR, SDC_COM_CONF);
+ mx3fb_write_reg(mx3fb, reg | SDC_COM_TFT_COLOR, SDC_COM_CONF);
break;
default:
return -EINVAL;
@@ -563,13 +617,12 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
/**
* sdc_set_color_key() - set the transparent color key for SDC graphic plane.
* @mx3fb: mx3fb context.
- * @channel: IPU DMAC channel ID.
* @enable: boolean to enable or disable color keyl.
* @color_key: 24-bit RGB color to use as transparent color key.
* @return: 0 on success or negative error code on failure.
*/
-static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,
- bool enable, uint32_t color_key)
+static int sdc_set_color_key(struct mx3fb_data *mx3fb, bool enable,
+ uint32_t color_key)
{
uint32_t reg, sdc_conf;
unsigned long lock_flags;
@@ -577,10 +630,6 @@ static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,
spin_lock_irqsave(&mx3fb->lock, lock_flags);
sdc_conf = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
- if (channel == IDMAC_SDC_0)
- sdc_conf &= ~SDC_COM_GWSEL;
- else
- sdc_conf |= SDC_COM_GWSEL;
if (enable) {
reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0xFF000000L;
@@ -668,8 +717,16 @@ static int mx3fb_set_fix(struct fb_info *fbi)
{
struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var;
+ struct mx3fb_info *mx3_fbi = fbi->par;
+#ifndef CONFIG_FB_MX3_OVERLAY
strncpy(fix->id, "DISP3 BG", 8);
+#else
+ if (mx3_fbi->ipu_ch == IDMAC_SDC_1)
+ strncpy(fix->id, "DISP3 BG", 8);
+ else
+ strncpy(fix->id, "DISP3 FG", 8);
+#endif
fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
@@ -689,13 +746,25 @@ static void mx3fb_dma_done(void *arg)
struct idmac_channel *ichannel = to_idmac_chan(chan);
struct mx3fb_data *mx3fb = ichannel->client;
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ struct mx3fb_info *mx3_fbi_cur;
+ struct mx3fb_info *mx3_fbi_ovl = mx3fb->fbi_ovl ? mx3fb->fbi_ovl->par :
+ NULL;
dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq);
+ if (ichannel == mx3_fbi->idmac_channel) {
+ mx3_fbi_cur = mx3_fbi;
+ } else if (mx3_fbi_ovl && ichannel == mx3_fbi_ovl->idmac_channel) {
+ mx3_fbi_cur = mx3_fbi_ovl;
+ } else {
+ WARN(1, "Cannot identify channel!\n");
+ return;
+ }
+
/* We only need one interrupt, it will be re-enabled as needed */
disable_irq_nosync(ichannel->eof_irq);
- complete(&mx3_fbi->flip_cmpl);
+ complete(&mx3_fbi_cur->flip_cmpl);
}
static int __set_par(struct fb_info *fbi, bool lock)
@@ -1151,6 +1220,157 @@ static struct fb_ops mx3fb_ops = {
.fb_blank = mx3fb_blank,
};
+#ifdef CONFIG_FB_MX3_OVERLAY
+static int mx3fb_blank_ovl(int blank, struct fb_info *fbi)
+{
+ struct mx3fb_info *mx3_fbi = fbi->par;
+
+ dev_dbg(fbi->device, "ovl blank = %d\n", blank);
+
+ if (mx3_fbi->blank == blank)
+ return 0;
+
+ mutex_lock(&mx3_fbi->mutex);
+ mx3_fbi->blank = blank;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ sdc_disable_channel(mx3_fbi);
+ break;
+ case FB_BLANK_UNBLANK:
+ sdc_enable_channel(mx3_fbi);
+ break;
+ }
+ mutex_unlock(&mx3_fbi->mutex);
+
+ return 0;
+}
+
+/*
+ * Function to handle custom ioctls for MX3 framebuffer.
+ *
+ * @inode inode struct
+ * @file file struct
+ * @cmd Ioctl command to handle
+ * @arg User pointer to command arguments
+ * @fbi framebuffer information pointer
+ */
+static int mx3fb_ioctl_ovl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mx3fb_info *mx3_fbi = fbi->par;
+ struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
+ int retval = 0;
+ int __user *argp = (void __user *)arg;
+ struct mx3fb_alloc_list *mem;
+ int size;
+ unsigned long offset;
+ union {
+ struct mxcfb_pos pos;
+ struct mxcfb_gbl_alpha ga;
+ struct mxcfb_color_key key;
+ } s;
+
+ switch (cmd) {
+ case FBIO_ALLOC:
+ if (get_user(size, argp))
+ return -EFAULT;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ mem->size = PAGE_ALIGN(size);
+
+ mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
+ &mem->phy_addr,
+ GFP_DMA);
+ if (mem->cpu_addr == NULL) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+
+ mutex_lock(&mx3_fbi->mutex);
+ list_add(&mem->list, &mx3_fbi->ovl_list);
+ mutex_unlock(&mx3_fbi->mutex);
+
+ dev_dbg(fbi->device, "allocated %d bytes <at> 0x%08X\n",
+ mem->size, mem->phy_addr);
+
+ if (put_user(mem->phy_addr, argp))
+ return -EFAULT;
+
+ break;
+ case FBIO_FREE:
+ if (get_user(offset, argp))
+ return -EFAULT;
+
+ retval = -EINVAL;
+ mutex_lock(&mx3_fbi->mutex);
+ list_for_each_entry(mem, &mx3_fbi->ovl_list, list) {
+ if (mem->phy_addr == offset) {
+ list_del(&mem->list);
+ dma_free_coherent(fbi->device,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ retval = 0;
+ break;
+ }
+ }
+ mutex_unlock(&mx3_fbi->mutex);
+
+ break;
+ case MXCFB_SET_GBL_ALPHA:
+ if (copy_from_user(&s.ga, (void *)arg, sizeof(s.ga)))
+ retval = -EFAULT;
+
+ sdc_set_global_alpha(mx3fb, (bool)s.ga.enable, s.ga.alpha);
+ dev_dbg(fbi->device, "Set global alpha to %d\n", s.ga.alpha);
+
+ break;
+ case MXCFB_SET_CLR_KEY:
+ if (copy_from_user(&s.key, (void *)arg, sizeof(s.key)))
+ retval = -EFAULT;
+
+ sdc_set_color_key(mx3fb, (bool)s.key.enable, s.key.color_key);
+ dev_dbg(fbi->device, "Set color key to %d\n", s.key.color_key);
+
+ break;
+ case MXCFB_SET_OVERLAY_POS:
+ if (copy_from_user(&s.pos, (void *)arg, sizeof(s.pos)))
+ retval = -EFAULT;
+
+ sdc_set_window_pos(mx3fb, mx3_fbi->ipu_ch, s.pos.x, s.pos.y);
+ dev_dbg(fbi->device, "Set win position to posx=%d, posy=%d\n",
+ s.pos.x, s.pos.y);
+
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+static struct fb_ops mx3fb_ovl_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_par = mx3fb_set_par,
+ .fb_check_var = mx3fb_check_var,
+ .fb_setcolreg = mx3fb_setcolreg,
+ .fb_pan_display = mx3fb_pan_display,
+ .fb_ioctl = mx3fb_ioctl_ovl,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = mx3fb_blank_ovl,
+};
+#endif
+
#ifdef CONFIG_PM
/*
* Power management hooks. Note that we won't be called from IRQ context,
@@ -1164,11 +1384,16 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ struct mx3fb_info *mx3_fbi_ovl = mx3fb->fbi_ovl->par;
console_lock();
fb_set_suspend(mx3fb->fbi, 1);
+ fb_set_suspend(mx3fb->fbi_ovl, 1);
console_unlock();
+ if (mx3_fbi_ovl->blank == FB_BLANK_UNBLANK)
+ sdc_disable_channel(mx3_fbi_ovl);
+
if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
sdc_disable_channel(mx3_fbi);
sdc_set_brightness(mx3fb, 0);
@@ -1184,14 +1409,19 @@ static int mx3fb_resume(struct platform_device *pdev)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ struct mx3fb_info *mx3_fbi_ovl = mx3fb->fbi_ovl->par;
if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
sdc_enable_channel(mx3_fbi);
sdc_set_brightness(mx3fb, mx3fb->backlight_level);
}
+ if (mx3_fbi_ovl->blank == FB_BLANK_UNBLANK)
+ sdc_enable_channel(mx3_fbi_ovl);
+
console_lock();
fb_set_suspend(mx3fb->fbi, 0);
+ fb_set_suspend(mx3fb->fbi_ovl, 0);
console_unlock();
return 0;
@@ -1333,8 +1563,9 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
ichan->client = mx3fb;
irq = ichan->eof_irq;
- if (ichan->dma_chan.chan_id != IDMAC_SDC_0)
- return -EINVAL;
+ switch (ichan->dma_chan.chan_id) {
+
+ case IDMAC_SDC_0:
fbi = mx3fb_init_fbinfo(dev, &mx3fb_ops);
if (!fbi)
@@ -1375,7 +1606,29 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
sdc_set_brightness(mx3fb, 255);
sdc_set_global_alpha(mx3fb, true, 0xFF);
- sdc_set_color_key(mx3fb, IDMAC_SDC_0, false, 0);
+ sdc_set_color_key(mx3fb, false, 0);
+
+ break;
+#ifdef CONFIG_FB_MX3_OVERLAY
+ case IDMAC_SDC_1:
+
+ /* We know, that background has been allocated already! */
+ fbi = mx3fb_init_fbinfo(dev, &mx3fb_ovl_ops);
+ if (!fbi)
+ return -ENOMEM;
+
+ /* Default Y virtual size is 2x panel size */
+ fbi->var = mx3fb->fbi->var;
+ /* This shouldn't be necessary, it is already set up above */
+ fbi->var.yres_virtual = mx3fb->fbi->var.yres * 2;
+
+ mx3fb->fbi_ovl = fbi;
+
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
mx3fbi = fbi->par;
mx3fbi->idmac_channel = ichan;
@@ -1392,9 +1645,13 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
if (ret < 0)
goto esetpar;
- __blank(FB_BLANK_UNBLANK, fbi);
+ /* Overlay stays blanked by default */
+ if (ichan->dma_chan.chan_id == IDMAC_SDC_0) {
+ mx3fb_blank(FB_BLANK_UNBLANK, fbi);
- dev_info(dev, "registered, using mode %s\n", fb_mode);
+ dev_info(dev, "mx3fb: fb registered, using mode %s [%c]\n",
+ fb_mode, list_empty(&ichan->queue) ? '-' : '+');
+ }
ret = register_framebuffer(fbi);
if (ret < 0)
@@ -1492,14 +1749,42 @@ static int mx3fb_probe(struct platform_device *pdev)
mx3fb->backlight_level = 255;
+ mx3fb->idmac_channel[0] = to_idmac_chan(chan);
+ mx3fb->idmac_channel[0]->client = mx3fb;
+
ret = init_fb_chan(mx3fb, to_idmac_chan(chan));
if (ret < 0)
goto eisdc0;
+#ifdef CONFIG_FB_MX3_OVERLAY
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ rq.id = IDMAC_SDC_1;
+ chan = dma_request_channel(mask, chan_filter, &rq);
+ if (!chan) {
+ ret = -EBUSY;
+ goto ersdc1;
+ }
+
+ mx3fb->idmac_channel[1] = to_idmac_chan(chan);
+ mx3fb->idmac_channel[1]->client = mx3fb;
+
+ ret = init_fb_chan(mx3fb, to_idmac_chan(chan));
+ if (ret < 0)
+ goto eisdc1;
+#endif
+
return 0;
+#ifdef CONFIG_FB_MX3_OVERLAY
+eisdc1:
+ dma_release_channel(&mx3fb->idmac_channel[1]->dma_chan);
+ersdc1:
+ release_fbi(mx3fb->fbi);
+#endif
eisdc0:
- dma_release_channel(chan);
+ dma_release_channel(&mx3fb->idmac_channel[0]->dma_chan);
ersdc0:
dmaengine_put();
iounmap(mx3fb->reg_base);
@@ -1513,13 +1798,16 @@ static int mx3fb_remove(struct platform_device *dev)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(dev);
struct fb_info *fbi = mx3fb->fbi;
- struct mx3fb_info *mx3_fbi = fbi->par;
- struct dma_chan *chan;
- chan = &mx3_fbi->idmac_channel->dma_chan;
- release_fbi(fbi);
+ if (fbi)
+ release_fbi(fbi);
+
+ fbi = mx3fb->fbi_ovl;
+ if (fbi)
+ release_fbi(fbi);
- dma_release_channel(chan);
+ dma_release_channel(&mx3fb->idmac_channel[1]->dma_chan);
+ dma_release_channel(&mx3fb->idmac_channel[0]->dma_chan);
dmaengine_put();
iounmap(mx3fb->reg_base);
diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h
new file mode 100644
index 0000000..b5b681f
--- /dev/null
+++ b/include/linux/mxcfb.h
@@ -0,0 +1,40 @@
+/*
+ * File: include/linux/mxcfb.h
+ * Global header file for the MXC Framebuffer
+ *
+ * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __LINUX_MXCFB_H__
+#define __LINUX_MXCFB_H__
+
+struct mxcfb_gbl_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mxcfb_color_key {
+ int enable;
+ __u32 color_key;
+};
+
+struct mxcfb_pos {
+ __u16 x;
+ __u16 y;
+};
+
+/* IOCTL commands. */
+
+#define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha)
+#define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key)
+#define MXCFB_SET_OVERLAY_POS _IOWR('F', 0x24, struct mxcfb_pos)
+
+#endif
+
--
1.7.0.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH v2] ARM: i.mx: mx3fb: add overlay support
@ 2012-04-22 13:31 ` Alex Gershgorin
0 siblings, 0 replies; 2+ messages in thread
From: Alex Gershgorin @ 2012-04-22 13:31 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: g.liakhovetski, s.hauer, laurent.pinchart, linux-fbdev,
linux-media, Alex Gershgorin
This work is based on some earlier patch series
"i.MX31: dmaengine and framebuffer drivers" from 2008
by Guennadi Liakhovetski, the patch initializes overlay channel,
adds ioctl for configuring transparency of the overlay and graphics
planes, CONFIG_FB_MX3_OVERLAY is also supported.
In case that CONFIG_FB_MX3_OVERLAY is not defined, mx3fb is completely
backward compatible.
Blend mode, only global alpha blending has been tested.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Alex Gershgorin <alexg@meprolight.com>
---
Applies to v3.4-rc4
Changes since v1:
*Some fixes after review
*Added ioctl for setting overlay windows position
---
drivers/video/Kconfig | 7 +
drivers/video/mx3fb.c | 346 ++++++++++++++++++++++++++++++++++++++++++++----
include/linux/mxcfb.h | 40 ++++++
3 files changed, 364 insertions(+), 29 deletions(-)
create mode 100644 include/linux/mxcfb.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a290be5..acbfccc 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2368,6 +2368,13 @@ config FB_MX3
far only synchronous displays are supported. If you plan to use
an LCD display with your i.MX31 system, say Y here.
+config FB_MX3_OVERLAY
+ bool "MX3 Overlay support"
+ default n
+ depends on FB_MX3
+ ---help---
+ Say Y here to enable overlay support
+
config FB_BROADSHEET
tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
depends on FB
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index eec0d7b..09d7885 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -26,6 +26,7 @@
#include <linux/console.h>
#include <linux/clk.h>
#include <linux/mutex.h>
+#include <linux/mxcfb.h>
#include <mach/dma.h>
#include <mach/hardware.h>
@@ -238,6 +239,7 @@ static const struct fb_videomode mx3fb_modedb[] = {
struct mx3fb_data {
struct fb_info *fbi;
+ struct fb_info *fbi_ovl;
int backlight_level;
void __iomem *reg_base;
spinlock_t lock;
@@ -246,6 +248,9 @@ struct mx3fb_data {
uint32_t h_start_width;
uint32_t v_start_width;
enum disp_data_mapping disp_data_fmt;
+
+ /* IDMAC / dmaengine interface */
+ struct idmac_channel *idmac_channel[2]; /* We need 2 channels */
};
struct dma_chan_request {
@@ -268,10 +273,19 @@ struct mx3fb_info {
struct dma_async_tx_descriptor *txd;
dma_cookie_t cookie;
struct scatterlist sg[2];
+ struct list_head ovl_list; /* overlay buffer list */
u32 sync; /* preserve var->sync flags */
};
+/* Allocated overlay buffer */
+struct mx3fb_alloc_list {
+ struct list_head list;
+ dma_addr_t phy_addr;
+ void *cpu_addr;
+ size_t size;
+};
+
static void mx3fb_dma_done(void *);
/* Used fb-mode and bpp. Can be set on kernel command line, therefore file-static. */
@@ -303,7 +317,13 @@ static void sdc_fb_init(struct mx3fb_info *fbi)
struct mx3fb_data *mx3fb = fbi->mx3fb;
uint32_t reg;
- reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
+ reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF) & ~SDC_COM_GWSEL;
+
+ /* Also enable foreground for overlay graphic window is foreground */
+ if (mx3fb->fbi_ovl && fbi = mx3fb->fbi_ovl->par) {
+ reg |= SDC_COM_FG_EN | SDC_COM_GWSEL;
+ INIT_LIST_HEAD(&fbi->ovl_list);
+ }
mx3fb_write_reg(mx3fb, reg | SDC_COM_BG_EN, SDC_COM_CONF);
}
@@ -312,13 +332,24 @@ static void sdc_fb_init(struct mx3fb_info *fbi)
static uint32_t sdc_fb_uninit(struct mx3fb_info *fbi)
{
struct mx3fb_data *mx3fb = fbi->mx3fb;
- uint32_t reg;
+ uint32_t reg, chan_mask;
reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
- mx3fb_write_reg(mx3fb, reg & ~SDC_COM_BG_EN, SDC_COM_CONF);
+ /*
+ * Don't we have to automatically disable overlay when disabling
+ * background? Attention: cannot test mx3fb->fbi_ovl->par, must
+ * test mx3fb->fbi->par, because at the time this function is
+ * called for the first time fbi_ovl is not assigned yet.
+ */
+ if (fbi = mx3fb->fbi->par)
+ chan_mask = SDC_COM_BG_EN;
+ else
+ chan_mask = SDC_COM_FG_EN | SDC_COM_GWSEL;
+
+ mx3fb_write_reg(mx3fb, reg & ~chan_mask, SDC_COM_CONF);
- return reg & SDC_COM_BG_EN;
+ return reg & chan_mask;
}
static void sdc_enable_channel(struct mx3fb_info *mx3_fbi)
@@ -412,13 +443,33 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel,
int16_t x_pos, int16_t y_pos)
{
- if (channel != IDMAC_SDC_0)
- return -EINVAL;
-
x_pos += mx3fb->h_start_width;
y_pos += mx3fb->v_start_width;
- mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
+/*
+ If the overlay is defined, we just need to swap
+ the window position register relative to DMAC channel ID
+*/
+ switch (channel) {
+#ifndef CONFIG_FB_MX3_OVERLAY
+ case IDMAC_SDC_0:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
+ break;
+ case IDMAC_SDC_1:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_FG_POS);
+ break;
+#else
+ case IDMAC_SDC_0:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_FG_POS);
+ break;
+ case IDMAC_SDC_1:
+ mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
return 0;
}
@@ -482,14 +533,17 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
mx3fb->h_start_width = h_start_width;
mx3fb->v_start_width = v_start_width;
+ reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
+
switch (panel) {
case IPU_PANEL_SHARP_TFT:
mx3fb_write_reg(mx3fb, 0x00FD0102L, SDC_SHARP_CONF_1);
mx3fb_write_reg(mx3fb, 0x00F500F4L, SDC_SHARP_CONF_2);
- mx3fb_write_reg(mx3fb, SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
+ mx3fb_write_reg(mx3fb, reg | SDC_COM_SHARP |
+ SDC_COM_TFT_COLOR, SDC_COM_CONF);
break;
case IPU_PANEL_TFT:
- mx3fb_write_reg(mx3fb, SDC_COM_TFT_COLOR, SDC_COM_CONF);
+ mx3fb_write_reg(mx3fb, reg | SDC_COM_TFT_COLOR, SDC_COM_CONF);
break;
default:
return -EINVAL;
@@ -563,13 +617,12 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
/**
* sdc_set_color_key() - set the transparent color key for SDC graphic plane.
* @mx3fb: mx3fb context.
- * @channel: IPU DMAC channel ID.
* @enable: boolean to enable or disable color keyl.
* @color_key: 24-bit RGB color to use as transparent color key.
* @return: 0 on success or negative error code on failure.
*/
-static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,
- bool enable, uint32_t color_key)
+static int sdc_set_color_key(struct mx3fb_data *mx3fb, bool enable,
+ uint32_t color_key)
{
uint32_t reg, sdc_conf;
unsigned long lock_flags;
@@ -577,10 +630,6 @@ static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,
spin_lock_irqsave(&mx3fb->lock, lock_flags);
sdc_conf = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
- if (channel = IDMAC_SDC_0)
- sdc_conf &= ~SDC_COM_GWSEL;
- else
- sdc_conf |= SDC_COM_GWSEL;
if (enable) {
reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0xFF000000L;
@@ -668,8 +717,16 @@ static int mx3fb_set_fix(struct fb_info *fbi)
{
struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var;
+ struct mx3fb_info *mx3_fbi = fbi->par;
+#ifndef CONFIG_FB_MX3_OVERLAY
strncpy(fix->id, "DISP3 BG", 8);
+#else
+ if (mx3_fbi->ipu_ch = IDMAC_SDC_1)
+ strncpy(fix->id, "DISP3 BG", 8);
+ else
+ strncpy(fix->id, "DISP3 FG", 8);
+#endif
fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
@@ -689,13 +746,25 @@ static void mx3fb_dma_done(void *arg)
struct idmac_channel *ichannel = to_idmac_chan(chan);
struct mx3fb_data *mx3fb = ichannel->client;
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ struct mx3fb_info *mx3_fbi_cur;
+ struct mx3fb_info *mx3_fbi_ovl = mx3fb->fbi_ovl ? mx3fb->fbi_ovl->par :
+ NULL;
dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq);
+ if (ichannel = mx3_fbi->idmac_channel) {
+ mx3_fbi_cur = mx3_fbi;
+ } else if (mx3_fbi_ovl && ichannel = mx3_fbi_ovl->idmac_channel) {
+ mx3_fbi_cur = mx3_fbi_ovl;
+ } else {
+ WARN(1, "Cannot identify channel!\n");
+ return;
+ }
+
/* We only need one interrupt, it will be re-enabled as needed */
disable_irq_nosync(ichannel->eof_irq);
- complete(&mx3_fbi->flip_cmpl);
+ complete(&mx3_fbi_cur->flip_cmpl);
}
static int __set_par(struct fb_info *fbi, bool lock)
@@ -1151,6 +1220,157 @@ static struct fb_ops mx3fb_ops = {
.fb_blank = mx3fb_blank,
};
+#ifdef CONFIG_FB_MX3_OVERLAY
+static int mx3fb_blank_ovl(int blank, struct fb_info *fbi)
+{
+ struct mx3fb_info *mx3_fbi = fbi->par;
+
+ dev_dbg(fbi->device, "ovl blank = %d\n", blank);
+
+ if (mx3_fbi->blank = blank)
+ return 0;
+
+ mutex_lock(&mx3_fbi->mutex);
+ mx3_fbi->blank = blank;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ sdc_disable_channel(mx3_fbi);
+ break;
+ case FB_BLANK_UNBLANK:
+ sdc_enable_channel(mx3_fbi);
+ break;
+ }
+ mutex_unlock(&mx3_fbi->mutex);
+
+ return 0;
+}
+
+/*
+ * Function to handle custom ioctls for MX3 framebuffer.
+ *
+ * @inode inode struct
+ * @file file struct
+ * @cmd Ioctl command to handle
+ * @arg User pointer to command arguments
+ * @fbi framebuffer information pointer
+ */
+static int mx3fb_ioctl_ovl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mx3fb_info *mx3_fbi = fbi->par;
+ struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
+ int retval = 0;
+ int __user *argp = (void __user *)arg;
+ struct mx3fb_alloc_list *mem;
+ int size;
+ unsigned long offset;
+ union {
+ struct mxcfb_pos pos;
+ struct mxcfb_gbl_alpha ga;
+ struct mxcfb_color_key key;
+ } s;
+
+ switch (cmd) {
+ case FBIO_ALLOC:
+ if (get_user(size, argp))
+ return -EFAULT;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (mem = NULL)
+ return -ENOMEM;
+
+ mem->size = PAGE_ALIGN(size);
+
+ mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
+ &mem->phy_addr,
+ GFP_DMA);
+ if (mem->cpu_addr = NULL) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+
+ mutex_lock(&mx3_fbi->mutex);
+ list_add(&mem->list, &mx3_fbi->ovl_list);
+ mutex_unlock(&mx3_fbi->mutex);
+
+ dev_dbg(fbi->device, "allocated %d bytes <at> 0x%08X\n",
+ mem->size, mem->phy_addr);
+
+ if (put_user(mem->phy_addr, argp))
+ return -EFAULT;
+
+ break;
+ case FBIO_FREE:
+ if (get_user(offset, argp))
+ return -EFAULT;
+
+ retval = -EINVAL;
+ mutex_lock(&mx3_fbi->mutex);
+ list_for_each_entry(mem, &mx3_fbi->ovl_list, list) {
+ if (mem->phy_addr = offset) {
+ list_del(&mem->list);
+ dma_free_coherent(fbi->device,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ retval = 0;
+ break;
+ }
+ }
+ mutex_unlock(&mx3_fbi->mutex);
+
+ break;
+ case MXCFB_SET_GBL_ALPHA:
+ if (copy_from_user(&s.ga, (void *)arg, sizeof(s.ga)))
+ retval = -EFAULT;
+
+ sdc_set_global_alpha(mx3fb, (bool)s.ga.enable, s.ga.alpha);
+ dev_dbg(fbi->device, "Set global alpha to %d\n", s.ga.alpha);
+
+ break;
+ case MXCFB_SET_CLR_KEY:
+ if (copy_from_user(&s.key, (void *)arg, sizeof(s.key)))
+ retval = -EFAULT;
+
+ sdc_set_color_key(mx3fb, (bool)s.key.enable, s.key.color_key);
+ dev_dbg(fbi->device, "Set color key to %d\n", s.key.color_key);
+
+ break;
+ case MXCFB_SET_OVERLAY_POS:
+ if (copy_from_user(&s.pos, (void *)arg, sizeof(s.pos)))
+ retval = -EFAULT;
+
+ sdc_set_window_pos(mx3fb, mx3_fbi->ipu_ch, s.pos.x, s.pos.y);
+ dev_dbg(fbi->device, "Set win position to posx=%d, posy=%d\n",
+ s.pos.x, s.pos.y);
+
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+static struct fb_ops mx3fb_ovl_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_par = mx3fb_set_par,
+ .fb_check_var = mx3fb_check_var,
+ .fb_setcolreg = mx3fb_setcolreg,
+ .fb_pan_display = mx3fb_pan_display,
+ .fb_ioctl = mx3fb_ioctl_ovl,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = mx3fb_blank_ovl,
+};
+#endif
+
#ifdef CONFIG_PM
/*
* Power management hooks. Note that we won't be called from IRQ context,
@@ -1164,11 +1384,16 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ struct mx3fb_info *mx3_fbi_ovl = mx3fb->fbi_ovl->par;
console_lock();
fb_set_suspend(mx3fb->fbi, 1);
+ fb_set_suspend(mx3fb->fbi_ovl, 1);
console_unlock();
+ if (mx3_fbi_ovl->blank = FB_BLANK_UNBLANK)
+ sdc_disable_channel(mx3_fbi_ovl);
+
if (mx3_fbi->blank = FB_BLANK_UNBLANK) {
sdc_disable_channel(mx3_fbi);
sdc_set_brightness(mx3fb, 0);
@@ -1184,14 +1409,19 @@ static int mx3fb_resume(struct platform_device *pdev)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
+ struct mx3fb_info *mx3_fbi_ovl = mx3fb->fbi_ovl->par;
if (mx3_fbi->blank = FB_BLANK_UNBLANK) {
sdc_enable_channel(mx3_fbi);
sdc_set_brightness(mx3fb, mx3fb->backlight_level);
}
+ if (mx3_fbi_ovl->blank = FB_BLANK_UNBLANK)
+ sdc_enable_channel(mx3_fbi_ovl);
+
console_lock();
fb_set_suspend(mx3fb->fbi, 0);
+ fb_set_suspend(mx3fb->fbi_ovl, 0);
console_unlock();
return 0;
@@ -1333,8 +1563,9 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
ichan->client = mx3fb;
irq = ichan->eof_irq;
- if (ichan->dma_chan.chan_id != IDMAC_SDC_0)
- return -EINVAL;
+ switch (ichan->dma_chan.chan_id) {
+
+ case IDMAC_SDC_0:
fbi = mx3fb_init_fbinfo(dev, &mx3fb_ops);
if (!fbi)
@@ -1375,7 +1606,29 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
sdc_set_brightness(mx3fb, 255);
sdc_set_global_alpha(mx3fb, true, 0xFF);
- sdc_set_color_key(mx3fb, IDMAC_SDC_0, false, 0);
+ sdc_set_color_key(mx3fb, false, 0);
+
+ break;
+#ifdef CONFIG_FB_MX3_OVERLAY
+ case IDMAC_SDC_1:
+
+ /* We know, that background has been allocated already! */
+ fbi = mx3fb_init_fbinfo(dev, &mx3fb_ovl_ops);
+ if (!fbi)
+ return -ENOMEM;
+
+ /* Default Y virtual size is 2x panel size */
+ fbi->var = mx3fb->fbi->var;
+ /* This shouldn't be necessary, it is already set up above */
+ fbi->var.yres_virtual = mx3fb->fbi->var.yres * 2;
+
+ mx3fb->fbi_ovl = fbi;
+
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
mx3fbi = fbi->par;
mx3fbi->idmac_channel = ichan;
@@ -1392,9 +1645,13 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
if (ret < 0)
goto esetpar;
- __blank(FB_BLANK_UNBLANK, fbi);
+ /* Overlay stays blanked by default */
+ if (ichan->dma_chan.chan_id = IDMAC_SDC_0) {
+ mx3fb_blank(FB_BLANK_UNBLANK, fbi);
- dev_info(dev, "registered, using mode %s\n", fb_mode);
+ dev_info(dev, "mx3fb: fb registered, using mode %s [%c]\n",
+ fb_mode, list_empty(&ichan->queue) ? '-' : '+');
+ }
ret = register_framebuffer(fbi);
if (ret < 0)
@@ -1492,14 +1749,42 @@ static int mx3fb_probe(struct platform_device *pdev)
mx3fb->backlight_level = 255;
+ mx3fb->idmac_channel[0] = to_idmac_chan(chan);
+ mx3fb->idmac_channel[0]->client = mx3fb;
+
ret = init_fb_chan(mx3fb, to_idmac_chan(chan));
if (ret < 0)
goto eisdc0;
+#ifdef CONFIG_FB_MX3_OVERLAY
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ rq.id = IDMAC_SDC_1;
+ chan = dma_request_channel(mask, chan_filter, &rq);
+ if (!chan) {
+ ret = -EBUSY;
+ goto ersdc1;
+ }
+
+ mx3fb->idmac_channel[1] = to_idmac_chan(chan);
+ mx3fb->idmac_channel[1]->client = mx3fb;
+
+ ret = init_fb_chan(mx3fb, to_idmac_chan(chan));
+ if (ret < 0)
+ goto eisdc1;
+#endif
+
return 0;
+#ifdef CONFIG_FB_MX3_OVERLAY
+eisdc1:
+ dma_release_channel(&mx3fb->idmac_channel[1]->dma_chan);
+ersdc1:
+ release_fbi(mx3fb->fbi);
+#endif
eisdc0:
- dma_release_channel(chan);
+ dma_release_channel(&mx3fb->idmac_channel[0]->dma_chan);
ersdc0:
dmaengine_put();
iounmap(mx3fb->reg_base);
@@ -1513,13 +1798,16 @@ static int mx3fb_remove(struct platform_device *dev)
{
struct mx3fb_data *mx3fb = platform_get_drvdata(dev);
struct fb_info *fbi = mx3fb->fbi;
- struct mx3fb_info *mx3_fbi = fbi->par;
- struct dma_chan *chan;
- chan = &mx3_fbi->idmac_channel->dma_chan;
- release_fbi(fbi);
+ if (fbi)
+ release_fbi(fbi);
+
+ fbi = mx3fb->fbi_ovl;
+ if (fbi)
+ release_fbi(fbi);
- dma_release_channel(chan);
+ dma_release_channel(&mx3fb->idmac_channel[1]->dma_chan);
+ dma_release_channel(&mx3fb->idmac_channel[0]->dma_chan);
dmaengine_put();
iounmap(mx3fb->reg_base);
diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h
new file mode 100644
index 0000000..b5b681f
--- /dev/null
+++ b/include/linux/mxcfb.h
@@ -0,0 +1,40 @@
+/*
+ * File: include/linux/mxcfb.h
+ * Global header file for the MXC Framebuffer
+ *
+ * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __LINUX_MXCFB_H__
+#define __LINUX_MXCFB_H__
+
+struct mxcfb_gbl_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mxcfb_color_key {
+ int enable;
+ __u32 color_key;
+};
+
+struct mxcfb_pos {
+ __u16 x;
+ __u16 y;
+};
+
+/* IOCTL commands. */
+
+#define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha)
+#define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key)
+#define MXCFB_SET_OVERLAY_POS _IOWR('F', 0x24, struct mxcfb_pos)
+
+#endif
+
--
1.7.0.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2012-04-22 13:38 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-22 13:31 [PATCH v2] ARM: i.mx: mx3fb: add overlay support Alex Gershgorin
2012-04-22 13:31 ` Alex Gershgorin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.