* Kvóta varovné
From: WEB ADMIN @ 2011-09-28 11:30 UTC (permalink / raw)
To: linux-fbdev
Vaše poštovní schránka storage byl překročen limit, dokud se
znovu potvrdili svou poštovní schránku, kterou nelze odesílat nebo
přijímat e-mail.To znovu potvrdili svou poštovní schránku, prosím
CLICK
ZDE <http://is.gd/IemtD7>
díky
správce systému
^ permalink raw reply
* Re: [PATCH 2/2] drivers/video: move some definitions from fsl-diu-fb.h
From: Timur Tabi @ 2011-09-27 18:37 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1316624096-5291-2-git-send-email-timur@freescale.com>
Timur Tabi wrote:
> Move several macros and structures from the Freescale DIU driver's header
> file into the source file, because they're only used by that file. Also
> delete a few unused macros.
>
> The diu and diu_ad structures cannot be moved because they're being used
> by the MPC5121 platform file. A future patch eliminate the need for
> the platform file to access these structs, so they'll be moved also.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
> ---
This patch breaks the MPC5121, so please ignore it. Sorry about that.
Please ignore Patch 1/2 as well. I'll just repost both with a bunch of other
patches in a large patchset.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: Question on struct fb_videomode.name
From: Geert Uytterhoeven @ 2011-09-27 12:22 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <4E80E6D1.3010907@freescale.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1253", Size: 1912 bytes --]
On Mon, Sep 26, 2011 at 22:55, Timur Tabi <timur@freescale.com> wrote:
> In my fb driver, I have an array of fb_videomode structs, like this:
>
> static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
> Â Â Â Â {
>         .name      = "1024x768-60",
>         .refresh     = 60,
>         .xres      = 1024,
>         .yres      = 768,
>         .pixclock    = 15385,
>         .left_margin   = 160,
>         .right_margin  = 24,
>         .upper_margin  = 29,
>         .lower_margin  = 3,
>         .hsync_len    = 136,
>         .vsync_len    = 6,
>         .sync      = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
>         .vmode      = FB_VMODE_NONINTERLACED
> Â Â Â Â },
> Â Â Â Â ...
>
> Is there any value in specifying the .name field as "<xres>x<yres>-<ref>"? Â I
> know the .name field is optional, but what happens if I don't specify it? Â It
> just seems redundant to generate the name based on other data in the same structure.
If the name is just "<xres>x<yres>-<ref>", you can leave it NULL.
The name only adds value if it's something different, cfr. the modes
in macmodes.c,
amifb.c, or ps3fb.c.
Gr{oetje,eeting}s,
            Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                 -- Linus Torvalds
ÿôèº{.nÇ+·®+%Ëÿ±éݶ\x17¥wÿº{.nÇ+·¥{±ýöÝzÿâØ^nr¡ö¦zË\x1aëh¨èÚ&£ûàz¿äz¹Þú+Ê+zf£¢·h§~Ûiÿÿïêÿêçz_è®\x0fæj:+v¨þ)ߣøm
^ permalink raw reply
* Poslední varování =?iso-8859-2?Q?(kv=
From: WEB ADMIN @ 2011-09-27 8:52 UTC (permalink / raw)
To: linux-fbdev
Vaše poštovní schránka storage byl překročen limit, dokud se
znovu potvrdili svou schránku youcan odesílat nebo přijímat e-mail.To
znovu potvrdili svou poštovní schránku, prosím CLICK
ZDE <http://is.gd/CQFt47>
Díky
Správce systému
^ permalink raw reply
* RE: [PATCH v2 2/2] fb: add events for early fb event support.
From: Inki Dae @ 2011-09-27 4:48 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1317047842-12220-1-git-send-email-inki.dae@samsung.com>
> -----Original Message-----
> From: Inki Dae [mailto:inki.dae@samsung.com]
> Sent: Monday, September 26, 2011 11:37 PM
> To: FlorianSchandinat@gmx.de; linux-fbdev@vger.kernel.org
> Cc: kyungmin.park@samsung.com; lars@metafoo.de; Inki Dae
> Subject: [PATCH v2 2/2] fb: add events for early fb event support.
>
> this patch adds FB_EARLY_EVENT_BLANK and FB_R_EARLY_EVENT_BLANK
> event mode supports. first, fb_notifier_call_chain() is called with
> FB_EARLY_EVENT_BLANK and fb_blank() of specific fb driver is called
> and then fb_notifier_call_chain() is called with FB_EVENT_BLANK again
> at fb_blank(). and if fb_blank() was failed then fb_nitifier_call_chain()
> would be called with FB_R_EARLY_EVENT_BLANK to revert the previous
effects.
>
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> drivers/video/fbmem.c | 21 +++++++++++++++------
> include/linux/fb.h | 4 ++++
> 2 files changed, 19 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
> index ad93629..a2bd17b 100644
> --- a/drivers/video/fbmem.c
> +++ b/drivers/video/fbmem.c
> @@ -1032,20 +1032,29 @@ fb_set_var(struct fb_info *info, struct
> fb_var_screeninfo *var)
> int
> fb_blank(struct fb_info *info, int blank)
> {
> - int ret = -EINVAL;
> + struct fb_event event;
> + int ret = -EINVAL, early_ret;
>
> if (blank > FB_BLANK_POWERDOWN)
> blank = FB_BLANK_POWERDOWN;
>
> + event.info = info;
> + event.data = ␣
> +
> + early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
> +
> if (info->fbops->fb_blank)
> ret = info->fbops->fb_blank(blank, info);
>
> - if (!ret) {
> - struct fb_event event;
> -
> - event.info = info;
> - event.data = ␣
> + if (!ret)
> fb_notifier_call_chain(FB_EVENT_BLANK, &event);
> + else {
> + /*
> + * if fb_blank is failed then revert effects of
> + * the early blank event.
> + */
> + if (early_ret < 0)
Ah, this is condition wrong so I will fix it to "if (!early_ret)".
> + fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK,
&event);
> }
>
> return ret;
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index 1d6836c..29f53d5 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -549,6 +549,10 @@ struct fb_cursor_user {
> #define FB_EVENT_FB_UNBIND 0x0E
> /* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga
> switcheroo */
> #define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
> +/* A hardware display blank early change occured */
> +#define FB_EARLY_EVENT_BLANK 0x10
> +/* A hardware display blank revert early change occured */
> +#define FB_R_EARLY_EVENT_BLANK 0x11
>
> struct fb_event {
> struct fb_info *info;
> --
> 1.7.4.1
^ permalink raw reply
* Question on struct fb_videomode.name
From: Timur Tabi @ 2011-09-26 20:55 UTC (permalink / raw)
To: linux-fbdev
In my fb driver, I have an array of fb_videomode structs, like this:
static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
{
.name = "1024x768-60",
.refresh = 60,
.xres = 1024,
.yres = 768,
.pixclock = 15385,
.left_margin = 160,
.right_margin = 24,
.upper_margin = 29,
.lower_margin = 3,
.hsync_len = 136,
.vsync_len = 6,
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.vmode = FB_VMODE_NONINTERLACED
},
...
Is there any value in specifying the .name field as "<xres>x<yres>-<ref>"? I
know the .name field is optional, but what happens if I don't specify it? It
just seems redundant to generate the name based on other data in the same structure.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* [PATCH v2 2/2] fb: add events for early fb event support.
From: Inki Dae @ 2011-09-26 14:37 UTC (permalink / raw)
To: linux-fbdev
this patch adds FB_EARLY_EVENT_BLANK and FB_R_EARLY_EVENT_BLANK
event mode supports. first, fb_notifier_call_chain() is called with
FB_EARLY_EVENT_BLANK and fb_blank() of specific fb driver is called
and then fb_notifier_call_chain() is called with FB_EVENT_BLANK again
at fb_blank(). and if fb_blank() was failed then fb_nitifier_call_chain()
would be called with FB_R_EARLY_EVENT_BLANK to revert the previous effects.
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/video/fbmem.c | 21 +++++++++++++++------
include/linux/fb.h | 4 ++++
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index ad93629..a2bd17b 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1032,20 +1032,29 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
int
fb_blank(struct fb_info *info, int blank)
{
- int ret = -EINVAL;
+ struct fb_event event;
+ int ret = -EINVAL, early_ret;
if (blank > FB_BLANK_POWERDOWN)
blank = FB_BLANK_POWERDOWN;
+ event.info = info;
+ event.data = ␣
+
+ early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
+
if (info->fbops->fb_blank)
ret = info->fbops->fb_blank(blank, info);
- if (!ret) {
- struct fb_event event;
-
- event.info = info;
- event.data = ␣
+ if (!ret)
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
+ else {
+ /*
+ * if fb_blank is failed then revert effects of
+ * the early blank event.
+ */
+ if (early_ret < 0)
+ fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
}
return ret;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 1d6836c..29f53d5 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -549,6 +549,10 @@ struct fb_cursor_user {
#define FB_EVENT_FB_UNBIND 0x0E
/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga switcheroo */
#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
+/* A hardware display blank early change occured */
+#define FB_EARLY_EVENT_BLANK 0x10
+/* A hardware display blank revert early change occured */
+#define FB_R_EARLY_EVENT_BLANK 0x11
struct fb_event {
struct fb_info *info;
--
1.7.4.1
^ permalink raw reply related
* [PATCH v2 1/2] lcd: add callbacks for early fb event blank support.
From: Inki Dae @ 2011-09-26 14:36 UTC (permalink / raw)
To: linux-fbdev
this patch adds early_set_power and r_early_set_power callbacks.
early_set_power callback is called prior to fb_blank() of fbmem.c and
r_early_set_power callback is called if fb_blank() was failed to
revert the effects of the early_set_power call of lcd panel driver.
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/video/backlight/lcd.c | 10 ++++++++++
include/linux/lcd.h | 10 ++++++++++
2 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 71a11ca..7a03b6c 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -32,6 +32,8 @@ static int fb_notifier_callback(struct notifier_block *self,
case FB_EVENT_BLANK:
case FB_EVENT_MODE_CHANGE:
case FB_EVENT_MODE_CHANGE_ALL:
+ case FB_EARLY_EVENT_BLANK:
+ case FB_R_EARLY_EVENT_BLANK:
break;
default:
return 0;
@@ -46,6 +48,14 @@ static int fb_notifier_callback(struct notifier_block *self,
if (event = FB_EVENT_BLANK) {
if (ld->ops->set_power)
ld->ops->set_power(ld, *(int *)evdata->data);
+ } else if (event = FB_EARLY_EVENT_BLANK) {
+ if (ld->ops->early_set_power)
+ ld->ops->early_set_power(ld,
+ *(int *)evdata->data);
+ } else if (event = FB_R_EARLY_EVENT_BLANK) {
+ if (ld->ops->r_early_set_power)
+ ld->ops->r_early_set_power(ld,
+ *(int *)evdata->data);
} else {
if (ld->ops->set_mode)
ld->ops->set_mode(ld, evdata->data);
diff --git a/include/linux/lcd.h b/include/linux/lcd.h
index 8877123..e00c3b0 100644
--- a/include/linux/lcd.h
+++ b/include/linux/lcd.h
@@ -40,6 +40,16 @@ struct lcd_ops {
/* Get the LCD panel power status (0: full on, 1..3: controller
power on, flat panel power off, 4: full off), see FB_BLANK_XXX */
int (*get_power)(struct lcd_device *);
+ /*
+ * Enable or disable power to the LCD(0: on; 4: off, see FB_BLANK_XXX)
+ * and this callback would be called proir to fb driver's callback.
+ *
+ * P.S. note that if early_set_power is not NULL then early fb notifier
+ * would be registered.
+ */
+ int (*early_set_power)(struct lcd_device *, int power);
+ /* revert the effects of the early blank event. */
+ int (*r_early_set_power)(struct lcd_device *, int power);
/* Enable or disable power to the LCD (0: on; 4: off, see FB_BLANK_XXX) */
int (*set_power)(struct lcd_device *, int power);
/* Get the current contrast setting (0-max_contrast) */
--
1.7.4.1
^ permalink raw reply related
* [RFC PATCH 3/3] davinci: vpbe: add build infrastructure for fbdev driver
From: Manjunath Hadli @ 2011-09-26 13:47 UTC (permalink / raw)
To: linux-fbdev
add Kconfig and Makefile changes to build the fbdev driver
Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
---
drivers/media/video/davinci/Kconfig | 13 +++++++++++++
drivers/media/video/davinci/Makefile | 1 +
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
index a7f11e7..0ea27b8 100644
--- a/drivers/media/video/davinci/Kconfig
+++ b/drivers/media/video/davinci/Kconfig
@@ -113,3 +113,16 @@ config VIDEO_VPBE_DISPLAY
To compile this driver as a module, choose M here: the
module will be called vpbe_display.
+
+config VIDEO_VPBE_FB
+ tristate "VPBE Framebuffer driver"
+ depends on FB && ARCH_DAVINCI
+ select VIDEO_DMXXX_VPBE
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ default y
+ help
+ Enables VPBE Framebuffer driver on a DMXXX device
+ To compile this driver as a module, choose M here: the
+ module will be called vpbe_fb.
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile
index ae7dafb..da4a5b4 100644
--- a/drivers/media/video/davinci/Makefile
+++ b/drivers/media/video/davinci/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
obj-$(CONFIG_VIDEO_ISIF) += isif.o
obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o
obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o
+obj-$(CONFIG_VIDEO_VPBE_FB) += vpbe_fb.o
--
1.6.2.4
^ permalink raw reply related
* [RFC PATCH 2/3] davinci: vpbe: add fbdev driver for dm644x
From: Manjunath Hadli @ 2011-09-26 13:47 UTC (permalink / raw)
To: linux-fbdev
add the fbdev driver for dm644x which uses an OSD layer
with RGB565/RGB888 support and an attribute window which can
also be doubled as another RGB565 window. The fbdev supports
fb0 and fb2 for OSD0 and OSD1, and also supports video windows
with fb1 and fb3.
Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
---
drivers/media/video/davinci/vpbe_fb.c | 2537 +++++++++++++++++++++++++++
drivers/media/video/davinci/vpbe_fb.h | 66 +
drivers/media/video/davinci/vpbe_fb_ioctl.h | 159 ++
3 files changed, 2762 insertions(+), 0 deletions(-)
create mode 100644 drivers/media/video/davinci/vpbe_fb.c
create mode 100644 drivers/media/video/davinci/vpbe_fb.h
create mode 100644 drivers/media/video/davinci/vpbe_fb_ioctl.h
diff --git a/drivers/media/video/davinci/vpbe_fb.c b/drivers/media/video/davinci/vpbe_fb.c
new file mode 100644
index 0000000..acd164d
--- /dev/null
+++ b/drivers/media/video/davinci/vpbe_fb.c
@@ -0,0 +1,2537 @@
+/*
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * Andy Lowe (alowe@mvista.com), MontaVista Software
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option)any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <linux/uaccess.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include "vpbe_fb_ioctl.h"
+#include "vpbe_fb.h"
+
+#include <mach/cputype.h>
+
+static struct osd_state *osd_device;
+
+/* return non-zero if the info structure corresponds to OSD0 or OSD1 */
+static int is_osd_win(const struct fb_info *info)
+{
+ const struct vpbe_dm_win_info *win = info->par;
+
+ if (win->layer = WIN_OSD0 || win->layer = WIN_OSD1)
+ return 1;
+ return 0;
+}
+
+/* return non-zero if the info structure corresponds to VID0 or VID1 */
+#define is_vid_win(info) (!is_osd_win(info))
+
+/*
+ * Convert a framebuffer info pointer to a osd_layer enumeration.
+ * It is up to the caller to verify that the info structure corresponds to
+ * either OSD0 or OSD1.
+ */
+static enum osd_layer fb_info_to_osd_enum(const struct fb_info *info)
+{
+ const struct vpbe_dm_win_info *win = info->par;
+
+ if (win->layer = WIN_OSD1)
+ return OSDWIN_OSD1;
+ return OSDWIN_OSD0;
+}
+
+/* macros for testing fb_var_screeninfo attributes */
+#define is_attribute_mode(var) (((var)->bits_per_pixel = 4) && \
+ ((var)->nonstd != 0))
+#define is_yuv(var) ((((var)->bits_per_pixel = 16) || \
+ ((var)->bits_per_pixel = 8)) && \
+ ((var)->nonstd != 0))
+#define is_window_interlaced(var) (((var)->vmode & FB_VMODE_INTERLACED) \
+ = FB_VMODE_INTERLACED)
+
+/* macros for testing fb_videomode attributes */
+#define is_display_interlaced(mode) (((mode)->vmode & FB_VMODE_INTERLACED) \
+ = FB_VMODE_INTERLACED)
+
+static unsigned int fb_cbcr_ofst;
+
+/*
+ * Convert an fb_var_screeninfo struct to a Davinci display layer configuration.
+ * lconfig->xpos, lconfig->ypos, and lconfig->line_length are not modified
+ * because no information about them is contained in var.
+ * The value of the yc_pixfmt argument is returned in lconfig->pixfmt if a
+ * the var specifies a YC pixel format. The value of yc_pixfmt must be either
+ * PIXFMT_YCbCrI or PIXFMT_YCrCbI.
+ */
+static void convert_fb_var_to_osd(const struct fb_var_screeninfo *var,
+ struct osd_layer_config *lconfig,
+ enum osd_pix_format yc_pixfmt)
+{
+ lconfig->xsize = var->xres;
+ lconfig->ysize = var->yres;
+ lconfig->interlaced = is_window_interlaced(var);
+
+ switch (var->bits_per_pixel) {
+ case 1:
+ lconfig->pixfmt = PIXFMT_1BPP;
+ break;
+ case 2:
+ lconfig->pixfmt = PIXFMT_2BPP;
+ break;
+ case 4:
+ if (is_attribute_mode(var))
+ lconfig->pixfmt = PIXFMT_OSD_ATTR;
+ else
+ lconfig->pixfmt = PIXFMT_4BPP;
+ break;
+ case 8:
+ if (is_yuv(var))
+ lconfig->pixfmt = PIXFMT_NV12;
+ else
+ lconfig->pixfmt = PIXFMT_8BPP;
+ break;
+ case 16:
+ default:
+ if (is_yuv(var))
+ lconfig->pixfmt = yc_pixfmt;
+ else
+ lconfig->pixfmt = PIXFMT_RGB565;
+ break;
+ case 24:
+ case 32:
+ lconfig->pixfmt = PIXFMT_RGB888;
+ break;
+ }
+}
+
+/*
+ * Convert an fb_info struct to a OSD display layer configuration.
+ */
+static void convert_fb_info_to_osd(const struct fb_info *info,
+ struct osd_layer_config *lconfig)
+{
+ const struct vpbe_dm_win_info *win = info->par;
+
+ lconfig->line_length = info->fix.line_length;
+ lconfig->xpos = win->xpos;
+ lconfig->ypos = win->ypos;
+ convert_fb_var_to_osd(&info->var, lconfig, win->dm->yc_pixfmt);
+}
+
+/*
+ * Convert a OSD display layer configuration to var info.
+ * The following members of var are not modified:
+ * var->xres_virtual
+ * var->yres_virtual
+ * var->xoffset
+ * var->yoffset
+ * var->pixclock
+ * var->left_margin
+ * var->right_margin
+ * var->upper_margin
+ * var->lower_margin
+ * var->hsync_len
+ * var->vsync_len
+ * var->sync
+ * Only bit 0 of var->vmode (FB_VMODE_INTERLACED) is modified. All other bits
+ * of var->vmode are retained.
+ */
+static void convert_osd_to_fb_var(const struct osd_layer_config *lconfig,
+ struct fb_var_screeninfo *var)
+{
+ var->xres = lconfig->xsize;
+ var->yres = lconfig->ysize;
+ if (lconfig->interlaced)
+ var->vmode |= FB_VMODE_INTERLACED;
+ else
+ var->vmode &= ~FB_VMODE_INTERLACED;
+
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+ var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+ var->nonstd = 0;
+
+ switch (lconfig->pixfmt) {
+ case PIXFMT_1BPP:
+ var->bits_per_pixel = 1;
+ var->red.length = var->green.length = var->blue.length + var->bits_per_pixel;
+ break;
+ case PIXFMT_2BPP:
+ var->bits_per_pixel = 2;
+ var->red.length = var->green.length = var->blue.length + var->bits_per_pixel;
+ break;
+ case PIXFMT_4BPP:
+ var->bits_per_pixel = 4;
+ var->red.length = var->green.length = var->blue.length + var->bits_per_pixel;
+ break;
+ case PIXFMT_8BPP:
+ var->bits_per_pixel = 8;
+ var->red.length = var->green.length = var->blue.length + var->bits_per_pixel;
+ break;
+ case PIXFMT_RGB565:
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ break;
+ case PIXFMT_YCbCrI:
+ case PIXFMT_YCrCbI:
+ var->bits_per_pixel = 16;
+ var->red.length = var->green.length = var->blue.length = 0;
+ var->nonstd = 1;
+ break;
+ case PIXFMT_NV12:
+ if (cpu_is_davinci_dm365()) {
+ var->bits_per_pixel = 8;
+ var->red.length = var->green.length = var->blue.length + 0;
+ var->nonstd = 1;
+ }
+ case PIXFMT_RGB888:
+ if (cpu_is_davinci_dm644x()) {
+ var->bits_per_pixel = 24;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ } else {
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 3;
+ }
+ break;
+ case PIXFMT_OSD_ATTR:
+ var->bits_per_pixel = 4;
+ var->red.length = var->green.length = var->blue.length = 0;
+ var->nonstd = 1;
+ break;
+ }
+
+ var->grayscale = 0;
+ var->activate = FB_ACTIVATE_NOW;
+ var->height = 0;
+ var->width = 0;
+ var->accel_flags = 0;
+ var->rotate = 0;
+}
+
+/*
+ * Get the video mode from the encoder manager.
+ */
+static int get_video_mode(struct vpbe_device *vpbe_dev,
+ struct fb_videomode *mode)
+{
+ struct vpbe_enc_mode_info mode_info;
+ int ret;
+
+ memset(&mode_info, 0, sizeof(mode_info));
+ memset(mode, 0, sizeof(*mode));
+
+ ret = vpbe_dev->ops.get_mode_info(vpbe_dev, &mode_info);
+ if (ret < 0)
+ return ret;
+
+ mode->name = mode_info.name;
+ if (mode_info.fps.denominator) {
+ unsigned fps_1000; /* frames per 1000 seconds */
+ unsigned lps; /* lines per second */
+ unsigned pps; /* pixels per second */
+ unsigned vtotal; /* total lines per frame */
+ unsigned htotal; /* total pixels per line */
+ unsigned interlace = (mode_info.interlaced) ? 2 : 1;
+
+ fps_1000 = (1000 * mode_info.fps.numerator +
+ mode_info.fps.denominator / 2) / mode_info.fps.denominator;
+
+ mode->refresh = (interlace * fps_1000 + 1000 / 2) / 1000;
+
+ vtotal = mode_info.yres + mode_info.lower_margin +
+ mode_info.vsync_len + mode_info.upper_margin;
+ lps = (fps_1000 * vtotal + 1000 / 2) / 1000;
+
+ htotal = mode_info.xres + mode_info.right_margin +
+ mode_info.hsync_len + mode_info.left_margin;
+ pps = lps * htotal;
+
+ if (pps)
+ mode->pixclock + ((1000000000UL + pps / 2) / pps) * 1000;
+ }
+ mode->xres = mode_info.xres;
+ mode->yres = mode_info.yres;
+ mode->left_margin = mode_info.left_margin;
+ mode->right_margin = mode_info.right_margin;
+ mode->upper_margin = mode_info.upper_margin;
+ mode->lower_margin = mode_info.lower_margin;
+ mode->hsync_len = mode_info.hsync_len;
+ mode->vsync_len = mode_info.vsync_len;
+ if (mode_info.flags & (1 << 0))
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (mode_info.flags & (1 << 1))
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ if ((mode_info.timings_type & VPBE_ENC_STD) ||
+ (mode_info.timings_type & VPBE_ENC_DV_PRESET))
+ mode->sync |= FB_SYNC_BROADCAST;
+ if (mode_info.interlaced)
+ mode->vmode |= FB_VMODE_INTERLACED;
+
+ return 0;
+}
+
+/*
+ * Set a video mode with the encoder manager.
+ */
+static int set_video_mode(struct vpbe_device *vpbe_dev,
+ struct fb_videomode *mode)
+{
+ struct vpbe_enc_mode_info mode_info;
+ int ret;
+
+ ret = vpbe_dev->ops.get_mode_info(vpbe_dev, &mode_info);
+ if (ret < 0)
+ return ret;
+
+ mode_info.name = (unsigned char *)mode->name;
+ mode_info.fps.numerator = 0;
+ mode_info.fps.denominator = 0;
+ if (mode->pixclock && mode->xres && mode->yres) {
+ unsigned fps_1000; /* frames per 1000 seconds */
+ unsigned lps; /* lines per second */
+ unsigned pps; /* pixels per second */
+ unsigned vtotal; /* total lines per frame */
+ unsigned htotal; /* total pixels per line */
+
+ pps = ((1000000000UL + mode->pixclock / 2) / mode->pixclock) *
+ 1000;
+
+ htotal = mode->xres + mode->right_margin + mode->hsync_len +
+ mode->left_margin;
+ lps = (pps + htotal / 2) / htotal;
+
+ vtotal = mode->yres + mode->lower_margin + mode->vsync_len +
+ mode->upper_margin;
+ fps_1000 = (lps * 1000 + vtotal / 2) / vtotal;
+
+ mode_info.fps.numerator = fps_1000;
+ mode_info.fps.denominator = 1000;
+
+ /*
+ * 1000 = 2*2*2*5*5*5, so factor out any common multiples of 2
+ * or 5
+ */
+ while ((((mode_info.fps.numerator / 2) * 2) =
+ mode_info.fps.numerator) &&
+ (((mode_info.fps.denominator / 2) * 2) =
+ mode_info.fps.denominator)) {
+ mode_info.fps.numerator = mode_info.fps.numerator / 2;
+ mode_info.fps.denominator + mode_info.fps.denominator / 2;
+ }
+ while ((((mode_info.fps.numerator / 5) * 5) =
+ mode_info.fps.numerator) &&
+ (((mode_info.fps.denominator / 5) * 5) =
+ mode_info.fps.denominator)) {
+ mode_info.fps.numerator = mode_info.fps.numerator / 5;
+ mode_info.fps.denominator + mode_info.fps.denominator / 5;
+ }
+ }
+ mode_info.xres = mode->xres;
+ mode_info.yres = mode->yres;
+ mode_info.left_margin = mode->left_margin;
+ mode_info.right_margin = mode->right_margin;
+ mode_info.upper_margin = mode->upper_margin;
+ mode_info.lower_margin = mode->lower_margin;
+ mode_info.hsync_len = mode->hsync_len;
+ mode_info.vsync_len = mode->vsync_len;
+ if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ mode_info.flags |= (1 << 0);
+ else
+ mode_info.flags &= ~(1 << 0);
+ if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ mode_info.flags |= (1 << 1);
+ else
+ mode_info.flags &= ~(1 << 1);
+ /*
+ * seems like a flag std is used in earlier version of the driver to
+ * indicate if it is a standard timings non standard timings. We use
+ * timings_type for the same.
+ */
+ if (mode->sync & FB_SYNC_BROADCAST)
+ mode_info.timings_type = VPBE_ENC_TIMINGS_INVALID;
+ else
+ mode_info.timings_type = VPBE_ENC_CUSTOM_TIMINGS;
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ mode_info.interlaced = 1;
+ else
+ mode_info.interlaced = 0;
+
+ ret = vpbe_dev->ops.set_mode(vpbe_dev, &mode_info);
+
+ return ret;
+}
+
+/*
+ * Construct an fb_var_screeninfo structure from an fb_videomode structure
+ * describing the display and a osd_layer_config structure describing a window.
+ * The following members of var not modified:
+ * var->xoffset
+ * var->yoffset
+ * var->xres_virtual
+ * var->yres_virtual
+ * The following members of var are loaded with values derived from mode:
+ * var->pixclock
+ * var->left_margin
+ * var->hsync_len
+ * var->vsync_len
+ * var->right_margin
+ * var->upper_margin
+ * var->lower_margin
+ * var->sync
+ * var->vmode (all bits except bit 0: FB_VMODE_INTERLACED)
+ * The following members of var are loaded with values derived from lconfig:
+ * var->xres
+ * var->yres
+ * var->bits_per_pixel
+ * var->red
+ * var->green
+ * var->blue
+ * var->transp
+ * var->nonstd
+ * var->grayscale
+ * var->activate
+ * var->height
+ * var->width
+ * var->accel_flags
+ * var->rotate
+ * var->vmode (only bit 0: FB_VMODE_INTERLACED)
+ *
+ * If the display resolution (xres and yres) specified in mode matches the
+ * window resolution specified in lconfig, then the display timing info returned
+ * in var is valid and var->pixclock will be the value derived from mode.
+ * If the display resolution does not match the window resolution, then
+ * var->pixclock will be set to 0 to indicate that the display timing info
+ * returned in var is not valid.
+ *
+ * mode and lconfig are not modified.
+ */
+static void construct_fb_var(struct fb_var_screeninfo *var,
+ struct fb_videomode *mode,
+ struct osd_layer_config *lconfig)
+{
+ fb_videomode_to_var(var, mode);
+ convert_osd_to_fb_var(lconfig, var);
+ if (lconfig->xsize != mode->xres || lconfig->ysize != mode->yres)
+ var->pixclock = 0;
+}
+
+/*
+ * Update the values in an fb_fix_screeninfo structure based on the values in an
+ * fb_var_screeninfo structure.
+ * The following members of fix are updated:
+ * fix->visual
+ * fix->xpanstep
+ * fix->ypanstep
+ * fix->ywrapstep
+ * fix->line_length
+ * All other members of fix are unmodified.
+ */
+static void update_fix_info(const struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
+{
+ fix->visual = (var->bits_per_pixel > 8) ? FB_VISUAL_TRUECOLOR :
+ FB_VISUAL_PSEUDOCOLOR;
+ /*
+ * xpanstep must correspond to a multiple of the 32-byte cache line size
+ */
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 12:
+ case 16:
+ case 32:
+ fix->xpanstep = (8 * 32) / var->bits_per_pixel;
+ break;
+ case 24:
+ fix->xpanstep = 32; /* 32 pixels = 3 cache lines */
+ break;
+ default:
+ fix->xpanstep = 0;
+ break;
+ }
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = (var->xres_virtual * var->bits_per_pixel + 7) / 8;
+ /* line_length must be a multiple of the 32-byte cache line size */
+ fix->line_length = ((fix->line_length + 31) / 32) * 32;
+}
+
+/*
+ * Determine if the window configuration specified by var will fit in a
+ * framebuffer of size fb_size.
+ * Returns 1 if the window will fit in the framebuffer, or 0 otherwise.
+ */
+static int window_will_fit_framebuffer(const struct fb_var_screeninfo *var,
+ unsigned fb_size)
+{
+ unsigned line_length;
+
+ line_length = (var->bits_per_pixel * var->xres_virtual + 7) / 8;
+ /* line length must be a multiple of the cache line size (32) */
+ line_length = ((line_length + 31) / 32) * 32;
+
+ if (var->yres_virtual * line_length <= fb_size)
+ return 1;
+ return 0;
+}
+
+/*
+ * FBIO_WAITFORVSYNC handler
+ */
+static int vpbe_fb_wait_for_vsync(struct fb_info *info)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ unsigned long cnt;
+ wait_queue_t wq;
+ int ret;
+
+ init_waitqueue_entry(&wq, current);
+
+ cnt = win->dm->vsync_cnt;
+ ret = wait_event_interruptible_timeout(win->dm->vsync_wait,
+ cnt != win->dm->vsync_cnt, win->dm->timeout);
+ if (ret < 0)
+ return ret;
+ if (ret = 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void vpbe_fb_vsync_callback(unsigned event, void *arg)
+{
+ struct vpbe_dm_info *dm = (struct vpbe_dm_info *)arg;
+ static unsigned last_event;
+ unsigned long addr = 0;
+
+ event &= ~VENC_END_OF_FRAME;
+ if (event = last_event) {
+ /* progressive */
+ xchg(&addr, dm->win[WIN_OSD0].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_OSD0].layer,
+ dm->win[WIN_OSD0].sdram_address,
+ fb_cbcr_ofst);
+ dm->win[WIN_OSD0].sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->win[WIN_OSD1].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_OSD1].layer,
+ dm->win[WIN_OSD1].sdram_address,
+ fb_cbcr_ofst);
+ dm->win[WIN_OSD1].sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->win[WIN_VID0].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_VID0].layer,
+ dm->win[WIN_VID0].sdram_address,
+ fb_cbcr_ofst);
+ dm->win[WIN_VID0].sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->win[WIN_VID1].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_VID1].layer,
+ dm->win[WIN_VID1].sdram_address,
+ fb_cbcr_ofst);
+
+ dm->win[WIN_VID1].sdram_address = 0;
+ }
+ ++dm->vsync_cnt;
+ wake_up_interruptible(&dm->vsync_wait);
+ last_event = event;
+ return;
+ }
+ /* interlaced */
+ if (!(event & VENC_SECOND_FIELD)) {
+ ++dm->vsync_cnt;
+ wake_up_interruptible(&dm->vsync_wait);
+ last_event = event;
+ return;
+ }
+ xchg(&addr, dm->win[WIN_OSD0].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_OSD0].layer,
+ dm->win[WIN_OSD0].sdram_address,
+ fb_cbcr_ofst);
+
+ dm->win[WIN_OSD0].sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->win[WIN_OSD1].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_OSD1].layer,
+ dm->win[WIN_OSD1].sdram_address,
+ fb_cbcr_ofst);
+ dm->win[WIN_OSD1].sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->win[WIN_VID0].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_VID0].layer,
+ dm->win[WIN_VID0].sdram_address,
+ fb_cbcr_ofst);
+ dm->win[WIN_VID0].sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->win[WIN_VID1].sdram_address);
+ if (addr) {
+ osd_device->ops.start_layer(osd_device,
+ dm->win[WIN_VID1].layer,
+ dm->win[WIN_VID1].sdram_address,
+ fb_cbcr_ofst);
+ dm->win[WIN_VID1].sdram_address = 0;
+ }
+ last_event = event;
+}
+
+/*
+ * FBIO_SETATTRIBUTE handler
+ *
+ * This ioctl is deprecated. The user can write the attribute values directly
+ * to the OSD1 framebuffer.
+ *
+ * Set a uniform attribute value over a rectangular area on the attribute
+ * window. The attribute value (0 to 15) is passed through the fb_fillrect's
+ * color parameter. r->dx and r->width must both be even. If not, they are
+ * rounded down.
+ */
+static int vpbe_set_attr_blend(struct fb_info *info, struct fb_fillrect *r)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct vpbe_dm_win_info *win = info->par;
+ char __iomem *start;
+ u32 width_bytes;
+ u8 blend;
+
+ if (win->layer != WIN_OSD1)
+ return -EINVAL;
+ if (!is_attribute_mode(var))
+ return -EINVAL;
+
+ if (r->dx + r->width > var->xres_virtual)
+ return -EINVAL;
+ if (r->dy + r->height > var->yres_virtual)
+ return -EINVAL;
+ if (r->color > 15)
+ return -EINVAL;
+ width_bytes = (r->width * var->bits_per_pixel) / 8;
+ start = info->screen_base + r->dy * info->fix.line_length +
+ (r->dx * var->bits_per_pixel) / 8;
+
+ blend = (((u8) r->color & 0xf) << 4) | ((u8) r->color);
+ while (r->height--) {
+ memset(start, blend, width_bytes);
+ start += info->fix.line_length * 3;
+ }
+
+ return 0;
+}
+
+/*
+ * FBIO_SETPOSX handler
+ */
+static int vpbe_setposx(struct fb_info *info, unsigned xpos)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct vpbe_dm_win_info *win = info->par;
+ unsigned old_xpos = win->xpos;
+ struct fb_var_screeninfo v;
+ int retval;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ memcpy(&v, var, sizeof(v));
+ win->xpos = xpos;
+ retval = info->fbops->fb_check_var(&v, info);
+ if (retval) {
+ win->xpos = old_xpos;
+ return retval;
+ }
+
+ /* update the window position */
+ memcpy(var, &v, sizeof(v));
+ retval = info->fbops->fb_set_par(info);
+
+ return retval;
+}
+
+/*
+ * FBIO_SETPOSY handler
+ */
+static int vpbe_setposy(struct fb_info *info, unsigned ypos)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct vpbe_dm_win_info *win = info->par;
+ unsigned old_ypos = win->ypos;
+ struct fb_var_screeninfo v;
+ int retval;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ memcpy(&v, var, sizeof(v));
+ win->ypos = ypos;
+ retval = info->fbops->fb_check_var(&v, info);
+ if (retval) {
+ win->ypos = old_ypos;
+ return retval;
+ }
+
+ /* update the window position */
+ memcpy(var, &v, sizeof(v));
+ retval = info->fbops->fb_set_par(info);
+
+ return retval;
+}
+
+/*
+ * FBIO_SETZOOM handler
+ */
+static int vpbe_set_zoom(struct fb_info *info, struct zoom_params *zoom)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ enum osd_zoom_factor h_zoom, v_zoom;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ switch (zoom->zoom_h) {
+ case 0:
+ h_zoom = ZOOM_X1;
+ break;
+ case 1:
+ h_zoom = ZOOM_X2;
+ break;
+ case 2:
+ h_zoom = ZOOM_X4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (zoom->zoom_v) {
+ case 0:
+ v_zoom = ZOOM_X1;
+ break;
+ case 1:
+ v_zoom = ZOOM_X2;
+ break;
+ case 2:
+ v_zoom = ZOOM_X4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ osd_device->ops.set_zoom(osd_device,
+ win->layer, h_zoom, v_zoom);
+ return 0;
+}
+
+/*
+ * FBIO_ENABLE_DISABLE_WIN handler
+ *
+ * This ioctl is deprecated. Use the standard FBIOBLANK ioctl instead.
+ */
+static int vpbe_enable_disable_win(struct fb_info *info, int enable)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ int retval = 0;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ if (!enable) {
+ win->display_window = 0;
+ osd_device->ops.disable_layer(osd_device, win->layer);
+ return retval;
+ }
+ win->display_window = 1;
+ retval = info->fbops->fb_check_var(&info->var, info);
+ if (retval)
+ return retval;
+ retval = info->fbops->fb_set_par(info);
+ return retval;
+}
+
+/*
+ * FBIO_SET_BITMAP_BLEND_FACTOR handler
+ */
+static int vpbe_bitmap_set_blend_factor(struct fb_info *info,
+ struct vpbe_bitmap_blend_params *para)
+{
+ enum osd_layer osdwin = fb_info_to_osd_enum(info);
+
+ if (!is_osd_win(info))
+ return -EINVAL;
+
+ if (para->bf > OSD_8_VID_0)
+ return -EINVAL;
+
+ osd_device->ops.set_blending_factor(osd_device, osdwin, para->bf);
+ if (para->enable_colorkeying)
+ osd_device->ops.enable_color_key(osd_device,
+ osdwin, para->colorkey);
+ else
+ osd_device->ops.disable_color_key(osd_device, osdwin);
+ return 0;
+}
+
+/*
+ * FBIO_SET_BITMAP_WIN_RAM_CLUT handler
+ *
+ * This ioctl is deprecated. Use the standard framebuffer ioctl FBIOPUTCMAP
+ * instead. Note that FBIOPUTCMAP colors are expressed in RGB space instead of
+ * YCbCr space.
+ */
+static int vpbe_bitmap_set_ram_clut(struct fb_info *info,
+ unsigned char ram_clut[256][3])
+{
+ int i;
+
+ if (!is_osd_win(info))
+ return -EINVAL;
+
+ for (i = 0; i < 256; i++)
+ osd_device->ops.set_clut_ycbcr(osd_device, i, ram_clut[i][0],
+ ram_clut[i][1], ram_clut[i][2]);
+
+ return 0;
+}
+
+/*
+ * FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN handler
+ *
+ * This ioctl is deprecated. Attribute mode can be enabled via the standard
+ * framebuffer ioctl FBIOPUT_VSCREENINFO by setting var->bits_per_pixel to 4
+ * and var->nonstd to a non-zero value. Attribute mode can be disabled by using
+ * FBIOPUT_VSCREENINFO to set a standard pixel format.
+ *
+ * The enabled/disabled status of OSD1 is unchanged by this ioctl. To avoid
+ * display glitches, you should disable OSD1 prior to calling this ioctl.
+ *
+ * When enabling attribute mode, var->bits_per_pixel is set to 4. var->xres,
+ * var->yres, var->xres_virtual, var->yres_virtual, win->xpos, and win->ypos are
+ * all copied from OSD0. var->xoffset and var->yoffset are set to 0.
+ * fix->line_length is updated to be consistent with 4 bits per pixel. No
+ * changes are made to the OSD1 configuration if OSD1 is already in attribute
+ * mode.
+ *
+ * When disabling attribute mode, the window geometry is unchanged.
+ * var->bits_per_pixel remains set to 4. No changes are made to the OSD1
+ * configuration if OSD1 is not in attribute mode.
+ */
+static int vpbe_enable_disable_attribute_window(struct fb_info *info, u32 flag)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct vpbe_dm_win_info *win = info->par;
+ struct osd_layer_config lconfig;
+ struct fb_var_screeninfo v;
+ int retval;
+
+ if (win->layer != WIN_OSD1)
+ return -EINVAL;
+
+ /* return with no error if there is nothing to do */
+ if ((is_attribute_mode(var) && flag) ||
+ (!is_attribute_mode(var) && !flag))
+ return 0;
+
+ /* start with the current OSD1 var */
+ memcpy(&v, var, sizeof(v));
+
+ if (flag) {
+ /* enable attribute mode */
+ const struct vpbe_dm_win_info *osd0 = &win->dm->win[WIN_OSD0];
+ const struct fb_var_screeninfo *osd0_var = &osd0->info->var;
+ unsigned old_xpos = win->xpos;
+ unsigned old_ypos = win->ypos;
+ /* get the OSD0 window configuration */
+ convert_fb_var_to_osd(osd0_var, &lconfig, win->dm->yc_pixfmt);
+ /* change the pixfmt to attribute mode */
+ lconfig.pixfmt = PIXFMT_OSD_ATTR;
+ /* update the var for OSD1 */
+ convert_osd_to_fb_var(&lconfig, &v);
+ /* copy xres_virtual and yres_virtual from OSD0 */
+ v.xres_virtual = osd0_var->xres_virtual;
+ v.yres_virtual = osd0_var->yres_virtual;
+ /* zero xoffset and yoffset */
+ v.xoffset = 0;
+ v.yoffset = 0;
+ /* copy xpos and ypos from OSD0 */
+ win->xpos = osd0->xpos;
+ win->ypos = osd0->ypos;
+
+ retval = info->fbops->fb_check_var(&v, info);
+ if (retval) {
+ win->xpos = old_xpos;
+ win->ypos = old_ypos;
+ return retval;
+ }
+
+ /*
+ * Enable attribute mode by replacing info->var and calling
+ * the fb_set_par method to activate it.
+ */
+ memcpy(var, &v, sizeof(v));
+ retval = info->fbops->fb_set_par(info);
+ return retval;
+ }
+ /* disable attribute mode */
+ /* get the current OSD1 window configuration */
+ convert_fb_var_to_osd(var, &lconfig, win->dm->yc_pixfmt);
+ /* change the pixfmt to 4-bits-per-pixel bitmap */
+ lconfig.pixfmt = PIXFMT_4BPP;
+ /* update the var for OSD1 */
+ convert_osd_to_fb_var(&lconfig, &v);
+
+ retval = info->fbops->fb_check_var(&v, info);
+ if (retval)
+ return retval;
+
+ /*
+ * Disable attribute mode by replacing info->var and calling
+ * the fb_set_par method to activate it.
+ */
+ memcpy(var, &v, sizeof(v));
+ retval = info->fbops->fb_set_par(info);
+ return retval;
+}
+
+/*
+ * FBIO_GET_BLINK_INTERVAL handler
+ */
+static int vpbe_get_blinking(struct fb_info *info,
+ struct vpbe_blink_option *blink_option)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ enum osd_blink_interval blink;
+ int enabled;
+
+ if (win->layer != WIN_OSD1)
+ return -EINVAL;
+
+ osd_device->ops.get_blink_attribute(osd_device, &enabled, &blink);
+ blink_option->blinking = enabled;
+ blink_option->interval = blink;
+
+ return 0;
+}
+
+/*
+ * FBIO_SET_BLINK_INTERVAL handler
+ */
+static int vpbe_set_blinking(struct fb_info *info,
+ struct vpbe_blink_option *blink_option)
+{
+ struct vpbe_dm_win_info *win = info->par;
+
+ if (win->layer != WIN_OSD1)
+ return -EINVAL;
+
+ if (blink_option->interval > BLINK_X4)
+ return -EINVAL;
+ osd_device->ops.set_blink_attribute(osd_device,
+ blink_option->blinking, blink_option->interval);
+
+ return 0;
+}
+
+/*
+ * FBIO_GET_VIDEO_CONFIG_PARAMS handler
+ *
+ * Despite the name, this ioctl can be used on both video windows and OSD
+ * (bitmap) windows.
+ */
+static int vpbe_get_vid_params(struct fb_info *info,
+ struct vpbe_video_config_params *vid_conf_params)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ enum osd_h_exp_ratio h_exp;
+ enum osd_v_exp_ratio v_exp;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ if (is_vid_win(info))
+ osd_device->ops.get_vid_expansion(osd_device,
+ &h_exp, &v_exp);
+ else
+ osd_device->ops.get_osd_expansion(osd_device,
+ &h_exp, &v_exp);
+
+ vid_conf_params->cb_cr_order + (win->dm->yc_pixfmt = PIXFMT_YCbCrI) ? 0 : 1;
+ vid_conf_params->exp_info.horizontal = h_exp;
+ vid_conf_params->exp_info.vertical = v_exp;
+
+ return 0;
+}
+
+/*
+ * FBIO_SET_VIDEO_CONFIG_PARAMS handler
+ *
+ * Despite the name, this ioctl can be used on both video windows and OSD
+ * (bitmap) windows.
+ *
+ * NOTE: If the cb_cr_order is changed, it won't take effect until an
+ * FBIOPUT_VSCREENINFO ioctl is executed on a window with a YC pixel format.
+ */
+static int vpbe_set_vid_params(struct fb_info *info,
+ struct vpbe_video_config_params *vid_conf_params)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ enum osd_h_exp_ratio h_exp;
+ enum osd_v_exp_ratio v_exp;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ if (vid_conf_params->exp_info.horizontal > H_EXP_3_OVER_2)
+ return -EINVAL;
+
+ if (vid_conf_params->exp_info.vertical > V_EXP_6_OVER_5)
+ return -EINVAL;
+
+ win->dm->yc_pixfmt + vid_conf_params->cb_cr_order ? PIXFMT_YCrCbI : PIXFMT_YCbCrI;
+
+ h_exp = vid_conf_params->exp_info.horizontal;
+ v_exp = vid_conf_params->exp_info.vertical;
+ if (is_vid_win(info))
+ osd_device->ops.set_vid_expansion(osd_device,
+ h_exp, v_exp);
+ else
+ osd_device->ops.set_osd_expansion(osd_device,
+ h_exp, v_exp);
+
+ return 0;
+}
+
+/*
+ * FBIO_GET_BITMAP_CONFIG_PARAMS handler
+ */
+static int vpbe_bitmap_get_params(struct fb_info *info,
+ struct vpbe_bitmap_config_params*
+ bitmap_conf_params)
+{
+ enum osd_layer osdwin = fb_info_to_osd_enum(info);
+ enum osd_clut clut;
+
+ if (!is_osd_win(info))
+ return -EINVAL;
+
+ clut = osd_device->ops.get_osd_clut(osd_device, osdwin);
+ if (clut = ROM_CLUT)
+ bitmap_conf_params->clut_select + osd_device->ops.get_rom_clut(osd_device);
+ else
+ bitmap_conf_params->clut_select = 2;
+
+ bitmap_conf_params->attenuation_enable + osd_device->ops.get_rec601_attenuation(osd_device,
+ osdwin);
+
+ memset(&bitmap_conf_params->clut_idx, 0,
+ sizeof(bitmap_conf_params->clut_idx));
+
+ switch (info->var.bits_per_pixel) {
+ case 1:
+ bitmap_conf_params->clut_idx.for_1bit_bitmap.bitmap_val_0 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 0);
+ bitmap_conf_params->clut_idx.for_1bit_bitmap.bitmap_val_1 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 1);
+ break;
+ case 2:
+ bitmap_conf_params->clut_idx.for_2bit_bitmap.bitmap_val_0 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 0);
+ bitmap_conf_params->clut_idx.for_2bit_bitmap.bitmap_val_1 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 1);
+
+ bitmap_conf_params->clut_idx.for_2bit_bitmap.bitmap_val_2 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 2);
+ bitmap_conf_params->clut_idx.for_2bit_bitmap.bitmap_val_3 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 3);
+ break;
+ case 4:
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_0 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 0);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_1 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 1);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_2 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 2);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_3 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 3);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_4 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 4);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_5 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 5);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_6 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 6);
+
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_7 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 7);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_8 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 8);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_9 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 9);
+
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_10 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 10);
+
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_11 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 11);
+
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_12 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 12);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_13 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 13);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_14 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 14);
+ bitmap_conf_params->clut_idx.for_4bit_bitmap.bitmap_val_15 + osd_device->ops.get_palette_map(osd_device,
+ osdwin, 15);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * FBIO_SET_BITMAP_CONFIG_PARAMS handler
+ *
+ * The palette map is ignored unless the color depth is set to 1, 2, or 4 bits
+ * per pixel. A default palette map is supplied for these color depths where
+ * the clut index is equal to the pixel value. It is not necessary to change
+ * the default palette map when using the RAM clut, because the RAM clut values
+ * can be changed. It is only necessary to modify the default palette map when
+ * using a ROM clut.
+ */
+static int vpbe_bitmap_set_params(struct fb_info *info,
+ struct vpbe_bitmap_config_params*
+ bitmap_conf_params)
+{
+ enum osd_layer osdwin = fb_info_to_osd_enum(info);
+ enum osd_clut clut = ROM_CLUT;
+
+ if (!is_osd_win(info))
+ return -EINVAL;
+
+ if (bitmap_conf_params->clut_select = 0)
+ osd_device->ops.set_rom_clut(osd_device, ROM_CLUT0);
+ else if (bitmap_conf_params->clut_select = 1)
+ osd_device->ops.set_rom_clut(osd_device, ROM_CLUT1);
+ else if (bitmap_conf_params->clut_select = 2)
+ clut = RAM_CLUT;
+ else
+ return -EINVAL;
+
+ osd_device->ops.set_osd_clut(osd_device, osdwin, clut);
+
+ osd_device->ops.set_rec601_attenuation(osd_device, osdwin,
+ bitmap_conf_params->attenuation_enable);
+
+ switch (info->var.bits_per_pixel) {
+ case 1:
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 0, bitmap_conf_params->clut_idx.
+ for_1bit_bitmap.bitmap_val_0);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 1, bitmap_conf_params->clut_idx.
+ for_1bit_bitmap.bitmap_val_1);
+ break;
+ case 2:
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 0, bitmap_conf_params->clut_idx.
+ for_2bit_bitmap.bitmap_val_0);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 1, bitmap_conf_params->clut_idx.
+ for_2bit_bitmap.bitmap_val_1);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 2, bitmap_conf_params->clut_idx.
+ for_2bit_bitmap.bitmap_val_2);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 3, bitmap_conf_params->clut_idx.
+ for_2bit_bitmap.bitmap_val_3);
+
+ break;
+ case 4:
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 0, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_0);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 1, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_1);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 2, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_2);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 3, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_3);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 4, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_4);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 5, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_5);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 6, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_6);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 7, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_7);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 8, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_8);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 9, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_9);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 10, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_10);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 11, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_11);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 12, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_12);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 13, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_13);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 14, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_14);
+ osd_device->ops.set_palette_map(osd_device,
+ osdwin, 15, bitmap_conf_params->clut_idx.
+ for_4bit_bitmap.bitmap_val_15);
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * FBIO_SET_BACKG_COLOR handler
+ */
+static int vpbe_set_backg_color(struct fb_info *info,
+ struct vpbe_backg_color *backg_color)
+{
+ enum osd_clut clut = ROM_CLUT;
+
+ if (backg_color->clut_select = 0)
+ osd_device->ops.set_rom_clut(osd_device, ROM_CLUT0);
+ else if (backg_color->clut_select = 1)
+ osd_device->ops.set_rom_clut(osd_device, ROM_CLUT1);
+ else if (backg_color->clut_select = 2)
+ clut = RAM_CLUT;
+ else
+ return -EINVAL;
+
+ osd_device->ops.set_background(osd_device, clut,
+ backg_color->color_offset);
+
+ return 0;
+}
+
+/*
+ * FBIO_SETPOS handler
+ */
+static int vpbe_setpos(struct fb_info *info,
+ struct vpbe_window_position *win_pos)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ struct fb_var_screeninfo *var = &info->var;
+ unsigned old_xpos = win->xpos;
+ unsigned old_ypos = win->ypos;
+ struct fb_var_screeninfo v;
+ int retval;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ memcpy(&v, var, sizeof(v));
+ win->xpos = win_pos->xpos;
+ win->ypos = win_pos->ypos;
+ retval = info->fbops->fb_check_var(&v, info);
+ if (retval) {
+ win->xpos = old_xpos;
+ win->ypos = old_ypos;
+ return retval;
+ }
+ /* update the window position */
+ memcpy(var, &v, sizeof(v));
+ retval = info->fbops->fb_set_par(info);
+
+ return retval;
+}
+
+/*
+ * FBIO_SET_CURSOR handler
+ */
+static int vpbe_set_cursor_params(struct fb_info *info,
+ struct fb_cursor *fbcursor)
+{
+ struct osd_cursor_config cursor;
+
+ if (!fbcursor->enable) {
+ osd_device->ops.cursor_disable(osd_device);
+ return 0;
+ }
+
+ cursor.xsize = fbcursor->image.width;
+ cursor.ysize = fbcursor->image.height;
+ cursor.xpos = fbcursor->image.dx;
+ cursor.ypos = fbcursor->image.dy;
+ cursor.interlaced = is_window_interlaced(&info->var);
+ cursor.h_width + (fbcursor->image.depth > 7) ? 7 : fbcursor->image.depth;
+ cursor.v_width = cursor.h_width;
+ cursor.clut = ROM_CLUT;
+ cursor.clut_index = fbcursor->image.fg_color;
+ osd_device->ops.set_cursor_config(osd_device, &cursor);
+ osd_device->ops.cursor_enable(osd_device);
+
+ return 0;
+}
+
+/*
+ * fb_ioctl method
+ */
+static int
+vpbe_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+ struct vpbe_bitmap_config_params bitmap_conf_params;
+ struct vpbe_video_config_params vid_conf_params;
+ struct vpbe_bitmap_blend_params blend_para;
+ struct vpbe_dm_win_info *win = info->par;
+ void __user *argp = (void __user *)arg;
+ struct vpbe_blink_option blink_option;
+ struct vpbe_backg_color backg_color;
+ struct vpbe_window_position win_pos;
+ struct fb_fillrect rect;
+ struct zoom_params zoom;
+ struct fb_cursor cursor;
+ int retval = 0;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ /* This ioctl accepts an integer argument to specify a
+ * display. We only support one display, so we will
+ * simply ignore the argument.
+ */
+ return vpbe_fb_wait_for_vsync(info);
+
+ case FBIO_SETATTRIBUTE:
+ if (copy_from_user(&rect, argp, sizeof(rect)))
+ return -EFAULT;
+ return vpbe_set_attr_blend(info, &rect);
+
+ case FBIO_SETPOSX:
+ return vpbe_setposx(info, arg);
+
+ case FBIO_SETPOSY:
+ return vpbe_setposy(info, arg);
+
+ case FBIO_SETZOOM:
+ if (copy_from_user(&zoom, argp, sizeof(zoom)))
+ return -EFAULT;
+ return vpbe_set_zoom(info, &zoom);
+
+ case FBIO_ENABLE_DISABLE_WIN:
+ return vpbe_enable_disable_win(info, arg);
+
+ case FBIO_SET_BITMAP_BLEND_FACTOR:
+ if (copy_from_user(&blend_para, argp, sizeof(blend_para)))
+ return -EFAULT;
+ return vpbe_bitmap_set_blend_factor(info, &blend_para);
+
+ case FBIO_SET_BITMAP_WIN_RAM_CLUT:
+ if (copy_from_user(win->dm->ram_clut[0], argp, RAM_CLUT_SIZE))
+ return -EFAULT;
+ return vpbe_bitmap_set_ram_clut(info, win->dm->ram_clut);
+
+ case FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN:
+ return vpbe_enable_disable_attribute_window(info, arg);
+
+ case FBIO_GET_BLINK_INTERVAL:
+ retval = vpbe_get_blinking(info, &blink_option);
+ if (retval < 0)
+ return retval;
+ if (copy_to_user(argp, &blink_option, sizeof(blink_option)))
+ return -EFAULT;
+ return 0;
+
+ case FBIO_SET_BLINK_INTERVAL:
+ if (copy_from_user(&blink_option, argp, sizeof(blink_option)))
+ return -EFAULT;
+ return vpbe_set_blinking(info, &blink_option);
+
+ case FBIO_GET_VIDEO_CONFIG_PARAMS:
+ retval = vpbe_get_vid_params(info, &vid_conf_params);
+ if (retval < 0)
+ return retval;
+ if (copy_to_user
+ (argp, &vid_conf_params, sizeof(vid_conf_params)))
+ return -EFAULT;
+ return 0;
+
+ case FBIO_SET_VIDEO_CONFIG_PARAMS:
+ if (copy_from_user
+ (&vid_conf_params, argp, sizeof(vid_conf_params)))
+ return -EFAULT;
+ return vpbe_set_vid_params(info, &vid_conf_params);
+
+ case FBIO_GET_BITMAP_CONFIG_PARAMS:
+ retval = vpbe_bitmap_get_params(info, &bitmap_conf_params);
+ if (retval < 0)
+ return retval;
+ if (copy_to_user
+ (argp, &bitmap_conf_params, sizeof(bitmap_conf_params)))
+ return -EFAULT;
+ return 0;
+
+ case FBIO_SET_BITMAP_CONFIG_PARAMS:
+ if (copy_from_user
+ (&bitmap_conf_params, argp, sizeof(bitmap_conf_params)))
+ return -EFAULT;
+ return vpbe_bitmap_set_params(info, &bitmap_conf_params);
+
+ case FBIO_SET_BACKG_COLOR:
+ if (copy_from_user(&backg_color, argp, sizeof(backg_color)))
+ return -EFAULT;
+ return vpbe_set_backg_color(info, &backg_color);
+
+ case FBIO_SETPOS:
+ if (copy_from_user(&win_pos, argp, sizeof(win_pos)))
+ return -EFAULT;
+ return vpbe_setpos(info, &win_pos);
+
+ case FBIO_SET_CURSOR:
+ if (copy_from_user(&cursor, argp, sizeof(cursor)))
+ return -EFAULT;
+ return vpbe_set_cursor_params(info, &cursor);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/*
+ * fb_check_var method
+ */
+static int
+vpbe_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ struct fb_videomode *mode = &win->dm->mode;
+ struct osd_layer_config lconfig;
+ struct fb_fix_screeninfo fix;
+
+ /*
+ * Get an updated copy of the video mode from the encoder manager, just
+ * in case the display has been switched.
+ */
+ get_video_mode(win->dm->vpbe_dev, mode);
+
+ /*
+ * xres, yres, xres_virtual, or yres_virtual equal to zero is treated as
+ * a special case. It indicates that the window should be disabled. If
+ * the window is a video window, it will also be released.
+ */
+ if (var->xres = 0 || var->yres = 0 || var->xres_virtual = 0 ||
+ var->yres_virtual = 0) {
+ var->xres = 0;
+ var->yres = 0;
+ var->xres_virtual = 0;
+ var->yres_virtual = 0;
+ return 0;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ case 24:
+ if (cpu_is_davinci_dm355())
+ return -EINVAL;
+ break;
+ case 32:
+ if (cpu_is_davinci_dm644x())
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (var->xres_virtual < var->xres || var->yres_virtual < var->yres)
+ return -EINVAL;
+ if (var->xoffset > var->xres_virtual - var->xres)
+ return -EINVAL;
+ if (var->yoffset > var->yres_virtual - var->yres)
+ return -EINVAL;
+ if (mode->xres < var->xres || mode->yres < var->yres)
+ return -EINVAL;
+ if (win->xpos > mode->xres - var->xres)
+ return -EINVAL;
+ if (win->ypos > mode->yres - var->yres)
+ return -EINVAL;
+ convert_fb_var_to_osd(var, &lconfig, win->dm->yc_pixfmt);
+
+ update_fix_info(var, &fix);
+ lconfig.line_length = fix.line_length;
+ lconfig.xpos = win->xpos;
+ lconfig.ypos = win->ypos;
+ /* xoffset must be a multiple of xpanstep */
+ if (var->xoffset & ~(fix.xpanstep - 1))
+ return -EINVAL;
+
+ /* check if we have enough video memory to support this mode */
+ if (!window_will_fit_framebuffer(var, info->fix.smem_len))
+ return -EINVAL;
+ /* see if the OSD manager approves of this configuration */
+ if (osd_device->ops.try_layer_config(osd_device,
+ win->layer, &lconfig))
+ return -EINVAL;
+ /*
+ * Reject this var if the OSD manager would have to modify the window
+ * geometry to make it work.
+ */
+ if (lconfig.xsize != var->xres || lconfig.ysize != var->yres)
+ return -EINVAL;
+ if (lconfig.xpos != win->xpos || lconfig.ypos != win->ypos)
+ return -EINVAL;
+ /*
+ * At this point we have accepted the var, so now we convert our layer
+ * configuration struct back to the var in order to make all of the
+ * pixel format and geometry values consistent. The var timing values
+ * will be unmodified, as we have no way to verify them.
+ */
+ convert_osd_to_fb_var(&lconfig, var);
+ return 0;
+}
+
+/*
+ * fb_set_par method
+ */
+static int vpbe_fb_set_par(struct fb_info *info)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ struct vpbe_device *vpbe_dev = win->dm->vpbe_dev;
+ struct fb_var_screeninfo *var = &info->var;
+ struct osd_layer_config lconfig;
+ struct fb_videomode mode;
+ unsigned start;
+
+ /* update the fix info to be consistent with the var */
+ update_fix_info(var, &info->fix);
+ convert_fb_info_to_osd(info, &lconfig);
+
+ /* See if we need to pass the timing values to the encoder manager. */
+ memcpy(&mode, &win->dm->mode, sizeof(mode));
+ fb_var_to_videomode(&mode, var);
+ mode.name = win->dm->mode.name;
+ if (mode.xres = win->dm->mode.xres && mode.yres =
+ win->dm->mode.yres && mode.pixclock != 0 &&
+ !fb_mode_is_equal(&mode, &win->dm->mode)) {
+ /*
+ * If the timing parameters from the var are different than the
+ * timing parameters from the encoder, try to update the
+ * timing parameters with the encoder manager.
+ */
+ set_video_mode(vpbe_dev, &mode);
+ }
+ /* update our copy of the encoder video mode */
+ get_video_mode(vpbe_dev, &win->dm->mode);
+
+ /* turn off ping-pong buffer and field inversion to fix
+ the image shaking problem in 1080I mode. The problem i.d. by the
+ DM6446 Advisory 1.3.8 is not seen in 1080I mode, but the ping-pong
+ buffer workaround created a shaking problem. */
+#if 0
+ if (win->layer = WIN_VID0 &&
+ strcmp(mode.name, VID_ENC_STD_1080I_30) = 0 &&
+ (cpu_is_davinci_dm644x_pg1x() || cpu_is_davinci_dm357()))
+ davinci_disp_set_field_inversion(0);
+#endif
+ /*
+ * Update the var with the encoder timing info. The window geometry
+ * will be preserved.
+ */
+ construct_fb_var(var, &win->dm->mode, &lconfig);
+
+ /* need to update interlaced since the mode may have changed */
+ lconfig.interlaced = var->vmode = win->dm->mode.vmode;
+ /*
+ * xres, yres, xres_virtual, or yres_virtual equal to zero is treated as
+ * a special case. It indicates that the window should be disabled. If
+ * the window is a video window, it will also be released.
+ * Note that we disable the window, but we do not set the
+ * win->disable_window flag. This allows the window to be re-enabled
+ * simply by using the FBIOPUT_VSCREENINFO ioctl to set a valid
+ * configuration.
+ */
+ if (lconfig.xsize = 0 || lconfig.ysize = 0) {
+ if (win->own_window) {
+ osd_device->ops.disable_layer(osd_device, win->layer);
+ if (is_vid_win(info)) {
+ win->own_window = 0;
+ osd_device->ops.release_layer(osd_device,
+ win->layer);
+ }
+ }
+ return 0;
+ }
+
+ /*
+ * If we don't currently own this window, we must claim it from the OSD
+ * manager.
+ */
+ if (!win->own_window) {
+ if (osd_device->ops.request_layer(osd_device,
+ win->layer))
+ return -ENODEV;
+ win->own_window = 1;
+ }
+
+ if (!win->own_window) {
+ if (osd_device->ops.request_layer(osd_device,
+ win->layer))
+ return -ENODEV;
+ win->own_window = 1;
+ }
+
+ /* DM365 YUV420 Planar */
+ if (cpu_is_davinci_dm365() && info->var.bits_per_pixel = 8 &&
+ (win->layer = WIN_VID0 || win->layer = WIN_VID1))
+ start = info->fix.smem_start + (var->xoffset * 12) / 8 +
+ var->yoffset * 3 / 2 * info->fix.line_length;
+ else
+ start = info->fix.smem_start + (var->xoffset *
+ var->bits_per_pixel) / 8 + var->yoffset *
+ info->fix.line_length;
+
+ osd_device->ops.set_layer_config(osd_device, win->layer, &lconfig);
+ osd_device->ops.start_layer(osd_device, win->layer, start,
+ fb_cbcr_ofst);
+ if (win->display_window)
+ osd_device->ops.enable_layer(osd_device,
+ win->layer, 0);
+
+ return 0;
+}
+
+/*
+ * This macro converts a 16-bit color passed to fb_setcolreg to the width
+ * supported by the pixel format.
+ */
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/*
+ * fb_setcolreg method
+ */
+static int vpbe_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ unsigned r;
+ unsigned g;
+ unsigned b;
+ unsigned t;
+
+ /* no. of hw registers */
+ if (regno >= 256)
+ return -EINVAL;
+
+ /*
+ * An RGB color palette isn't applicable to a window with a YUV pixel
+ * format or to a window in attribute mode.
+ */
+ if (is_yuv(&info->var) || is_attribute_mode(&info->var))
+ return -EINVAL;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ r = CNVT_TOHW(red, info->var.red.length);
+ g = CNVT_TOHW(green, info->var.green.length);
+ b = CNVT_TOHW(blue, info->var.blue.length);
+ t = CNVT_TOHW(transp, info->var.transp.length);
+ break;
+ case FB_VISUAL_PSEUDOCOLOR:
+ default:
+ r = CNVT_TOHW(red, 8);
+ g = CNVT_TOHW(green, 8);
+ b = CNVT_TOHW(blue, 8);
+ t = 0;
+ break;
+ }
+
+ /* Truecolor has hardware independent palette */
+ if (info->fix.visual = FB_VISUAL_TRUECOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ v = (r << info->var.red.offset) |
+ (g << info->var.green.offset) |
+ (b << info->var.blue.offset) |
+ (t << info->var.transp.offset);
+
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ ((u16 *) (info->pseudo_palette))[regno] = v;
+ break;
+ case 24:
+ case 32:
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ break;
+ }
+ return 0;
+ }
+
+ if (!is_osd_win(info))
+ return -EINVAL;
+
+ osd_device->ops.set_clut_rgb(osd_device, regno, r, g, b);
+
+ return 0;
+}
+
+static int venc_is_second_field(struct vpbe_device *vpbe_dev)
+{
+ int ret;
+ int val = 0;
+ ret = v4l2_subdev_call(vpbe_dev->venc, core, ioctl, VENC_GET_FLD,
+ &val);
+ if (ret < 0)
+ dev_err(vpbe_dev->pdev, "Error in getting Field ID 0\n");
+ return val;
+}
+
+/*
+ * fb_pan_display method
+ *
+ * Pan the display using the `xoffset' and `yoffset' fields of the `var'
+ * structure. We don't support wrapping and ignore the FB_VMODE_YWRAP flag.
+ */
+static int
+vpbe_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ struct vpbe_device *vpbe_dev = win->dm->vpbe_dev;
+ unsigned start;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ if (var->xoffset > info->var.xres_virtual - info->var.xres)
+ return -EINVAL;
+ if (var->yoffset > info->var.yres_virtual - info->var.yres)
+ return -EINVAL;
+
+ /* xoffset must be a multiple of xpanstep */
+ if (var->xoffset & ~(info->fix.xpanstep - 1))
+ return -EINVAL;
+
+ /* For DM365 video windows:
+ * using bits_per_pixel to calculate start/offset address
+ * needs to be changed for YUV420 planar format since
+ * it is 8. But consider CbCr the real (avg) bits per pixel
+ * is 12. line_length is calcuate using 8, so offset needs
+ * to time 1.5 to take C plane into account.
+ */
+ if (cpu_is_davinci_dm365() && info->var.bits_per_pixel = 8 &&
+ (win->layer = WIN_VID0 || win->layer = WIN_VID1))
+ start = info->fix.smem_start + (var->xoffset * 12) / 8 +
+ var->yoffset * 3 / 2 * info->fix.line_length;
+ else
+ start = info->fix.smem_start + (var->xoffset *
+ info->var.bits_per_pixel) / 8 + var->yoffset *
+ info->fix.line_length;
+
+ if (venc_is_second_field(vpbe_dev))
+ osd_device->ops.start_layer(osd_device, win->layer, start,
+ fb_cbcr_ofst);
+ else
+ win->sdram_address = start;
+
+ return 0;
+}
+
+/*
+ * fb_blank method
+ *
+ * Blank the screen if blank_mode != 0, else unblank.
+ */
+int vpbe_fb_blank(int blank_mode, struct fb_info *info)
+{
+ struct vpbe_dm_win_info *win = info->par;
+ int retval = 0;
+
+ if (!win->own_window)
+ return -ENODEV;
+
+ if (blank_mode) {
+ win->display_window = 0;
+ osd_device->ops.disable_layer(osd_device, win->layer);
+ return retval;
+ }
+ win->display_window = 1;
+ retval = info->fbops->fb_check_var(&info->var, info);
+ if (retval)
+ return retval;
+ retval = info->fbops->fb_set_par(info);
+ return retval;
+}
+
+/*
+ * Frame buffer operations
+ */
+static struct fb_ops vpbe_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = vpbe_fb_check_var,
+ .fb_set_par = vpbe_fb_set_par,
+ .fb_setcolreg = vpbe_fb_setcolreg,
+ .fb_blank = vpbe_fb_blank,
+ .fb_pan_display = vpbe_fb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_rotate = NULL,
+ .fb_sync = NULL,
+ .fb_ioctl = vpbe_fb_ioctl,
+};
+
+static void vpbe_fb_release_window(struct device *dev,
+ struct vpbe_dm_win_info *win)
+{
+ struct fb_info *info = win->info;
+
+ if (info) {
+ unregister_framebuffer(info);
+ win->info = NULL;
+ }
+
+ if (win->own_window) {
+ osd_device->ops.release_layer(osd_device,
+ win->layer);
+ win->own_window = 0;
+ }
+ win->display_window = 0;
+
+ if (info) {
+ dma_free_coherent(dev, info->fix.smem_len, info->screen_base,
+ info->fix.smem_start);
+ fb_dealloc_cmap(&info->cmap);
+ kfree(info);
+ }
+}
+
+static int vpbe_fb_init_window(struct device *dev,
+ struct vpbe_dm_win_info *win,
+ struct osd_layer_config *lconfig,
+ unsigned fb_size, const char *name)
+{
+ struct fb_info *info;
+ int err = 0;
+
+ if (!fb_size)
+ return 0;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "%s: Can't allocate memory for fb_info struct.\n",
+ name);
+ return -ENOMEM;
+ }
+
+ win->info = info;
+ /* initialize fb_info */
+ info->par = win;
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT |
+ FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+ info->fbops = &vpbe_fb_ops;
+ info->screen_size = fb_size;
+ info->pseudo_palette = win->pseudo_palette;
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ dev_err(dev, "%s: Can't allocate color map.\n", name);
+ err = -ENODEV;
+ goto cmap_out;
+ }
+
+ /* initialize fb_fix_screeninfo */
+ strlcpy(info->fix.id, name, sizeof(info->fix.id));
+ info->fix.smem_len = fb_size;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+
+ /* allocate the framebuffer */
+ info->screen_base = dma_alloc_coherent(dev, info->fix.smem_len,
+ (dma_addr_t *) &info->fix.smem_start,
+ GFP_KERNEL | GFP_DMA);
+ if (!info->screen_base) {
+ dev_err(dev, "%s: dma_alloc_coherent failed when allocating "
+ "framebuffer.\n", name);
+ err = -ENOMEM;
+ goto fb_alloc_out;
+ }
+
+ /*
+ * Fill the framebuffer with zeros unless it is an OSD1 window in
+ * attribute mode, in which case we fill it with 0x77 to make the OSD0
+ * pixels opaque.
+ */
+ memset(info->screen_base,
+ (lconfig->pixfmt = PIXFMT_OSD_ATTR) ? 0x77 : 0,
+ info->fix.smem_len);
+
+ /* initialize fb_var_screeninfo */
+ construct_fb_var(&info->var, &win->dm->mode, lconfig);
+ win->xpos = lconfig->xpos;
+ win->ypos = lconfig->ypos;
+ info->var.xres_virtual = info->var.xres;
+ info->var.yres_virtual = info->var.yres;
+
+ /* update the fix info to be consistent with the var */
+ update_fix_info(&info->var, &info->fix);
+
+ /*
+ * Request ownership of the window from the OSD manager unless this is
+ * a video window and the window size is 0.
+ */
+
+ if ((is_osd_win(info) || (info->var.xres != 0 && info->var.yres !+ 0)) && !osd_device->ops.request_layer(osd_device, win->layer)) {
+ win->own_window = 1;
+ }
+ /* bail out if this is an OSD window and we don't own it */
+ if (is_osd_win(info) && !win->own_window) {
+ dev_err(dev, "%s: Failed to obtain ownership of OSD "
+ "window.\n", name);
+ err = -ENODEV;
+ goto own_out;
+ }
+
+ win->display_window = 1;
+
+ if (win->own_window) {
+ /* check if our initial window configuration is valid */
+ if (info->fbops->fb_check_var(&info->var, info))
+ dev_warn(dev, "%s: Initial window configuration is "
+ "invalid.\n", name);
+ else
+ info->fbops->fb_set_par(info);
+ }
+
+ /* register the framebuffer */
+ if (register_framebuffer(info)) {
+ dev_err(dev, "%s: Failed to register framebuffer.\n", name);
+ err = -ENODEV;
+ goto register_out;
+ }
+
+ dev_info(dev, "%s: %dx%dx%d@%d,%d with framebuffer size %dKB\n",
+ info->fix.id, info->var.xres, info->var.yres,
+ info->var.bits_per_pixel, win->xpos, win->ypos,
+ info->fix.smem_len >> 10);
+
+ return 0;
+
+register_out:
+ if (win->own_window)
+ osd_device->ops.release_layer(osd_device,
+ win->layer);
+ win->own_window = 0;
+own_out:
+ dma_free_coherent(dev, info->fix.smem_len, info->screen_base,
+ info->fix.smem_start);
+fb_alloc_out:
+ fb_dealloc_cmap(&info->cmap);
+cmap_out:
+ kfree(info);
+
+ return err;
+}
+
+static int vpbe_fb_remove(struct platform_device *pdev)
+{
+ struct vpbe_dm_info *dm = platform_get_drvdata(pdev);
+ struct vpbe_device *vpbe_dev = dm->vpbe_dev;
+
+ platform_set_drvdata(pdev, NULL);
+
+ v4l2_subdev_call(vpbe_dev->venc, core, ioctl,
+ VENC_UNREG_CALLBACK, &dm->vsync_callback);
+
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_VID1]);
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_OSD1]);
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_VID0]);
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_OSD0]);
+ kfree(dm);
+
+ return 0;
+}
+
+/*
+ * Return the maximum number of bytes per screen for a display layer at a
+ * resolution specified by an fb_videomode struct.
+ */
+static unsigned vpbe_fb_max_screen_size(enum osd_layer layer,
+ const struct fb_videomode *mode)
+{
+ unsigned max_bpp = 32;
+ unsigned line_length;
+ unsigned size;
+
+ switch (layer) {
+ case WIN_OSD0:
+ case WIN_OSD1:
+ if (cpu_is_davinci_dm355())
+ max_bpp = 32;
+ else
+ max_bpp = 16;
+ break;
+ case WIN_VID0:
+ case WIN_VID1:
+ if (cpu_is_davinci_dm355())
+ max_bpp = 16;
+ else
+ max_bpp = 24;
+ break;
+ }
+
+ line_length = (mode->xres * max_bpp + 7) / 8;
+ line_length = ((line_length + 31) / 32) * 32;
+ size = mode->yres * line_length;
+
+ return size;
+}
+
+static void parse_win_params(struct vpbe_dm_win_info *win,
+ struct osd_layer_config *lconfig,
+ unsigned *fb_size, char *opt)
+{
+ unsigned bits_per_pixel;
+ char c = 0;
+ char *s;
+ char *p;
+
+ if (!opt)
+ return;
+
+ /* xsize */
+ p = strpbrk(opt, "x,@");
+ if (p)
+ c = *p;
+ s = strsep(&opt, "x,@");
+ if (s = NULL)
+ return;
+ if (*s)
+ lconfig->xsize = simple_strtoul(s, NULL, 0);
+ if (!p || !opt)
+ return;
+
+ /* ysize */
+ if (c = 'x') {
+ p = strpbrk(opt, "x,@");
+ if (p)
+ c = *p;
+ s = strsep(&opt, "x,@");
+ if (s = NULL)
+ return;
+ if (*s)
+ lconfig->ysize = simple_strtoul(s, NULL, 0);
+ if (!p || !opt)
+ return;
+ }
+
+ /* bits per pixel */
+ if (c = 'x') {
+ p = strpbrk(opt, ",@");
+ if (p)
+ c = *p;
+ s = strsep(&opt, ",@");
+ if (s = NULL)
+ return;
+
+ if (!*s)
+ goto bits_per_pixel_out;
+
+ bits_per_pixel = simple_strtoul(s, NULL, 0);
+ switch (bits_per_pixel) {
+ case 1:
+ if (win->layer = WIN_OSD0 ||
+ win->layer = WIN_OSD1)
+ lconfig->pixfmt = PIXFMT_1BPP;
+ break;
+ case 2:
+ if (win->layer = WIN_OSD0 ||
+ win->layer = WIN_OSD1)
+ lconfig->pixfmt = PIXFMT_2BPP;
+ break;
+ case 4:
+ if (win->layer = WIN_OSD0 ||
+ win->layer = WIN_OSD1)
+ lconfig->pixfmt = PIXFMT_4BPP;
+ break;
+ case 8:
+ if (win->layer = WIN_OSD0 ||
+ win->layer = WIN_OSD1)
+ lconfig->pixfmt = PIXFMT_8BPP;
+ if (cpu_is_davinci_dm365())
+ if (win->layer = WIN_VID0 ||
+ win->layer = WIN_VID1)
+ lconfig->pixfmt = PIXFMT_NV12;
+ break;
+ case 16:
+ if (win->layer = WIN_OSD0 ||
+ win->layer = WIN_OSD1)
+ lconfig->pixfmt = PIXFMT_RGB565;
+ else
+ lconfig->pixfmt = win->dm->yc_pixfmt;
+ break;
+ case 24:
+ if (cpu_is_davinci_dm644x() &&
+ (win->layer = WIN_VID0 ||
+ win->layer = WIN_VID1))
+ lconfig->pixfmt = PIXFMT_RGB888;
+ break;
+ case 32:
+ if (cpu_is_davinci_dm355() &&
+ (win->layer = WIN_OSD0 || win->layer = WIN_OSD1))
+ lconfig->pixfmt = PIXFMT_RGB888;
+ break;
+ default:
+ break;
+ }
+
+bits_per_pixel_out:
+ if (!p || !opt)
+ return;
+ }
+
+ /* framebuffer size */
+ if (c = ',') {
+ p = strpbrk(opt, "@");
+ if (p)
+ c = *p;
+ s = strsep(&opt, "@");
+ if (s = NULL)
+ return;
+ if (*s) {
+ *fb_size = simple_strtoul(s, &s, 0);
+ if (*s = 'K')
+ *fb_size <<= 10;
+ if (*s = 'M')
+ *fb_size <<= 20;
+ }
+ if (!p || !opt)
+ return;
+ }
+
+ /* xpos */
+ if (c = '@') {
+ p = strpbrk(opt, ",");
+ if (p)
+ c = *p;
+ s = strsep(&opt, ",");
+ if (s = NULL)
+ return;
+ if (*s)
+ lconfig->xpos = simple_strtoul(s, NULL, 0);
+ if (!p || !opt)
+ return;
+ }
+
+ /* ypos */
+ if (c = ',') {
+ s = opt;
+ if (*s)
+ lconfig->ypos = simple_strtoul(s, NULL, 0);
+ }
+
+ return;
+}
+
+/*
+ * Pass boot-time options by adding the following string to the boot params:
+ * video=vpbe_fb:options
+ * Valid options:
+ * osd0=[MxNxP,S@X,Y]
+ * osd1=[MxNxP,S@X,Y]
+ * vid0=[off|MxNxP,S@X,Y]
+ * vid1=[off|MxNxP,S@X,Y]
+ * MxN are the horizontal and vertical window size
+ * P is the color depth (bits per pixel)
+ * S is the framebuffer size with a size suffix such as 'K' or 'M'
+ * X,Y are the window position
+ *
+ * Only video windows can be turned off. Turning off a video window means that
+ * no framebuffer device will be registered for it,
+ *
+ * To cause a window to be supported by the framebuffer driver but not displayed
+ * initially, pass a value of 0 struct vpbe_dm_win_info *win = info->par;
+ * struct vpbe_device *vpbe_dev = win->dm->vpbe_dev; for the window size.
+ *
+ * For example:
+ * video=vpbe_fb:osd0r0x480x16@0,0:osd1r0x480:vid0=off:vid1=off
+ *
+ * This routine returns 1 if the window is to be turned off, or 0 otherwise.
+ */
+static int vpbe_fb_get_default_win_config(struct device *dev,
+ struct vpbe_dm_win_info *win,
+ struct osd_layer_config *lconfig,
+ unsigned *fb_size,
+ const char *options)
+{
+ const char *win_names[] = { "osd0=", "vid0=", "osd1=", "vid1=" };
+ static char opt_buf[128];
+ const char *this_opt;
+ const char *next_opt;
+ int this_len;
+ int opt_len;
+
+ /* supply default values for lconfig and fb_size */
+ switch (win->layer) {
+ case WIN_OSD0:
+ lconfig->pixfmt = PIXFMT_RGB565;
+ lconfig->xsize = win->dm->mode.xres;
+ lconfig->ysize = win->dm->mode.yres;
+ break;
+ case WIN_OSD1:
+ lconfig->pixfmt = PIXFMT_OSD_ATTR;
+ lconfig->xsize = win->dm->mode.xres;
+ lconfig->ysize = win->dm->mode.yres;
+ break;
+ case WIN_VID0:
+ case WIN_VID1:
+ lconfig->pixfmt = win->dm->yc_pixfmt;
+ lconfig->xsize = 0;
+ lconfig->ysize = 0;
+ break;
+ }
+ lconfig->xpos = 0;
+ lconfig->ypos = 0;
+
+ lconfig->interlaced = is_display_interlaced(&win->dm->mode);
+ *fb_size = vpbe_fb_max_screen_size(win->layer, &win->dm->mode);
+
+ next_opt = options;
+ while ((this_opt = next_opt)) {
+ this_len = strcspn(this_opt, ":");
+ next_opt = strpbrk(this_opt, ":");
+ if (next_opt)
+ ++next_opt;
+
+ opt_len = strlen(win_names[win->layer]);
+ if (this_len >= opt_len) {
+ if (strncmp(this_opt, win_names[win->layer], opt_len))
+ continue;
+ this_len -= opt_len;
+ this_opt += opt_len;
+ if ((this_len >= strlen("off")) &&
+ !strncmp(this_opt, "off", strlen("off")))
+ return 1;
+ else {
+ strlcpy(opt_buf, this_opt,
+ min_t(int, sizeof(opt_buf),
+ this_len + 1));
+ parse_win_params(win, lconfig, fb_size,
+ opt_buf);
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Module parameter definitions
+ */
+static char *options = "";
+
+module_param(options, charp, S_IRUGO);
+
+static int vpbe_fb_callback_init(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vpbe_dm_info *dm = (struct vpbe_dm_info *)data;
+
+ if (strcmp("vpbe_controller", pdev->name) = 0)
+ dm->vpbe_dev = platform_get_drvdata(pdev);
+ return 0;
+}
+
+static int vpbe_device_get(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ if (strcmp("vpbe-osd", pdev->name) = 0)
+ osd_device = platform_get_drvdata(pdev);
+
+ return 0;
+}
+
+static int vpbe_fb_probe(struct platform_device *pdev)
+{
+ struct osd_layer_config lconfig;
+ struct device_driver *drv;
+ struct vpbe_dm_info *dm;
+ unsigned fb_size;
+ int err;
+
+ dm = kzalloc(sizeof(*dm), GFP_KERNEL);
+ if (!dm) {
+ dev_err(&pdev->dev, "Can't allocate memory for driver state.\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Scan all the platform devices to find the vpbe
+ * controller device and get the vpbe_dev object
+ */
+ drv = driver_find("vpbe_controller", &platform_bus_type);
+ err = driver_for_each_device(drv, NULL, dm, vpbe_fb_callback_init);
+ if ((err < 0) || (dm->vpbe_dev = NULL))
+ return -ENODEV;
+
+ if (!dm->vpbe_dev->initialized) {
+ dev_err(&pdev->dev, "vpbe controller not initialized\n");
+ return -ENODEV;
+ }
+
+ err = bus_for_each_dev(&platform_bus_type, NULL, NULL,
+ vpbe_device_get);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(pdev, dm);
+
+ /* get the video mode from the encoder manager */
+ get_video_mode(dm->vpbe_dev, &dm->mode);
+
+ /* set the default Cb/Cr order */
+ dm->yc_pixfmt = PIXFMT_YCbCrI;
+
+ /* initialize OSD0 */
+ dm->win[WIN_OSD0].layer = WIN_OSD0;
+ dm->win[WIN_OSD0].dm = dm;
+ dm->win[WIN_OSD0].sdram_address = 0;
+ vpbe_fb_get_default_win_config(&pdev->dev, &dm->win[WIN_OSD0],
+ &lconfig, &fb_size, options);
+ err = vpbe_fb_init_window(&pdev->dev, &dm->win[WIN_OSD0],
+ &lconfig, fb_size, OSD0_FBNAME);
+ if (err)
+ goto osd0_out;
+
+ /* initialize VID0 */
+ dm->win[WIN_VID0].layer = WIN_VID0;
+ dm->win[WIN_VID0].dm = dm;
+ dm->win[WIN_VID0].sdram_address = 0;
+ if (!vpbe_fb_get_default_win_config(&pdev->dev, &dm->win[WIN_VID0],
+ &lconfig, &fb_size, options)) {
+ err = vpbe_fb_init_window(&pdev->dev, &dm->win[WIN_VID0],
+ &lconfig, fb_size, VID0_FBNAME);
+ if (err)
+ goto vid0_out;
+ }
+
+ /* initialize OSD1 */
+ dm->win[WIN_OSD1].layer = WIN_OSD1;
+ dm->win[WIN_OSD1].dm = dm;
+ dm->win[WIN_OSD1].sdram_address = 0;
+ vpbe_fb_get_default_win_config(&pdev->dev, &dm->win[WIN_OSD1],
+ &lconfig, &fb_size, options);
+ err + vpbe_fb_init_window(&pdev->dev, &dm->win[WIN_OSD1],
+ &lconfig, fb_size, OSD1_FBNAME);
+ if (err)
+ goto osd1_out;
+
+ /* initialize VID1 */
+ dm->win[WIN_VID1].layer = WIN_VID1;
+ dm->win[WIN_VID1].dm = dm;
+ dm->win[WIN_VID1].sdram_address = 0;
+ if (!vpbe_fb_get_default_win_config(&pdev->dev, &dm->win[WIN_VID1],
+ &lconfig, &fb_size, options)) {
+ err = vpbe_fb_init_window(&pdev->dev, &dm->win[WIN_VID1],
+ &lconfig, fb_size, VID1_FBNAME);
+ if (err)
+ goto vid1_out;
+ }
+
+ /* initialize the vsync wait queue */
+ init_waitqueue_head(&dm->vsync_wait);
+ dm->timeout = HZ / 5;
+
+ /* register the end-of-frame callback */
+ dm->vsync_callback.mask = VENC_FIRST_FIELD |
+ VENC_SECOND_FIELD | VENC_END_OF_FRAME;
+
+ dm->vsync_callback.handler = vpbe_fb_vsync_callback;
+ dm->vsync_callback.arg = dm;
+
+ v4l2_subdev_call(dm->vpbe_dev->venc, core, ioctl,
+ VENC_REG_CALLBACK, &dm->vsync_callback);
+
+ printk(KERN_NOTICE "VPBE FB Driver probe success\n");
+ return 0;
+
+vid1_out:
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_OSD1]);
+osd1_out:
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_VID0]);
+vid0_out:
+ vpbe_fb_release_window(&pdev->dev, &dm->win[WIN_OSD0]);
+osd0_out:
+ kfree(dm);
+
+ return err;
+}
+
+static struct platform_driver vpbe_fb_driver = {
+ .driver = {
+ .name = "vpbe-fb",
+ .owner = THIS_MODULE,
+ .bus = &platform_bus_type,
+ },
+ .probe = vpbe_fb_probe,
+ .remove = __devexit_p(vpbe_fb_remove),
+};
+
+
+static int __init vpbe_fb_init(void)
+{
+#ifndef MODULE
+ {
+ char *names[] = { "vpbe_fb", "dm64xxfb", "dm355fb" };
+ int i, num_names = 3;
+
+ for (i = 0; i < num_names; i++) {
+ if (fb_get_options(names[i], &options)) {
+ printk(KERN_ERR " Disabled on command-line.\n");
+ return -ENODEV;
+ }
+ if (options)
+ break;
+ }
+ }
+#endif
+ /* Register the driver with LDM */
+ if (platform_driver_register(&vpbe_fb_driver)) {
+ printk(KERN_ERR "failed to register vpbe_fb driver\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit vpbe_fb_cleanup(void)
+{
+ platform_driver_unregister(&vpbe_fb_driver);
+}
+
+module_init(vpbe_fb_init);
+module_exit(vpbe_fb_cleanup);
+
+MODULE_DESCRIPTION("TI VPBE Framebuffer driver");
+MODULE_AUTHOR("Texas Instruments Ltd");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/davinci/vpbe_fb.h b/drivers/media/video/davinci/vpbe_fb.h
new file mode 100644
index 0000000..4f312b7
--- /dev/null
+++ b/drivers/media/video/davinci/vpbe_fb.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 MontaVista Software Inc.
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option)any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef VPBE_FB_H
+#define VPBE_FB_H
+
+#include <linux/poll.h>
+#include <linux/wait.h>
+
+#define DAVINCIFB_NAME "davincifb"
+
+/* There are 4 framebuffer devices, one per window. */
+#define OSD0_FBNAME "dm_osd0_fb"
+#define OSD1_FBNAME "dm_osd1_fb"
+#define VID0_FBNAME "dm_vid0_fb"
+#define VID1_FBNAME "dm_vid1_fb"
+
+/* Structure for each window */
+struct vpbe_dm_win_info {
+ struct fb_info *info;
+ struct vpbe_dm_info *dm;
+ enum osd_layer layer;
+ unsigned xpos;
+ unsigned ypos;
+ unsigned own_window; /* Does the framebuffer driver own this window? */
+ unsigned display_window;
+ unsigned sdram_address;
+ unsigned int pseudo_palette[16];
+};
+
+/*
+ * Structure for the driver holding information of windows,
+ * memory base addresses etc.
+ */
+struct vpbe_dm_info {
+ struct vpbe_dm_win_info win[4];
+
+ wait_queue_head_t vsync_wait;
+ unsigned int vsync_cnt;
+ int timeout;
+ struct venc_callback vsync_callback;
+
+ unsigned char ram_clut[256][3];
+ enum osd_pix_format yc_pixfmt;
+
+ struct fb_videomode mode;
+ struct vpbe_device *vpbe_dev;
+};
+
+#endif /* ifndef DAVINCIFB__H */
diff --git a/drivers/media/video/davinci/vpbe_fb_ioctl.h b/drivers/media/video/davinci/vpbe_fb_ioctl.h
new file mode 100644
index 0000000..1787e69
--- /dev/null
+++ b/drivers/media/video/davinci/vpbe_fb_ioctl.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2009 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option)any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DAVINCIFB_IOCTL_H
+#define DAVINCIFB_IOCTL_H
+
+/*
+ * Structures and Union Definitions
+ */
+
+struct zoom_params {
+ u_int32_t window_id;
+ u_int32_t zoom_h;
+ u_int32_t zoom_v;
+};
+
+/* Structure for transparency and the blending factor for the bitmap window */
+struct vpbe_bitmap_blend_params {
+ unsigned int colorkey; /* color key to be blended */
+ unsigned int enable_colorkeying; /* enable color keying */
+ unsigned int bf; /* valid range from 0 to 7 only. */
+};
+
+/* Structure for window expansion */
+struct vpbe_win_expansion {
+ unsigned char horizontal;
+ unsigned char vertical; /* 1: Enable 0:disable */
+};
+
+/* Structure for OSD window blinking options */
+struct vpbe_blink_option {
+ unsigned char blinking; /* 1: Enable blinking 0: Disable */
+ unsigned int interval; /* Valid only if blinking is 1 */
+};
+
+/* Structure for background color */
+struct vpbe_backg_color {
+ /* 2: RAM CLUT 1:ROM1 CLUT 0:ROM0 CLUT */
+ unsigned char clut_select;
+ unsigned char color_offset; /* index of color */
+};
+
+/* Structure for Video window configurable parameters */
+struct vpbe_video_config_params {
+ /* Cb/Cr order in input data for a pixel. */
+ unsigned char cb_cr_order; /* 0: cb cr 1: cr cb */
+ /* HZ/VT Expansion enable disable */
+ struct vpbe_win_expansion exp_info;
+};
+
+/*
+ * Union of structures giving the CLUT index for the 1, 2, 4 bit bitmap values
+ */
+union vpbe_clut_idx {
+ struct _for_4bit_bitmap {
+ unsigned char bitmap_val_0;
+ unsigned char bitmap_val_1;
+ unsigned char bitmap_val_2;
+ unsigned char bitmap_val_3;
+ unsigned char bitmap_val_4;
+ unsigned char bitmap_val_5;
+ unsigned char bitmap_val_6;
+ unsigned char bitmap_val_7;
+ unsigned char bitmap_val_8;
+ unsigned char bitmap_val_9;
+ unsigned char bitmap_val_10;
+ unsigned char bitmap_val_11;
+ unsigned char bitmap_val_12;
+ unsigned char bitmap_val_13;
+ unsigned char bitmap_val_14;
+ unsigned char bitmap_val_15;
+ } for_4bit_bitmap;
+ struct _for_2bit_bitmap {
+ unsigned char bitmap_val_0;
+ unsigned char dummy0[4];
+ unsigned char bitmap_val_1;
+ unsigned char dummy1[4];
+ unsigned char bitmap_val_2;
+ unsigned char dummy2[4];
+ unsigned char bitmap_val_3;
+ } for_2bit_bitmap;
+ struct _for_1bit_bitmap {
+ unsigned char bitmap_val_0;
+ unsigned char dummy0[14];
+ unsigned char bitmap_val_1;
+ } for_1bit_bitmap;
+};
+
+/* Structure for bitmap window configurable parameters */
+struct vpbe_bitmap_config_params {
+ /* Only for bitmap width = 1,2,4 bits */
+ union vpbe_clut_idx clut_idx;
+ /* Attenuation value for YUV o/p for bitmap window */
+ unsigned char attenuation_enable;
+ /* 0: ROM DM270, 1:ROM DM320, 2:RAM CLUT */
+ unsigned char clut_select;
+};
+
+/* Structure to hold window position */
+struct vpbe_window_position {
+ unsigned int xpos; /* X position of the window */
+ unsigned int ypos; /* Y position of the window */
+};
+
+#define RAM_CLUT_SIZE (256*3)
+
+#define FBIO_SETATTRIBUTE _IOW('F', 0x21, struct fb_fillrect)
+#define FBIO_SETPOSX _IOW('F', 0x22, u_int32_t)
+#define FBIO_SETPOSY _IOW('F', 0x23, u_int32_t)
+#define FBIO_SETZOOM _IOW('F', 0x24, struct zoom_params)
+#define FBIO_ENABLE_DISABLE_WIN \
+ _IOW('F', 0x30, unsigned char)
+#define FBIO_SET_BITMAP_BLEND_FACTOR \
+ _IOW('F', 0x31, struct vpbe_bitmap_blend_params)
+#define FBIO_SET_BITMAP_WIN_RAM_CLUT \
+ _IOW('F', 0x32, unsigned char[RAM_CLUT_SIZE])
+#define FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN \
+ _IOW('F', 0x33, unsigned int)
+#define FBIO_GET_BLINK_INTERVAL \
+ _IOR('F', 0x34, struct vpbe_blink_option)
+#define FBIO_SET_BLINK_INTERVAL \
+ _IOW('F', 0x35, struct vpbe_blink_option)
+#define FBIO_GET_VIDEO_CONFIG_PARAMS \
+ _IOR('F', 0x36, struct vpbe_video_config_params)
+#define FBIO_SET_VIDEO_CONFIG_PARAMS \
+ _IOW('F', 0x37, struct vpbe_video_config_params)
+#define FBIO_GET_BITMAP_CONFIG_PARAMS \
+ _IOR('F', 0x38, struct vpbe_bitmap_config_params)
+#define FBIO_SET_BITMAP_CONFIG_PARAMS \
+ _IOW('F', 0x39, struct vpbe_bitmap_config_params)
+#define FBIO_SET_BACKG_COLOR \
+ _IOW('F', 0x47, struct vpbe_backg_color)
+#define FBIO_SETPOS \
+ _IOW('F', 0x49, u_int32_t)
+#define FBIO_SET_CURSOR \
+ _IOW('F', 0x50, struct fb_cursor)
+
+/* Window ID definitions */
+#define OSD0 0
+#define VID0 1
+#define OSD1 2
+#define VID1 3
+
+#endif /* ifndef DAVINCIFB_IOCTL_H */
--
1.6.2.4
^ permalink raw reply related
* [RFC PATCH 1/3] davinci: vpbe: enable vpbe for fbdev addition
From: Manjunath Hadli @ 2011-09-26 13:47 UTC (permalink / raw)
To: linux-fbdev
enable the venc, osd and vpbe display driver for addition
of fbdev driver. Mainly includes fbdev ops structure inclusion,
palette and osd layer related functionality for OSD block.
Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
---
drivers/media/video/davinci/vpbe_display.c | 6 +
drivers/media/video/davinci/vpbe_osd.c | 793 +++++++++++++++++++++++++++-
drivers/media/video/davinci/vpbe_venc.c | 84 +++
include/media/davinci/vpbe_osd.h | 64 +++-
include/media/davinci/vpbe_venc.h | 21 +
5 files changed, 959 insertions(+), 9 deletions(-)
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
index 09a659e..9eb97f6 100644
--- a/drivers/media/video/davinci/vpbe_display.c
+++ b/drivers/media/video/davinci/vpbe_display.c
@@ -119,9 +119,11 @@ static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
static irqreturn_t venc_isr(int irq, void *arg)
{
struct vpbe_display *disp_dev = (struct vpbe_display *)arg;
+ struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
struct vpbe_layer *layer;
static unsigned last_event;
unsigned event = 0;
+ int ret;
int fid;
int i;
@@ -194,6 +196,10 @@ static irqreturn_t venc_isr(int irq, void *arg)
vpbe_isr_odd_field(disp_dev, layer);
}
}
+ ret = v4l2_subdev_call(vpbe_dev->venc, core, ioctl, VENC_INTERRUPT,
+ &event);
+ if (ret < 0)
+ v4l2_err(&vpbe_dev->v4l2_dev, "Error in getting Field ID 0\n");
return IRQ_HANDLED;
}
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c
index 2dc21fa..eb07d61 100644
--- a/drivers/media/video/davinci/vpbe_osd.c
+++ b/drivers/media/video/davinci/vpbe_osd.c
@@ -158,6 +158,13 @@ static int _osd_dm6446_vid0_pingpong(struct osd_state *sd,
return 0;
}
+static int osd_get_field_inversion(struct osd_state *sd)
+{
+ struct osd_state *osd = sd;
+
+ return osd->field_inversion;
+}
+
static void _osd_set_field_inversion(struct osd_state *sd, int enable)
{
unsigned fsinv = 0;
@@ -168,6 +175,359 @@ static void _osd_set_field_inversion(struct osd_state *sd, int enable)
osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE);
}
+static void osd_set_field_inversion(struct osd_state *sd, int enable)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->field_inversion = (enable != 0);
+ _osd_set_field_inversion(sd, enable);
+
+ osd->pingpong = _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+ osd->win[WIN_VID0].fb_base_phys,
+ &osd->win[WIN_VID0].lconfig);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_get_background(struct osd_state *sd, enum osd_clut *clut,
+ unsigned char *clut_index)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ *clut = osd->backg_clut;
+ *clut_index = osd->backg_clut_index;
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_set_background(struct osd_state *sd, enum osd_clut clut,
+ unsigned char clut_index)
+{
+ u32 mode = 0;
+
+ if (clut = RAM_CLUT)
+ mode |= OSD_MODE_BCLUT;
+ mode |= clut_index;
+ osd_modify(sd, OSD_MODE_BCLUT | OSD_MODE_CABG, mode, OSD_MODE);
+}
+
+static void osd_set_background(struct osd_state *sd, enum osd_clut clut,
+ unsigned char clut_index)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->backg_clut = clut;
+ osd->backg_clut_index = clut_index;
+ _osd_set_background(sd, clut, clut_index);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static int osd_get_interpolation_filter(struct osd_state *sd)
+{
+ struct osd_state *osd = sd;
+
+ return osd->interpolation_filter;
+}
+
+static void _osd_set_interpolation_filter(struct osd_state *sd, int filter)
+{
+ struct osd_state *osd = sd;
+
+ if (osd->vpbe_type = VPBE_VERSION_3 ||
+ osd->vpbe_type = VPBE_VERSION_2)
+ osd_clear(sd, OSD_EXTMODE_EXPMDSEL, OSD_EXTMODE);
+ osd_modify(sd, OSD_MODE_EF, filter ? OSD_MODE_EF : 0, OSD_MODE);
+}
+
+static void osd_set_interpolation_filter(struct osd_state *sd, int filter)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->interpolation_filter = (filter != 0);
+ _osd_set_interpolation_filter(sd, filter);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_get_cursor_config(struct osd_state *sd,
+ struct osd_cursor_config *cursor)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ *cursor = osd->cursor.config;
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_set_cursor_config(struct osd_state *sd,
+ const struct osd_cursor_config *cursor)
+{
+ struct osd_state *osd = sd;
+ unsigned rectcur = 0;
+
+ osd_write(sd, cursor->xsize, OSD_CURXL);
+ osd_write(sd, cursor->xpos, OSD_CURXP);
+
+ if (cursor->interlaced) {
+ osd_write(sd, cursor->ypos >> 1, OSD_CURYP);
+ if (osd->vpbe_type = VPBE_VERSION_1)
+ /* Must add 1 to ysize due to device erratum. */
+ osd_write(sd, (cursor->ysize >> 1) + 1, OSD_CURYL);
+ else
+ osd_write(sd, cursor->ysize >> 1, OSD_CURYL);
+ } else {
+ osd_write(sd, cursor->ypos, OSD_CURYP);
+ if (osd->vpbe_type = VPBE_VERSION_1)
+ /* Must add 1 to ysize due to device erratum. */
+ osd_write(sd, cursor->ysize + 1, OSD_CURYL);
+ else
+ osd_write(sd, cursor->ysize, OSD_CURYL);
+ }
+
+ if (cursor->clut = RAM_CLUT)
+ rectcur |= OSD_RECTCUR_CLUTSR;
+ rectcur |= (cursor->clut_index << OSD_RECTCUR_RCAD_SHIFT);
+ rectcur |= (cursor->h_width << OSD_RECTCUR_RCHW_SHIFT);
+ rectcur |= (cursor->v_width << OSD_RECTCUR_RCVW_SHIFT);
+ osd_modify(sd, OSD_RECTCUR_RCAD | OSD_RECTCUR_CLUTSR |
+ OSD_RECTCUR_RCHW | OSD_RECTCUR_RCVW, rectcur, OSD_RECTCUR);
+}
+
+static void osd_set_cursor_config(struct osd_state *sd,
+ struct osd_cursor_config *cursor)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ cursor->xsize = min(cursor->xsize, (unsigned)OSD_CURXL_RCSW);
+ cursor->ysize = min(cursor->ysize, (unsigned)OSD_CURYL_RCSH);
+ cursor->xpos = min(cursor->xpos, (unsigned)OSD_CURXP_RCSX);
+ cursor->ypos = min(cursor->ypos, (unsigned)OSD_CURYP_RCSY);
+ cursor->interlaced = (cursor->interlaced != 0);
+ if (cursor->interlaced) {
+ cursor->ysize &= ~1;
+ cursor->ypos &= ~1;
+ }
+ cursor->h_width &= (OSD_RECTCUR_RCHW >> OSD_RECTCUR_RCHW_SHIFT);
+ cursor->v_width &= (OSD_RECTCUR_RCVW >> OSD_RECTCUR_RCVW_SHIFT);
+ cursor->clut = (cursor->clut = RAM_CLUT) ? RAM_CLUT : ROM_CLUT;
+
+ osd->cursor.config = *cursor;
+ _osd_set_cursor_config(sd, cursor);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static int osd_cursor_is_enabled(struct osd_state *sd)
+{
+ struct osd_state *osd = sd;
+
+ return osd->cursor.is_enabled;
+}
+
+static void _osd_cursor_disable(struct osd_state *sd)
+{
+ osd_clear(sd, OSD_RECTCUR_RCACT, OSD_RECTCUR);
+}
+
+static void osd_cursor_disable(struct osd_state *sd)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->cursor.is_enabled = 0;
+ _osd_cursor_disable(sd);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_cursor_enable(struct osd_state *sd)
+{
+ osd_set(sd, OSD_RECTCUR_RCACT, OSD_RECTCUR);
+}
+
+static void osd_cursor_enable(struct osd_state *sd)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->cursor.is_enabled = 1;
+ _osd_cursor_enable(sd);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_get_vid_expansion(struct osd_state *sd,
+ enum osd_h_exp_ratio *h_exp,
+ enum osd_v_exp_ratio *v_exp)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ *h_exp = osd->vid_h_exp;
+ *v_exp = osd->vid_v_exp;
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_set_vid_expansion(struct osd_state *sd,
+ enum osd_h_exp_ratio h_exp,
+ enum osd_v_exp_ratio v_exp)
+{
+ struct osd_state *osd = sd;
+ u32 mode = 0;
+ u32 extmode = 0;
+
+ switch (h_exp) {
+ case H_EXP_OFF:
+ break;
+ case H_EXP_9_OVER_8:
+ mode |= OSD_MODE_VHRSZ;
+ break;
+ case H_EXP_3_OVER_2:
+ extmode |= OSD_EXTMODE_VIDHRSZ15;
+ break;
+ }
+
+ switch (v_exp) {
+ case V_EXP_OFF:
+ break;
+ case V_EXP_6_OVER_5:
+ mode |= OSD_MODE_VVRSZ;
+ break;
+ }
+
+ if (osd->vpbe_type = VPBE_VERSION_3 ||
+ osd->vpbe_type = VPBE_VERSION_2)
+ osd_modify(sd, OSD_EXTMODE_VIDHRSZ15, extmode, OSD_EXTMODE);
+ osd_modify(sd, OSD_MODE_VHRSZ | OSD_MODE_VVRSZ, mode, OSD_MODE);
+}
+
+static int osd_set_vid_expansion(struct osd_state *sd,
+ enum osd_h_exp_ratio h_exp,
+ enum osd_v_exp_ratio v_exp)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ if (h_exp = H_EXP_3_OVER_2 && (osd->vpbe_type = VPBE_VERSION_1))
+ return -EINVAL;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->vid_h_exp = h_exp;
+ osd->vid_v_exp = v_exp;
+ _osd_set_vid_expansion(sd, h_exp, v_exp);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+ return 0;
+}
+
+static void osd_get_osd_expansion(struct osd_state *sd,
+ enum osd_h_exp_ratio *h_exp,
+ enum osd_v_exp_ratio *v_exp)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ *h_exp = osd->osd_h_exp;
+ *v_exp = osd->osd_v_exp;
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_set_osd_expansion(struct osd_state *sd,
+ enum osd_h_exp_ratio h_exp,
+ enum osd_v_exp_ratio v_exp)
+{
+ struct osd_state *osd = sd;
+ u32 mode = 0;
+ u32 extmode = 0;
+
+ switch (h_exp) {
+ case H_EXP_OFF:
+ break;
+ case H_EXP_9_OVER_8:
+ mode |= OSD_MODE_OHRSZ;
+ break;
+ case H_EXP_3_OVER_2:
+ extmode |= OSD_EXTMODE_OSDHRSZ15;
+ break;
+ }
+
+ switch (v_exp) {
+ case V_EXP_OFF:
+ break;
+ case V_EXP_6_OVER_5:
+ mode |= OSD_MODE_OVRSZ;
+ break;
+ }
+
+ if (osd->vpbe_type = VPBE_VERSION_3 ||
+ osd->vpbe_type = VPBE_VERSION_2)
+ osd_modify(sd, OSD_EXTMODE_OSDHRSZ15, extmode, OSD_EXTMODE);
+ osd_modify(sd, OSD_MODE_OHRSZ | OSD_MODE_OVRSZ, mode, OSD_MODE);
+}
+
+static int osd_set_osd_expansion(struct osd_state *sd,
+ enum osd_h_exp_ratio h_exp,
+ enum osd_v_exp_ratio v_exp)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ if (h_exp = H_EXP_3_OVER_2 && (osd->vpbe_type = VPBE_VERSION_1))
+ return -EINVAL;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->osd_h_exp = h_exp;
+ osd->osd_v_exp = v_exp;
+ _osd_set_osd_expansion(sd, h_exp, v_exp);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+ return 0;
+}
+
+static void osd_get_blink_attribute(struct osd_state *sd, int *enable,
+ enum osd_blink_interval *blink)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ *enable = osd->is_blinking;
+ *blink = osd->blink;
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
static void _osd_set_blink_attribute(struct osd_state *sd, int enable,
enum osd_blink_interval blink)
{
@@ -182,6 +542,29 @@ static void _osd_set_blink_attribute(struct osd_state *sd, int enable,
OSD_OSDATRMD);
}
+static void osd_set_blink_attribute(struct osd_state *sd, int enable,
+ enum osd_blink_interval blink)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->is_blinking = (enable != 0);
+ osd->blink = blink;
+ if (osd->win[WIN_OSD1].lconfig.pixfmt = PIXFMT_OSD_ATTR)
+ _osd_set_blink_attribute(sd, enable, blink);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static enum osd_rom_clut osd_get_rom_clut(struct osd_state *sd)
+{
+ struct osd_state *osd = sd;
+
+ return osd->rom_clut;
+}
+
static void _osd_set_rom_clut(struct osd_state *sd,
enum osd_rom_clut rom_clut)
{
@@ -191,6 +574,150 @@ static void _osd_set_rom_clut(struct osd_state *sd,
osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
}
+static void osd_set_rom_clut(struct osd_state *sd,
+ enum osd_rom_clut rom_clut)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->rom_clut = rom_clut;
+ _osd_set_rom_clut(sd, rom_clut);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_set_clut_ycbcr(struct osd_state *sd,
+ unsigned char clut_index,
+ unsigned char y, unsigned char cb,
+ unsigned char cr)
+{
+ /* wait until any previous writes to the CLUT RAM have completed */
+ while (osd_read(sd, OSD_MISCCTL) & OSD_MISCCTL_CPBSY)
+ cpu_relax();
+
+ osd_write(sd, (y << OSD_CLUTRAMYCB_Y_SHIFT) | cb, OSD_CLUTRAMYCB);
+ osd_write(sd, (cr << OSD_CLUTRAMCR_CR_SHIFT) | clut_index,
+ OSD_CLUTRAMCR);
+}
+
+static void osd_set_clut_ycbcr(struct osd_state *sd,
+ unsigned char clut_index, unsigned char y,
+ unsigned char cb, unsigned char cr)
+{
+ struct osd_state *osd = sd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->clut_ram[clut_index][0] = y;
+ osd->clut_ram[clut_index][1] = cb;
+ osd->clut_ram[clut_index][2] = cr;
+ _osd_set_clut_ycbcr(sd, clut_index, y, cb, cr);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_rgb_to_ycbcr(const unsigned char rgb[3],
+ unsigned char ycbcr[3])
+{
+ int y, cb, cr;
+ int r = rgb[0];
+ int g = rgb[1];
+ int b = rgb[2];
+ /*
+ * This conversion matrix corresponds to the conversion matrix used
+ * by the OSD to convert RGB values to YCbCr values. All coefficients
+ * have been scaled by a factor of 2^22.
+ */
+ static const int rgb_to_ycbcr[3][3] = {
+ {1250330, 2453618, 490352},
+ {-726093, -1424868, 2150957},
+ {2099836, -1750086, -349759}
+ };
+
+ y = rgb_to_ycbcr[0][0] * r + rgb_to_ycbcr[0][1] * g +
+ rgb_to_ycbcr[0][2] * b;
+ cb = rgb_to_ycbcr[1][0] * r + rgb_to_ycbcr[1][1] * g +
+ rgb_to_ycbcr[1][2] * b;
+ cr = rgb_to_ycbcr[2][0] * r + rgb_to_ycbcr[2][1] * g +
+ rgb_to_ycbcr[2][2] * b;
+
+ /* round and scale */
+ y = ((y + (1 << 21)) >> 22);
+ cb = ((cb + (1 << 21)) >> 22) + 128;
+ cr = ((cr + (1 << 21)) >> 22) + 128;
+
+ /* clip */
+ y = (y < 0) ? 0 : y;
+ y = (y > 255) ? 255 : y;
+ cb = (cb < 0) ? 0 : cb;
+ cb = (cb > 255) ? 255 : cb;
+ cr = (cr < 0) ? 0 : cr;
+ cr = (cr > 255) ? 255 : cr;
+
+ ycbcr[0] = y;
+ ycbcr[1] = cb;
+ ycbcr[2] = cr;
+}
+
+static void osd_set_clut_rgb(struct osd_state *sd, unsigned char clut_index,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ struct osd_state *osd = sd;
+ unsigned char rgb[3], ycbcr[3];
+ unsigned long flags;
+
+ rgb[0] = r;
+ rgb[1] = g;
+ rgb[2] = b;
+ _osd_rgb_to_ycbcr(rgb, ycbcr);
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osd->clut_ram[clut_index][0] = ycbcr[0];
+ osd->clut_ram[clut_index][1] = ycbcr[1];
+ osd->clut_ram[clut_index][2] = ycbcr[2];
+ _osd_set_clut_ycbcr(sd, clut_index, ycbcr[0], ycbcr[1], ycbcr[2]);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static unsigned char osd_get_palette_map(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ unsigned char pixel_value)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned char clut_index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ switch (win->lconfig.pixfmt) {
+ case PIXFMT_1BPP:
+ clut_index = osdwin_state->palette_map[pixel_value & 0x1];
+ break;
+ case PIXFMT_2BPP:
+ clut_index = osdwin_state->palette_map[pixel_value & 0x3];
+ break;
+ case PIXFMT_4BPP:
+ clut_index = osdwin_state->palette_map[pixel_value & 0xf];
+ break;
+ default:
+ clut_index = 0;
+ break;
+ }
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+
+ return clut_index;
+}
+
static void _osd_set_palette_map(struct osd_state *sd,
enum osd_win_layer osdwin,
unsigned char pixel_value,
@@ -240,14 +767,55 @@ static void _osd_set_palette_map(struct osd_state *sd,
osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset);
}
+static void osd_set_palette_map(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ unsigned char pixel_value,
+ unsigned char clut_index)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ switch (win->lconfig.pixfmt) {
+ case PIXFMT_1BPP:
+ osdwin_state->palette_map[pixel_value & 0x1] = clut_index;
+ break;
+ case PIXFMT_2BPP:
+ osdwin_state->palette_map[pixel_value & 0x3] = clut_index;
+ break;
+ case PIXFMT_4BPP:
+ osdwin_state->palette_map[pixel_value & 0xf] = clut_index;
+ break;
+ default:
+ spin_unlock_irqrestore(&osd->lock, flags);
+ return;
+ }
+
+ _osd_set_palette_map(sd, osdwin, pixel_value, clut_index,
+ win->lconfig.pixfmt);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static int osd_get_rec601_attenuation(struct osd_state *sd,
+ enum osd_win_layer osdwin)
+{
+ struct osd_state *osd = sd;
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+
+ return osdwin_state->rec601_attenuation;
+}
+
static void _osd_set_rec601_attenuation(struct osd_state *sd,
enum osd_win_layer osdwin, int enable)
{
switch (osdwin) {
case OSDWIN_OSD0:
- osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
- enable ? OSD_OSDWIN0MD_ATN0E : 0,
- OSD_OSDWIN0MD);
if (sd->vpbe_type = VPBE_VERSION_1)
osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
enable ? OSD_OSDWIN0MD_ATN0E : 0,
@@ -259,9 +827,6 @@ static void _osd_set_rec601_attenuation(struct osd_state *sd,
OSD_EXTMODE);
break;
case OSDWIN_OSD1:
- osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
- enable ? OSD_OSDWIN1MD_ATN1E : 0,
- OSD_OSDWIN1MD);
if (sd->vpbe_type = VPBE_VERSION_1)
osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
enable ? OSD_OSDWIN1MD_ATN1E : 0,
@@ -275,6 +840,35 @@ static void _osd_set_rec601_attenuation(struct osd_state *sd,
}
}
+static void osd_set_rec601_attenuation(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ int enable)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osdwin_state->rec601_attenuation = (enable != 0);
+ if (win->lconfig.pixfmt != PIXFMT_OSD_ATTR)
+ _osd_set_rec601_attenuation(sd, osdwin, enable);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static enum osd_blending_factor
+osd_get_blending_factor(struct osd_state *sd, enum osd_win_layer osdwin)
+{
+ struct osd_state *osd = sd;
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+
+ return osdwin_state->blend;
+}
+
static void _osd_set_blending_factor(struct osd_state *sd,
enum osd_win_layer osdwin,
enum osd_blending_factor blend)
@@ -291,6 +885,26 @@ static void _osd_set_blending_factor(struct osd_state *sd,
}
}
+static void osd_set_blending_factor(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ enum osd_blending_factor blend)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osdwin_state->blend = blend;
+ if (win->lconfig.pixfmt != PIXFMT_OSD_ATTR)
+ _osd_set_blending_factor(sd, osdwin, blend);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
static void _osd_enable_rgb888_pixblend(struct osd_state *sd,
enum osd_win_layer osdwin)
{
@@ -371,6 +985,29 @@ static void _osd_enable_color_key(struct osd_state *sd,
}
}
+static void osd_enable_color_key(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ unsigned colorkey)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osdwin_state->colorkey_blending = 1;
+ osdwin_state->colorkey = colorkey;
+ if (win->lconfig.pixfmt != PIXFMT_OSD_ATTR) {
+ _osd_enable_color_key(sd, osdwin, colorkey,
+ win->lconfig.pixfmt);
+ }
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
static void _osd_disable_color_key(struct osd_state *sd,
enum osd_win_layer osdwin)
{
@@ -384,6 +1021,25 @@ static void _osd_disable_color_key(struct osd_state *sd,
}
}
+static void osd_disable_color_key(struct osd_state *sd,
+ enum osd_win_layer osdwin)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osdwin_state->colorkey_blending = 0;
+ if (win->lconfig.pixfmt != PIXFMT_OSD_ATTR)
+ _osd_disable_color_key(sd, osdwin);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
static void _osd_set_osd_clut(struct osd_state *sd,
enum osd_win_layer osdwin,
enum osd_clut clut)
@@ -404,6 +1060,50 @@ static void _osd_set_osd_clut(struct osd_state *sd,
}
}
+static void osd_set_osd_clut(struct osd_state *sd, enum osd_win_layer osdwin,
+ enum osd_clut clut)
+{
+ struct osd_state *osd = sd;
+ enum osd_layer layer + (osdwin = OSDWIN_OSD0) ? WIN_OSD0 : WIN_OSD1;
+ struct osd_window_state *win = &osd->win[layer];
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ osdwin_state->clut = clut;
+ if (win->lconfig.pixfmt != PIXFMT_OSD_ATTR)
+ _osd_set_osd_clut(sd, osdwin, clut);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static enum osd_clut osd_get_osd_clut(struct osd_state *sd,
+ enum osd_win_layer osdwin)
+{
+ struct osd_state *osd = sd;
+ struct osd_osdwin_state *osdwin_state = &osd->osdwin[osdwin];
+
+ return osdwin_state->clut;
+}
+
+static void osd_get_zoom(struct osd_state *sd, enum osd_layer layer,
+ enum osd_zoom_factor *h_zoom,
+ enum osd_zoom_factor *v_zoom)
+{
+ struct osd_state *osd = sd;
+ struct osd_window_state *win = &osd->win[layer];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ *h_zoom = win->h_zoom;
+ *v_zoom = win->v_zoom;
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
enum osd_zoom_factor h_zoom,
enum osd_zoom_factor v_zoom)
@@ -438,6 +1138,32 @@ static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
}
}
+static void osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
+ enum osd_zoom_factor h_zoom,
+ enum osd_zoom_factor v_zoom)
+{
+ struct osd_state *osd = sd;
+ struct osd_window_state *win = &osd->win[layer];
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ win->h_zoom = h_zoom;
+ win->v_zoom = v_zoom;
+ _osd_set_zoom(sd, layer, h_zoom, v_zoom);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+
+static int osd_layer_is_enabled(struct osd_state *sd, enum osd_layer layer)
+{
+ struct osd_state *osd = sd;
+ struct osd_window_state *win = &osd->win[layer];
+
+ return win->is_enabled;
+}
+
static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
{
switch (layer) {
@@ -480,7 +1206,7 @@ static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
static void _osd_enable_attribute_mode(struct osd_state *sd)
{
/* enable attribute mode for OSD1 */
- osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD);
+ osd_set(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD);
}
static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer)
@@ -793,7 +1519,7 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
case PIXFMT_8BPP:
case PIXFMT_RGB565:
if (osd->vpbe_type = VPBE_VERSION_1)
- bad_config = !is_vid_win(layer);
+ bad_config = !is_osd_win(layer);
break;
case PIXFMT_YCbCrI:
case PIXFMT_YCrCbI:
@@ -892,6 +1618,22 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
return 0;
}
+static int osd_try_layer_config(struct osd_state *sd, enum osd_layer layer,
+ struct osd_layer_config *lconfig)
+{
+ struct osd_state *osd = sd;
+ int reject_config;
+ unsigned long flags;
+
+ spin_lock_irqsave(&osd->lock, flags);
+
+ reject_config = try_layer_config(sd, layer, lconfig);
+
+ spin_unlock_irqrestore(&osd->lock, flags);
+
+ return reject_config;
+}
+
static void _osd_disable_vid_rgb888(struct osd_state *sd)
{
/*
@@ -1512,13 +2254,48 @@ static int osd_initialize(struct osd_state *osd)
}
static const struct vpbe_osd_ops osd_ops = {
+ .set_clut_ycbcr = osd_set_clut_ycbcr,
+ .set_clut_rgb = osd_set_clut_rgb,
+ .set_osd_clut = osd_set_osd_clut,
+ .get_osd_clut = osd_get_osd_clut,
+ .enable_color_key = osd_enable_color_key,
+ .disable_color_key = osd_disable_color_key,
+ .set_blending_factor = osd_set_blending_factor,
+ .get_blending_factor = osd_get_blending_factor,
+ .set_rec601_attenuation = osd_set_rec601_attenuation,
+ .get_rec601_attenuation = osd_get_rec601_attenuation,
+ .set_palette_map = osd_set_palette_map,
+ .get_palette_map = osd_get_palette_map,
+ .set_blink_attribute = osd_set_blink_attribute,
+ .get_blink_attribute = osd_get_blink_attribute,
+ .cursor_enable = osd_cursor_enable,
+ .cursor_disable = osd_cursor_disable,
+ .cursor_is_enabled = osd_cursor_is_enabled,
+ .set_cursor_config = osd_set_cursor_config,
+ .get_cursor_config = osd_get_cursor_config,
+ .set_field_inversion = osd_set_field_inversion,
+ .get_field_inversion = osd_get_field_inversion,
.initialize = osd_initialize,
.request_layer = osd_request_layer,
.release_layer = osd_release_layer,
.enable_layer = osd_enable_layer,
.disable_layer = osd_disable_layer,
+ .layer_is_enabled = osd_layer_is_enabled,
.set_layer_config = osd_set_layer_config,
+ .try_layer_config = osd_try_layer_config,
.get_layer_config = osd_get_layer_config,
+ .set_interpolation_filter = osd_set_interpolation_filter,
+ .get_interpolation_filter = osd_get_interpolation_filter,
+ .set_osd_expansion = osd_set_osd_expansion,
+ .get_osd_expansion = osd_get_osd_expansion,
+ .set_vid_expansion = osd_set_vid_expansion,
+ .get_vid_expansion = osd_get_vid_expansion,
+ .set_zoom = osd_set_zoom,
+ .get_zoom = osd_get_zoom,
+ .set_background = osd_set_background,
+ .get_background = osd_get_background,
+ .set_rom_clut = osd_set_rom_clut,
+ .get_rom_clut = osd_get_rom_clut,
.start_layer = osd_start_layer,
.set_left_margin = osd_set_left_margin,
.set_top_margin = osd_set_top_margin,
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c
index a24fcab..b5178f3 100644
--- a/drivers/media/video/davinci/vpbe_venc.c
+++ b/drivers/media/video/davinci/vpbe_venc.c
@@ -36,6 +36,7 @@
#include <media/davinci/vpbe_venc.h>
#include <media/davinci/vpss.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
#include "vpbe_venc_regs.h"
@@ -49,6 +50,7 @@ struct venc_state {
struct v4l2_subdev sd;
struct venc_callback *callback;
struct venc_platform_data *pdata;
+ enum v4l2_mbus_pixelcode if_params;
struct device *pdev;
u32 output;
v4l2_std_id std;
@@ -445,6 +447,9 @@ static int venc_set_720p60_external(struct v4l2_subdev *sd,
if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0)
return -EINVAL;
+ if (pdata->setup_pinmux(venc->if_params, 0) < 0)
+ return -EINVAL;
+
vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
/* Reset video encoder module */
@@ -533,6 +538,8 @@ static int venc_set_1080i30_external(struct v4l2_subdev *sd,
if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080I30) < 0)
return -EINVAL;
+ if (pdata->setup_pinmux(venc->if_params, 1) < 0)
+ return -EINVAL;
/* setup pinmux */
vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
@@ -646,6 +653,44 @@ static int venc_set_ycc16_modes(struct v4l2_subdev *sd,
return ret;
}
+static int venc_configure_lcd_port(struct v4l2_subdev *sd,
+ struct vpbe_enc_mode_info *mode_info)
+{
+ struct venc_state *venc = to_state(sd);
+ int ret;
+
+ /*
+ * Only if the interface is other than VPBE_ANALOG_TV_IF, we need
+ * execute this
+ */
+ if (venc = NULL)
+ return -EINVAL;
+
+ if (venc->if_params = V4L2_MBUS_FMT_FIXED)
+ return 0;
+
+ if (mode_info = NULL)
+ return -EINVAL;
+
+ switch (venc->if_params) {
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ ret = venc_set_prgb(sd, mode_info);
+ break;
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ ret = venc_set_srgb(sd, mode_info);
+ break;
+ case V4L2_MBUS_FMT_YUYV10_1X20:
+ ret = venc_set_ycc16_modes(sd, mode_info);
+ break;
+ case V4L2_MBUS_FMT_Y10_1X10:
+ ret = venc_set_ycc8_modes(sd, mode_info);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
/*
* venc_set_625p
*
@@ -812,6 +857,10 @@ static long venc_ioctl(struct v4l2_subdev *sd,
unsigned int cmd,
void *arg)
{
+ struct venc_callback *next, *prev, *callback;
+ struct venc_state *venc = to_state(sd);
+ unsigned long flags;
+ unsigned event = 0;
u32 val;
switch (cmd) {
@@ -820,6 +869,41 @@ static long venc_ioctl(struct v4l2_subdev *sd,
*((int *)arg) = ((val & VENC_VSTAT_FIDST) =
VENC_VSTAT_FIDST);
break;
+ case VENC_REG_CALLBACK:
+ spin_lock_irqsave(&venc->lock, flags);
+ callback = (struct venc_callback *)arg;
+ next = venc->callback;
+ venc->callback = callback;
+ callback->next = next;
+ spin_unlock_irqrestore(&venc->lock, flags);
+ break;
+ case VENC_UNREG_CALLBACK:
+ spin_lock_irqsave(&venc->lock, flags);
+ callback = (struct venc_callback *)arg;
+ prev = venc->callback;
+ if (!prev)
+ return -EINVAL;
+ else if (prev = callback)
+ venc->callback = callback->next;
+ else {
+ while (prev->next && (prev->next != callback))
+ prev = prev->next;
+ if (!prev->next)
+ return -EINVAL;
+ else
+ prev->next = callback->next;
+ }
+ spin_unlock_irqrestore(&venc->lock, flags);
+ break;
+ case VENC_INTERRUPT:
+ callback = venc->callback;
+ event = *((unsigned *)arg);
+ while (callback) {
+ if (callback->mask & event)
+ callback->handler(event, callback->arg);
+ callback = callback->next;
+ }
+ break;
default:
v4l2_err(sd, "Wrong IOCTL cmd\n");
break;
diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h
index d7e397a..7f41a04 100644
--- a/include/media/davinci/vpbe_osd.h
+++ b/include/media/davinci/vpbe_osd.h
@@ -325,22 +325,74 @@ struct osd_cursor_state {
struct osd_state;
struct vpbe_osd_ops {
+ void (*set_clut_ycbcr)(struct osd_state *sd,
+ unsigned char clut_index, unsigned char y,
+ unsigned char cb, unsigned char cr);
+ void (*set_clut_rgb)(struct osd_state *sd, unsigned char clut_index,
+ unsigned char r, unsigned char g,
+ unsigned char b);
+ void (*set_osd_clut)(struct osd_state *sd, enum osd_win_layer osdwin,
+ enum osd_clut clut);
+ enum osd_clut (*get_osd_clut)(struct osd_state *sd,
+ enum osd_win_layer osdwin);
+ void (*enable_color_key)(struct osd_state *sd,
+ enum osd_win_layer osdwin, unsigned colorkey);
+ void (*disable_color_key)(struct osd_state *sd,
+ enum osd_win_layer osdwin);
+ void (*set_blending_factor)(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ enum osd_blending_factor blend);
+ enum osd_blending_factor (*get_blending_factor)(struct osd_state *sd,
+ enum osd_win_layer osdwin);
+ void (*set_rec601_attenuation)(struct osd_state *sd,
+ enum osd_win_layer osdwin, int enable);
+ int (*get_rec601_attenuation)(struct osd_state *sd,
+ enum osd_win_layer osdwin);
+ void (*set_palette_map)(struct osd_state *sd,
+ enum osd_win_layer osdwin,
+ unsigned char pixel_value,
+ unsigned char clut_index);
+ unsigned char (*get_palette_map)(struct osd_state *sd,
+ enum osd_win_layer osdwin, unsigned char pixel_value);
+ void (*set_blink_attribute)(struct osd_state *sd, int enable,
+ enum osd_blink_interval blink);
+ void (*get_blink_attribute)(struct osd_state *sd, int *enable,
+ enum osd_blink_interval *blink);
+ void (*cursor_enable)(struct osd_state *sd);
+ void (*cursor_disable)(struct osd_state *sd);
+ int (*cursor_is_enabled)(struct osd_state *sd);
+ void (*set_cursor_config)(struct osd_state *sd,
+ struct osd_cursor_config *cursor);
+ void (*get_cursor_config)(struct osd_state *sd,
+ struct osd_cursor_config *cursor);
+ void (*set_field_inversion)(struct osd_state *sd, int enable);
+ int (*get_field_inversion)(struct osd_state *sd);
int (*initialize)(struct osd_state *sd);
int (*request_layer)(struct osd_state *sd, enum osd_layer layer);
void (*release_layer)(struct osd_state *sd, enum osd_layer layer);
int (*enable_layer)(struct osd_state *sd, enum osd_layer layer,
int otherwin);
void (*disable_layer)(struct osd_state *sd, enum osd_layer layer);
+ int (*layer_is_enabled)(struct osd_state *sd, enum osd_layer layer);
int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer,
struct osd_layer_config *lconfig);
+ int (*try_layer_config)(struct osd_state *sd, enum osd_layer layer,
+ struct osd_layer_config *lconfig);
void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer,
struct osd_layer_config *lconfig);
void (*start_layer)(struct osd_state *sd, enum osd_layer layer,
unsigned long fb_base_phys,
unsigned long cbcr_ofst);
+ void (*set_interpolation_filter)(struct osd_state *sd, int filter);
+ int (*get_interpolation_filter)(struct osd_state *sd);
+ int (*set_osd_expansion)(struct osd_state *sd,
+ enum osd_h_exp_ratio h_exp,
+ enum osd_v_exp_ratio v_exp);
+ void (*get_osd_expansion)(struct osd_state *sd,
+ enum osd_h_exp_ratio *h_exp,
+ enum osd_v_exp_ratio *v_exp);
void (*set_left_margin)(struct osd_state *sd, u32 val);
void (*set_top_margin)(struct osd_state *sd, u32 val);
- void (*set_interpolation_filter)(struct osd_state *sd, int filter);
int (*set_vid_expansion)(struct osd_state *sd,
enum osd_h_exp_ratio h_exp,
enum osd_v_exp_ratio v_exp);
@@ -350,6 +402,16 @@ struct vpbe_osd_ops {
void (*set_zoom)(struct osd_state *sd, enum osd_layer layer,
enum osd_zoom_factor h_zoom,
enum osd_zoom_factor v_zoom);
+ void (*get_zoom)(struct osd_state *sd, enum osd_layer layer,
+ enum osd_zoom_factor *h_zoom,
+ enum osd_zoom_factor *v_zoom);
+ void (*set_background)(struct osd_state *sd, enum osd_clut clut,
+ unsigned char clut_index);
+ void (*get_background)(struct osd_state *sd, enum osd_clut *clut,
+ unsigned char *clut_index);
+ void (*set_rom_clut)(struct osd_state *sd,
+ enum osd_rom_clut rom_clut);
+ enum osd_rom_clut (*get_rom_clut)(struct osd_state *sd);
};
struct osd_state {
diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h
index 6b57334..d9836ef 100644
--- a/include/media/davinci/vpbe_venc.h
+++ b/include/media/davinci/vpbe_venc.h
@@ -27,6 +27,24 @@
#define VENC_FIRST_FIELD BIT(1)
#define VENC_SECOND_FIELD BIT(2)
+/**
+ * struct venc_callback
+ * @next: used internally by the venc driver to maintain a linked list of
+ * callbacks
+ * @mask: a bitmask specifying the venc event(s) for which the
+ * callback will be invoked
+ * @handler: the callback routine
+ * @arg: a null pointer that is passed as the second argument to the callback
+ * routine
+ */
+struct venc_callback {
+ struct venc_callback *next;
+ char *owner;
+ unsigned mask;
+ void (*handler) (unsigned event, void *arg);
+ void *arg;
+};
+
struct venc_platform_data {
enum vpbe_version venc_type;
int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type,
@@ -41,6 +59,9 @@ struct venc_platform_data {
enum venc_ioctls {
VENC_GET_FLD = 1,
+ VENC_REG_CALLBACK,
+ VENC_UNREG_CALLBACK,
+ VENC_INTERRUPT,
};
/* exported functions */
--
1.6.2.4
^ permalink raw reply related
* [RFC PATCH 0/3] fbdev driver for dm644x
From: Manjunath Hadli @ 2011-09-26 13:47 UTC (permalink / raw)
To: linux-fbdev
This patch series adds an fbdev driver for Texas
Instruments Davinci SoC.The display subsystem consists
of OSD and VENC, with OSD supporting 2 RGb planes and
2 video planes.
http://focus.ti.com/general/docs/lit/
getliterature.tsp?literatureNumber=sprue37d&fileType=pdf
A good amount of the OSD and VENC enabling code is
present in the kernel, and this patch series adds the
fbdev interface.
The fbdev driver exports 4 nodes representing each
plane to the user - from fb0 to fb3.
Manjunath Hadli (3):
davinci: vpbe: enable vpbe for fbdev addition
davinci: vpbe: add fbdev driver for dm644x
davinci: vpbe: add build infrastructure for fbdev driver
drivers/media/video/davinci/Kconfig | 13 +
drivers/media/video/davinci/Makefile | 1 +
drivers/media/video/davinci/vpbe_display.c | 6 +
drivers/media/video/davinci/vpbe_fb.c | 2537 +++++++++++++++++++++++++++
drivers/media/video/davinci/vpbe_fb.h | 66 +
drivers/media/video/davinci/vpbe_fb_ioctl.h | 159 ++
drivers/media/video/davinci/vpbe_osd.c | 793 +++++++++-
drivers/media/video/davinci/vpbe_venc.c | 84 +
include/media/davinci/vpbe_osd.h | 64 +-
include/media/davinci/vpbe_venc.h | 21 +
10 files changed, 3735 insertions(+), 9 deletions(-)
create mode 100644 drivers/media/video/davinci/vpbe_fb.c
create mode 100644 drivers/media/video/davinci/vpbe_fb.h
create mode 100644 drivers/media/video/davinci/vpbe_fb_ioctl.h
^ permalink raw reply
* RE: [PATCH] FB: add early fb blank feature.
From: Inki Dae @ 2011-09-26 11:15 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1315544581-16379-1-git-send-email-inki.dae@samsung.com>
Hi, Lars-Peter Clausen.
> > Why do we need a new notifier chain? Can't we introduce a new event for
> > the
> > existing chain?
Yes, it's good point. I will consider a new event as you said. thank you for
your advice. :)
> -----Original Message-----
> From: Inki Dae [mailto:inki.dae@samsung.com]
> Sent: Monday, September 26, 2011 7:37 PM
> To: 'Lars-Peter Clausen'
> Cc: 'FlorianSchandinat@gmx.de'; 'linux-fbdev@vger.kernel.org';
> 'akpm@linux-foundation.org'; 'linux-kernel@vger.kernel.org';
> 'kyungmin.park@samsung.com'
> Subject: RE: [PATCH] FB: add early fb blank feature.
>
> Hi, Lars-Peter Clausen.
>
> Sorry for being late.
>
> > -----Original Message-----
> > From: Lars-Peter Clausen [mailto:lars@metafoo.de]
> > Sent: Thursday, September 15, 2011 8:37 PM
> > To: Inki Dae
> > Cc: FlorianSchandinat@gmx.de; linux-fbdev@vger.kernel.org; akpm@linux-
> > foundation.org; linux-kernel@vger.kernel.org; kyungmin.park@samsung.com
> > Subject: Re: [PATCH] FB: add early fb blank feature.
> >
> > Hi
> >
> > I have a LCD panel with an similar issue, and I think the idea to
> > introduce a
> > early fb blank event is the right solution. I have some comments and
> > questions
> > on this particular implementation though.
> >
> > On 09/09/2011 07:03 AM, Inki Dae wrote:
> > > this patch adds early fb blank feature that this is a callback of
> > > lcd panel driver would be called prior to fb driver's one.
> > > in case of MIPI-DSI based video mode LCD Panel, for lcd power off,
> > > the power off commands should be transferred to lcd panel with display
> > > and mipi-dsi controller enabled because the commands is set to lcd
> panel
> > > at vsync porch period. on the other hand, in opposite case, the
> callback
> > > of fb driver should be called prior to lcd panel driver's one because
> of
> > > same issue. now we could handle call order to fb blank properly.
> > >
> > > the order is as the following:
> > >
> > > at fb_blank function of fbmem.c
> > > -> fb_early_notifier_call_chain()
> > > -> lcd panel driver's early_set_power()
> > > -> info->fbops->fb_blank()
> > > -> fb driver's fb_blank()
> > > -> fb_notifier_call_chain()
> > > -> lcd panel driver's set_power()
> > >
> >
> > I wonder if we really need the lcd_ops early_set_power callback. I can't
> > really
> > imagine a situation where you need to power the LCD down only after the
> > LCD
> > controller has been shutdown.
> >
>
> if fb_blank mode is changed to FB_BLANK_POWERDOWN then display controller
> would be off(clock disable). On the other hand, lcd panel would be still
> on. at this time, you could see some issue like sparkling on lcd panel
> because video clock to be delivered to ldi module of lcd panel was
> disabled.
>
> > So I wonder if we couldn't just have the set_power callback, but listen
> to
> > both
> > events and call set_power for early blank events with code !> > FB_BLANK_UNBLANK
> > and for normal blank events with code = FB_BLANK_UNBLANK?
> >
>
> with this feaure, if a event is FB_BLANK_POWERDOWN then early_set_power()
> callback would be called for lcd panel to be off and if FB_BLANK_UNBLANK
> or FB_BLANK_NORMAL then set_power() callback would be called for lcd panel
> to be on.
>
> > > note that early fb blank mode is valid only if lcd_ops-
> >early_blank_mode
> > is 1.
> > > if the value is 0 then early fb blank callback would be ignored.
> > >
> > > this patch is based on git repository below:
> > > git://github.com/schandinat/linux-2.6.git
> > > branch: fbdev-next
> > > commit-id: a67472ad1ae040f073e45048cbc5a01195f2e3f5
> > >
> > > Signed-off-by: Inki Dae <inki.dae@samsung.com>
> > > Signed-off-by: KyungMin Park <kyungmin.park@samsung.com>
> > > ---
> > > drivers/video/backlight/lcd.c | 77
> > ++++++++++++++++++++++++++++++++++++++--
> > > drivers/video/fb_notify.c | 31 ++++++++++++++++
> > > drivers/video/fbmem.c | 25 +++++++------
> > > include/linux/fb.h | 4 ++
> > > include/linux/lcd.h | 61 ++++++++++++++++++++++++--------
> >
> > In my opinion this should be split into two patches, one adding the
> early
> > blank
> > event, one adding support for it to the LCD framework.
> >
>
> You are right. this patch should be split into two patches. Thank you.
>
> > > 5 files changed, 167 insertions(+), 31 deletions(-)
> > >
> > > [...]
> > > diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c
> > > index 8c02038..3930c7c 100644
> > > --- a/drivers/video/fb_notify.c
> > > +++ b/drivers/video/fb_notify.c
> > > @@ -13,9 +13,20 @@
> > > #include <linux/fb.h>
> > > #include <linux/notifier.h>
> > >
> > > +static BLOCKING_NOTIFIER_HEAD(fb_early_notifier_list);
> > > static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
> > >
> > > /**
> > > + * fb_register_early_client - register a client early notifier
> > > + * @nb: notifier block to callback on events
> > > + */
> > > +int fb_register_early_client(struct notifier_block *nb)
> > > +{
> > > + return blocking_notifier_chain_register(&fb_early_notifier_list,
> > nb);
> > > +}
> > > +EXPORT_SYMBOL(fb_register_early_client);
> > > +
> >
> > Why do we need a new notifier chain? Can't we introduce a new event for
> > the
> > existing chain?
> >
>
> Suppose that we have only fb_notifier_list. Once lcd_device_register() is
> called by lcd panel driver, existing two notifiers would be added
> fb_notifier_list and when fb_blank is called by user process, some
> callback registered to the fb_notifier_list would be called two times, one
> is set_power() and another one is early_set_power(). as you know, this is
> not the thing we want. If there is any missing point, please give me your
> comment.
>
>
> > > +/**
> > > * fb_register_client - register a client notifier
> > > * @nb: notifier block to callback on events
> > > */
> > > @@ -26,6 +37,16 @@ int fb_register_client(struct notifier_block *nb)
> > > EXPORT_SYMBOL(fb_register_client);
> > >
> > > /**
> > > + * fb_unregister_early_client - unregister a client early
> notifier
> > > + * @nb: notifier block to callback on events
> > > + */
> > > +int fb_unregister_early_client(struct notifier_block *nb)
> > > +{
> > > + return blocking_notifier_chain_unregister(&fb_early_notifier_list,
> > nb);
> > > +}
> > > +EXPORT_SYMBOL(fb_unregister_early_client);
> > > +
> > > +/**
> > > * fb_unregister_client - unregister a client notifier
> > > * @nb: notifier block to callback on events
> > > */
> > > @@ -36,6 +57,16 @@ int fb_unregister_client(struct notifier_block *nb)
> > > EXPORT_SYMBOL(fb_unregister_client);
> > >
> > > /**
> > > + * fb_early_notifier_call_chain - early notify clients of fb_events
> > > + *
> > > + */
> > > +int fb_early_notifier_call_chain(unsigned long val, void *v)
> > > +{
> > > + return blocking_notifier_call_chain(&fb_early_notifier_list, val,
> > v);
> > > +}
> > > +EXPORT_SYMBOL_GPL(fb_early_notifier_call_chain);
> > > +
> > > +/**
> > > * fb_notifier_call_chain - notify clients of fb_events
> > > *
> > > */
> > > diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
> > > index ad93629..cf22516 100644
> > > --- a/drivers/video/fbmem.c
> > > +++ b/drivers/video/fbmem.c
> > > @@ -1031,24 +1031,25 @@ fb_set_var(struct fb_info *info, struct
> > fb_var_screeninfo *var)
> > >
> > > int
> > > fb_blank(struct fb_info *info, int blank)
> > > -{
> > > - int ret = -EINVAL;
> > > +{
> > > + struct fb_event event;
> > > + int ret = -EINVAL;
> > >
> > > - if (blank > FB_BLANK_POWERDOWN)
> > > - blank = FB_BLANK_POWERDOWN;
> > > + if (blank > FB_BLANK_POWERDOWN)
> > > + blank = FB_BLANK_POWERDOWN;
> > >
> > > - if (info->fbops->fb_blank)
> > > - ret = info->fbops->fb_blank(blank, info);
> > > + event.info = info;
> > > + event.data = ␣
> > >
> > > - if (!ret) {
> > > - struct fb_event event;
> > > + fb_early_notifier_call_chain(FB_EVENT_BLANK, &event);
> > >
> > > - event.info = info;
> > > - event.data = ␣
> > > + if (info->fbops->fb_blank)
> > > + ret = info->fbops->fb_blank(blank, info);
> >
> > I think we have to handle the case where the fb_blank callback fails and
> > should
> > somehow revert the effects of the early blank event.
> >
>
> You are right. it should be reverted with fail. thank you.
>
> >
> > > +
> > > + if (!ret)
> > > fb_notifier_call_chain(FB_EVENT_BLANK, &event);
> > > - }
> > >
> >
> >
> >
> > > - return ret;
> > > + return ret;
> > > }
> > >
> > > static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
> > > diff --git a/include/linux/fb.h b/include/linux/fb.h
> > > index 1d6836c..1d7d995 100644
> > > --- a/include/linux/fb.h
> > > +++ b/include/linux/fb.h
> > > @@ -562,6 +562,10 @@ struct fb_blit_caps {
> > > u32 flags;
> > > };
> > >
> > > +extern int fb_register_early_client(struct notifier_block *nb);
> > > +extern int fb_unregister_early_client(struct notifier_block *nb);
> > > +extern int fb_early_notifier_call_chain(unsigned long val, void *v);
> > > +
> > > extern int fb_register_client(struct notifier_block *nb);
> > > extern int fb_unregister_client(struct notifier_block *nb);
> > > extern int fb_notifier_call_chain(unsigned long val, void *v);
> > > diff --git a/include/linux/lcd.h b/include/linux/lcd.h
> > > index 8877123..930d1cc 100644
> > > --- a/include/linux/lcd.h
> > > +++ b/include/linux/lcd.h
> > > @@ -37,10 +37,21 @@ struct lcd_properties {
> > > };
> > >
> > > struct lcd_ops {
> > > - /* Get the LCD panel power status (0: full on, 1..3: controller
> > > - power on, flat panel power off, 4: full off), see FB_BLANK_XXX */
> > > + /*
> > > + * Get the LCD panel power status (0: full on, 1..3: controller
> > > + * power on, flat panel power off, 4: full off), see FB_BLANK_XXX
> > > + */
> > > int (*get_power)(struct lcd_device *);
> > > - /* Enable or disable power to the LCD (0: on; 4: off, see
> > FB_BLANK_XXX) */
> > > + /*
> > > + * Get the current contrast setting (0-max_contrast) and
> >
> > ???
> >
>
> Ah, I missed it. this is a comment wrong so I will remove it. thank you.
>
> > > + * Enable or disable power to the LCD (0: on; 4: off, see
> > FB_BLANK_XXX)
> > > + * this callback would be called proir to fb driver's fb_blank
> > callback.
> > > + */
> > > + int (*early_set_power)(struct lcd_device *, int power);
> > > + /*
> > > + * Get the current contrast setting (0-max_contrast)
> > > + * Enable or disable power to the LCD (0: on; 4: off, see
> > FB_BLANK_XXX)
> > > + */
> > > int (*set_power)(struct lcd_device *, int power);
> > > /* Get the current contrast setting (0-max_contrast) */
> > > int (*get_contrast)(struct lcd_device *);
> > > @@ -48,21 +59,35 @@ struct lcd_ops {
> > > int (*set_contrast)(struct lcd_device *, int contrast);
> > > /* Set LCD panel mode (resolutions ...) */
> > > int (*set_mode)(struct lcd_device *, struct fb_videomode *);
> > > - /* Check if given framebuffer device is the one LCD is bound to;
> > > - return 0 if not, !=0 if it is. If NULL, lcd always matches the
fb.
> > */
> > > + /*
> > > + * Check if given framebuffer device is the one LCD is bound to;
> > > + * return 0 if not, !=0 if it is. If NULL, lcd always matches the
> > fb.
> > > + */
> > > int (*check_fb)(struct lcd_device *, struct fb_info *);
> > > +
> > > + /*
> > > + * indicate whether enabling early blank mode or not.
> > > + * (0: disable; 1: enable);
> > > + * if enabled, lcd blank callback would be called prior
> > > + * to fb blank callback.
> > > + */
> > > + unsigned int early_blank_mode;
> >
> > I think it should be sufficient to check early_set_power for NULL
> instead
> > of
> > adding this additional flag.
> >
>
> You are right. I will modify it. thank you.
>
> > > };
> > >
> > > struct lcd_device {
> > > struct lcd_properties props;
> > > - /* This protects the 'ops' field. If 'ops' is NULL, the driver that
> > > - registered this device has been unloaded, and if
> > class_get_devdata()
> > > - points to something in the body of that driver, it is also
> > invalid. */
> > > + /*
> > > + * This protects the 'ops' field. If 'ops' is NULL, the driver that
> > > + * registered this device has been unloaded, and if
> > class_get_devdata()
> > > + * points to something in the body of that driver, it is also
> > invalid.
> > > + */
> > > struct mutex ops_lock;
> > > /* If this is NULL, the backing module is unloaded */
> > > struct lcd_ops *ops;
> > > /* Serialise access to set_power method */
> > > struct mutex update_lock;
> > > + /* The framebuffer early notifier block */
> > > + struct notifier_block fb_early_notif;
> > > /* The framebuffer notifier block */
> > > struct notifier_block fb_notif;
> > >
> > > @@ -72,16 +97,22 @@ struct lcd_device {
> > > struct lcd_platform_data {
> > > /* reset lcd panel device. */
> > > int (*reset)(struct lcd_device *ld);
> > > - /* on or off to lcd panel. if 'enable' is 0 then
> > > - lcd power off and 1, lcd power on. */
> > > + /*
> > > + * on or off to lcd panel. if 'enable' is 0 then
> > > + * lcd power off and 1, lcd power on.
> > > + */
> > > int (*power_on)(struct lcd_device *ld, int enable);
> > >
> > > - /* it indicates whether lcd panel was enabled
> > > - from bootloader or not. */
> > > + /*
> > > + * it indicates whether lcd panel was enabled
> > > + * from bootloader or not.
> > > + */
> > > int lcd_enabled;
> > > - /* it means delay for stable time when it becomes low to high
> > > - or high to low that is dependent on whether reset gpio is
> > > - low active or high active. */
> > > + /*
> > > + * it means delay for stable time when it becomes low to high
> > > + * or high to low that is dependent on whether reset gpio is
> > > + * low active or high active.
> > > + */
> >
> > The formatting cleanup patches should go into a separate patch.
>
> Ok, get it. and I will re-send this patch. thank you again. :)
^ permalink raw reply
* RE: [PATCH] FB: add early fb blank feature.
From: Inki Dae @ 2011-09-26 10:36 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1315544581-16379-1-git-send-email-inki.dae@samsung.com>
Hi, Lars-Peter Clausen.
Sorry for being late.
> -----Original Message-----
> From: Lars-Peter Clausen [mailto:lars@metafoo.de]
> Sent: Thursday, September 15, 2011 8:37 PM
> To: Inki Dae
> Cc: FlorianSchandinat@gmx.de; linux-fbdev@vger.kernel.org; akpm@linux-
> foundation.org; linux-kernel@vger.kernel.org; kyungmin.park@samsung.com
> Subject: Re: [PATCH] FB: add early fb blank feature.
>
> Hi
>
> I have a LCD panel with an similar issue, and I think the idea to
> introduce a
> early fb blank event is the right solution. I have some comments and
> questions
> on this particular implementation though.
>
> On 09/09/2011 07:03 AM, Inki Dae wrote:
> > this patch adds early fb blank feature that this is a callback of
> > lcd panel driver would be called prior to fb driver's one.
> > in case of MIPI-DSI based video mode LCD Panel, for lcd power off,
> > the power off commands should be transferred to lcd panel with display
> > and mipi-dsi controller enabled because the commands is set to lcd panel
> > at vsync porch period. on the other hand, in opposite case, the callback
> > of fb driver should be called prior to lcd panel driver's one because of
> > same issue. now we could handle call order to fb blank properly.
> >
> > the order is as the following:
> >
> > at fb_blank function of fbmem.c
> > -> fb_early_notifier_call_chain()
> > -> lcd panel driver's early_set_power()
> > -> info->fbops->fb_blank()
> > -> fb driver's fb_blank()
> > -> fb_notifier_call_chain()
> > -> lcd panel driver's set_power()
> >
>
> I wonder if we really need the lcd_ops early_set_power callback. I can't
> really
> imagine a situation where you need to power the LCD down only after the
> LCD
> controller has been shutdown.
>
if fb_blank mode is changed to FB_BLANK_POWERDOWN then display controller
would be off(clock disable). On the other hand, lcd panel would be still on.
at this time, you could see some issue like sparkling on lcd panel because
video clock to be delivered to ldi module of lcd panel was disabled.
> So I wonder if we couldn't just have the set_power callback, but listen to
> both
> events and call set_power for early blank events with code !> FB_BLANK_UNBLANK
> and for normal blank events with code = FB_BLANK_UNBLANK?
>
with this feaure, if a event is FB_BLANK_POWERDOWN then early_set_power()
callback would be called for lcd panel to be off and if FB_BLANK_UNBLANK or
FB_BLANK_NORMAL then set_power() callback would be called for lcd panel to
be on.
> > note that early fb blank mode is valid only if lcd_ops->early_blank_mode
> is 1.
> > if the value is 0 then early fb blank callback would be ignored.
> >
> > this patch is based on git repository below:
> > git://github.com/schandinat/linux-2.6.git
> > branch: fbdev-next
> > commit-id: a67472ad1ae040f073e45048cbc5a01195f2e3f5
> >
> > Signed-off-by: Inki Dae <inki.dae@samsung.com>
> > Signed-off-by: KyungMin Park <kyungmin.park@samsung.com>
> > ---
> > drivers/video/backlight/lcd.c | 77
> ++++++++++++++++++++++++++++++++++++++--
> > drivers/video/fb_notify.c | 31 ++++++++++++++++
> > drivers/video/fbmem.c | 25 +++++++------
> > include/linux/fb.h | 4 ++
> > include/linux/lcd.h | 61 ++++++++++++++++++++++++--------
>
> In my opinion this should be split into two patches, one adding the early
> blank
> event, one adding support for it to the LCD framework.
>
You are right. this patch should be split into two patches. Thank you.
> > 5 files changed, 167 insertions(+), 31 deletions(-)
> >
> > [...]
> > diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c
> > index 8c02038..3930c7c 100644
> > --- a/drivers/video/fb_notify.c
> > +++ b/drivers/video/fb_notify.c
> > @@ -13,9 +13,20 @@
> > #include <linux/fb.h>
> > #include <linux/notifier.h>
> >
> > +static BLOCKING_NOTIFIER_HEAD(fb_early_notifier_list);
> > static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
> >
> > /**
> > + * fb_register_early_client - register a client early notifier
> > + * @nb: notifier block to callback on events
> > + */
> > +int fb_register_early_client(struct notifier_block *nb)
> > +{
> > + return blocking_notifier_chain_register(&fb_early_notifier_list,
> nb);
> > +}
> > +EXPORT_SYMBOL(fb_register_early_client);
> > +
>
> Why do we need a new notifier chain? Can't we introduce a new event for
> the
> existing chain?
>
Suppose that we have only fb_notifier_list. Once lcd_device_register() is
called by lcd panel driver, existing two notifiers would be added
fb_notifier_list and when fb_blank is called by user process, some callback
registered to the fb_notifier_list would be called two times, one is
set_power() and another one is early_set_power(). as you know, this is not
the thing we want. If there is any missing point, please give me your
comment.
> > +/**
> > * fb_register_client - register a client notifier
> > * @nb: notifier block to callback on events
> > */
> > @@ -26,6 +37,16 @@ int fb_register_client(struct notifier_block *nb)
> > EXPORT_SYMBOL(fb_register_client);
> >
> > /**
> > + * fb_unregister_early_client - unregister a client early notifier
> > + * @nb: notifier block to callback on events
> > + */
> > +int fb_unregister_early_client(struct notifier_block *nb)
> > +{
> > + return blocking_notifier_chain_unregister(&fb_early_notifier_list,
> nb);
> > +}
> > +EXPORT_SYMBOL(fb_unregister_early_client);
> > +
> > +/**
> > * fb_unregister_client - unregister a client notifier
> > * @nb: notifier block to callback on events
> > */
> > @@ -36,6 +57,16 @@ int fb_unregister_client(struct notifier_block *nb)
> > EXPORT_SYMBOL(fb_unregister_client);
> >
> > /**
> > + * fb_early_notifier_call_chain - early notify clients of fb_events
> > + *
> > + */
> > +int fb_early_notifier_call_chain(unsigned long val, void *v)
> > +{
> > + return blocking_notifier_call_chain(&fb_early_notifier_list, val,
> v);
> > +}
> > +EXPORT_SYMBOL_GPL(fb_early_notifier_call_chain);
> > +
> > +/**
> > * fb_notifier_call_chain - notify clients of fb_events
> > *
> > */
> > diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
> > index ad93629..cf22516 100644
> > --- a/drivers/video/fbmem.c
> > +++ b/drivers/video/fbmem.c
> > @@ -1031,24 +1031,25 @@ fb_set_var(struct fb_info *info, struct
> fb_var_screeninfo *var)
> >
> > int
> > fb_blank(struct fb_info *info, int blank)
> > -{
> > - int ret = -EINVAL;
> > +{
> > + struct fb_event event;
> > + int ret = -EINVAL;
> >
> > - if (blank > FB_BLANK_POWERDOWN)
> > - blank = FB_BLANK_POWERDOWN;
> > + if (blank > FB_BLANK_POWERDOWN)
> > + blank = FB_BLANK_POWERDOWN;
> >
> > - if (info->fbops->fb_blank)
> > - ret = info->fbops->fb_blank(blank, info);
> > + event.info = info;
> > + event.data = ␣
> >
> > - if (!ret) {
> > - struct fb_event event;
> > + fb_early_notifier_call_chain(FB_EVENT_BLANK, &event);
> >
> > - event.info = info;
> > - event.data = ␣
> > + if (info->fbops->fb_blank)
> > + ret = info->fbops->fb_blank(blank, info);
>
> I think we have to handle the case where the fb_blank callback fails and
> should
> somehow revert the effects of the early blank event.
>
You are right. it should be reverted with fail. thank you.
>
> > +
> > + if (!ret)
> > fb_notifier_call_chain(FB_EVENT_BLANK, &event);
> > - }
> >
>
>
>
> > - return ret;
> > + return ret;
> > }
> >
> > static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
> > diff --git a/include/linux/fb.h b/include/linux/fb.h
> > index 1d6836c..1d7d995 100644
> > --- a/include/linux/fb.h
> > +++ b/include/linux/fb.h
> > @@ -562,6 +562,10 @@ struct fb_blit_caps {
> > u32 flags;
> > };
> >
> > +extern int fb_register_early_client(struct notifier_block *nb);
> > +extern int fb_unregister_early_client(struct notifier_block *nb);
> > +extern int fb_early_notifier_call_chain(unsigned long val, void *v);
> > +
> > extern int fb_register_client(struct notifier_block *nb);
> > extern int fb_unregister_client(struct notifier_block *nb);
> > extern int fb_notifier_call_chain(unsigned long val, void *v);
> > diff --git a/include/linux/lcd.h b/include/linux/lcd.h
> > index 8877123..930d1cc 100644
> > --- a/include/linux/lcd.h
> > +++ b/include/linux/lcd.h
> > @@ -37,10 +37,21 @@ struct lcd_properties {
> > };
> >
> > struct lcd_ops {
> > - /* Get the LCD panel power status (0: full on, 1..3: controller
> > - power on, flat panel power off, 4: full off), see FB_BLANK_XXX */
> > + /*
> > + * Get the LCD panel power status (0: full on, 1..3: controller
> > + * power on, flat panel power off, 4: full off), see FB_BLANK_XXX
> > + */
> > int (*get_power)(struct lcd_device *);
> > - /* Enable or disable power to the LCD (0: on; 4: off, see
> FB_BLANK_XXX) */
> > + /*
> > + * Get the current contrast setting (0-max_contrast) and
>
> ???
>
Ah, I missed it. this is a comment wrong so I will remove it. thank you.
> > + * Enable or disable power to the LCD (0: on; 4: off, see
> FB_BLANK_XXX)
> > + * this callback would be called proir to fb driver's fb_blank
> callback.
> > + */
> > + int (*early_set_power)(struct lcd_device *, int power);
> > + /*
> > + * Get the current contrast setting (0-max_contrast)
> > + * Enable or disable power to the LCD (0: on; 4: off, see
> FB_BLANK_XXX)
> > + */
> > int (*set_power)(struct lcd_device *, int power);
> > /* Get the current contrast setting (0-max_contrast) */
> > int (*get_contrast)(struct lcd_device *);
> > @@ -48,21 +59,35 @@ struct lcd_ops {
> > int (*set_contrast)(struct lcd_device *, int contrast);
> > /* Set LCD panel mode (resolutions ...) */
> > int (*set_mode)(struct lcd_device *, struct fb_videomode *);
> > - /* Check if given framebuffer device is the one LCD is bound to;
> > - return 0 if not, !=0 if it is. If NULL, lcd always matches the
fb.
> */
> > + /*
> > + * Check if given framebuffer device is the one LCD is bound to;
> > + * return 0 if not, !=0 if it is. If NULL, lcd always matches the
> fb.
> > + */
> > int (*check_fb)(struct lcd_device *, struct fb_info *);
> > +
> > + /*
> > + * indicate whether enabling early blank mode or not.
> > + * (0: disable; 1: enable);
> > + * if enabled, lcd blank callback would be called prior
> > + * to fb blank callback.
> > + */
> > + unsigned int early_blank_mode;
>
> I think it should be sufficient to check early_set_power for NULL instead
> of
> adding this additional flag.
>
You are right. I will modify it. thank you.
> > };
> >
> > struct lcd_device {
> > struct lcd_properties props;
> > - /* This protects the 'ops' field. If 'ops' is NULL, the driver that
> > - registered this device has been unloaded, and if
> class_get_devdata()
> > - points to something in the body of that driver, it is also
> invalid. */
> > + /*
> > + * This protects the 'ops' field. If 'ops' is NULL, the driver that
> > + * registered this device has been unloaded, and if
> class_get_devdata()
> > + * points to something in the body of that driver, it is also
> invalid.
> > + */
> > struct mutex ops_lock;
> > /* If this is NULL, the backing module is unloaded */
> > struct lcd_ops *ops;
> > /* Serialise access to set_power method */
> > struct mutex update_lock;
> > + /* The framebuffer early notifier block */
> > + struct notifier_block fb_early_notif;
> > /* The framebuffer notifier block */
> > struct notifier_block fb_notif;
> >
> > @@ -72,16 +97,22 @@ struct lcd_device {
> > struct lcd_platform_data {
> > /* reset lcd panel device. */
> > int (*reset)(struct lcd_device *ld);
> > - /* on or off to lcd panel. if 'enable' is 0 then
> > - lcd power off and 1, lcd power on. */
> > + /*
> > + * on or off to lcd panel. if 'enable' is 0 then
> > + * lcd power off and 1, lcd power on.
> > + */
> > int (*power_on)(struct lcd_device *ld, int enable);
> >
> > - /* it indicates whether lcd panel was enabled
> > - from bootloader or not. */
> > + /*
> > + * it indicates whether lcd panel was enabled
> > + * from bootloader or not.
> > + */
> > int lcd_enabled;
> > - /* it means delay for stable time when it becomes low to high
> > - or high to low that is dependent on whether reset gpio is
> > - low active or high active. */
> > + /*
> > + * it means delay for stable time when it becomes low to high
> > + * or high to low that is dependent on whether reset gpio is
> > + * low active or high active.
> > + */
>
> The formatting cleanup patches should go into a separate patch.
Ok, get it. and I will re-send this patch. thank you again. :)
^ permalink raw reply
* KVÓTA ALERT
From: WEB ADMIN @ 2011-09-25 22:45 UTC (permalink / raw)
To: linux-fbdev
Vaše poštovní schránka storage byl překročen limit, dokud se
znovu potvrdili svou poštovní schránku, kterou nelze odesílat nebo
přijímat e-maily.
Chcete-li znovu ověřit své poštovní schránky laskavě
klikněte na odkaz níže odkaz
https://docs.google.com/spreadsheet/viewform?formkeyÞ1RV3JoclNoTkhEWDVmejYyNzVZYUE6MQ
díky
správce systému
^ permalink raw reply
* =?iso-8859-2?Q?Varov=E1n=ED_Upozorně
From: WEB ADMIN @ 2011-09-24 6:29 UTC (permalink / raw)
To: linux-fbdev
Vaše poštovní schránka překročila To kvót / Limit podle
nastavení na správce a možná nebudete moci přijímat ani odesílat nové
mailů Dokud nové ověření.
Chcete-li znovu ověřit ZDE
https://docs.google.com/spreadsheet/viewform?formkey=dGE2ak5fSGpkMmw4SlJBcjVsazdyYnc6MQ
děkuji
LocalHost
10.77.938.009
^ permalink raw reply
* [PATCH] mx3fb: fix NULL pointer dereference in screen blanking.
From: Michael Thalmeier @ 2011-09-23 12:09 UTC (permalink / raw)
To: Florian Tobias Schandinat; +Cc: linux-fbdev, linux-kernel
From: Wolfram Stering <wolfram.stering@hale.at>
When blanking an already blanked framebuffer, a kernel NULL pointer
dereference occurred, because mx3fb driver handles all kinds of screen
blanking (normal, vsync suspend, powerdown) in the same way.
Certain programs (Xorg X11 server) first do a normal blank, followed by
a powerdown blank, which triggered the bug.
Add an additional safeguard and make sdc_disable_channel() safe against
multiple calls independent of other logic.
Signed-off-by: Michael Thalmeier <michael.thalmeier@hale.at>
---
drivers/video/mx3fb.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 7e3a490..286be99 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -382,6 +382,9 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
uint32_t enabled;
unsigned long flags;
+ if (mx3_fbi->txd = NULL)
+ return;
+
spin_lock_irqsave(&mx3fb->lock, flags);
enabled = sdc_fb_uninit(mx3_fbi);
@@ -986,9 +989,19 @@ static void __blank(int blank, struct fb_info *fbi)
{
struct mx3fb_info *mx3_fbi = fbi->par;
struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
+ int was_blank = mx3_fbi->blank;
mx3_fbi->blank = blank;
+ /* Attention!
+ * Do not call sdc_disable_channel() for a channel that is disabled
+ * already! This will result in a kernel NULL pointer dereference
+ * (mx3_fbi->txd is NULL). Hide the fact, that all blank modes are
+ * handled equally by this driver.
+ */
+ if (blank > FB_BLANK_UNBLANK && was_blank > FB_BLANK_UNBLANK)
+ return;
+
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_VSYNC_SUSPEND:
--
1.7.6.2
--
Scanned by MailScanner.
^ permalink raw reply related
* Re: [PATCH] gma500: gtt based hardware scrolling console
From: Geert Uytterhoeven @ 2011-09-23 5:17 UTC (permalink / raw)
To: Alan Cox; +Cc: greg, linux-kernel, Linux Fbdev development list
In-Reply-To: <20110922212146.609065b1@lxorguk.ukuu.org.uk>
On Thu, Sep 22, 2011 at 22:21, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>> > + info->fix.ywrapstep = gtt_roll;
>>
>> Do you really want to set this? I didn't see any other wrapping
>> support in your patch.
>> However, I guess you can implement wrapping support using the same
>> mapping trick?
>
> It is actually wrapping - it writes the low pages back below the high
> ones so it works the GTT as a circular buffer - or am I misunderstanding
> this.
Then it should not set ypanstep to a non-zero value, and set/handle the other
various *YWRAP flags, to communicate with the frame buffer console driver.
Panning is moving inside a virtual screen bigger than the visible screen size.
> One thing I wasn't sure of on the fb side. If I've got a display width
> that is annoying and can't fit on a 4Kbyte stride am I right in thinking
> I can set this to say 8 and use a 512 byte stride and still get
> acceleration for the usual font choice ?
Yep, that should work. The console code can use ywrap resp. ypan if the
font height is a multiple of ywrapstep resp. ypanstep.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH] gma500: gtt based hardware scrolling console
From: Alan Cox @ 2011-09-22 20:21 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: greg, linux-kernel, Linux Fbdev development list
In-Reply-To: <CAMuHMdWBz9+TCBUbaOY3HRv=khiDHkRCKdx5e53HCen54RUBVw@mail.gmail.com>
> > + info->fix.ywrapstep = gtt_roll;
>
> Do you really want to set this? I didn't see any other wrapping
> support in your patch.
> However, I guess you can implement wrapping support using the same
> mapping trick?
It is actually wrapping - it writes the low pages back below the high
ones so it works the GTT as a circular buffer - or am I misunderstanding
this.
One thing I wasn't sure of on the fb side. If I've got a display width
that is annoying and can't fit on a 4Kbyte stride am I right in thinking
I can set this to say 8 and use a 512 byte stride and still get
acceleration for the usual font choice ?
Alan
^ permalink raw reply
* Re: [PATCH] gma500: gtt based hardware scrolling console
From: Geert Uytterhoeven @ 2011-09-22 19:40 UTC (permalink / raw)
To: Alan Cox; +Cc: greg, linux-kernel, Linux Fbdev development list
In-Reply-To: <20110922184316.25068.54702.stgit@localhost.localdomain>
Hi Alan,
On Thu, Sep 22, 2011 at 20:43, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
diff --git a/drivers/staging/gma500/framebuffer.c
b/drivers/staging/gma500/framebuffer.c
index 7748331..3f39a37 100644
--- a/drivers/staging/gma500/framebuffer.c
+++ b/drivers/staging/gma500/framebuffer.c
> @@ -416,6 +473,8 @@ static int psbfb_create(struct psb_fbdev *fbdev,
>
> info->fix.smem_start = dev->mode_config.fb_base;
> info->fix.smem_len = size;
> + info->fix.ywrapstep = gtt_roll;
Do you really want to set this? I didn't see any other wrapping
support in your patch.
However, I guess you can implement wrapping support using the same
mapping trick?
> + info->fix.ypanstep = gtt_roll;
>
> if (backing->stolen) {
> /* Accessed stolen memory directly */
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH 49/55] video: irq: Remove IRQF_DISABLED
From: Yong Zhang @ 2011-09-22 8:59 UTC (permalink / raw)
To: linux-kernel, linux-arch
Cc: tglx, yong.zhang0, Florian Tobias Schandinat, David Brown,
Daniel Walker, Bryan Huntsman, Wan ZongShun, Tomi Valkeinen,
Geoff Levand, Ben Dooks, Kukjin Kim, Anatolij Gustschin,
Paul Gortmaker, Andrew Morton, Laurent Pinchart, Jiri Kosina,
Archit Taneja, linux-fbdev, linux-arm-msm, linux-arm-kernel,
linux-omap, linuxppc-dev, cbe-oss-dev
In-Reply-To: <1316681962-8217-1-git-send-email-yong.zhang0@gmail.com>
Since commit [e58aa3d2: genirq: Run irq handlers with interrupts disabled],
We run all interrupt handlers with interrupts disabled
and we even check and yell when an interrupt handler
returns with interrupts enabled (see commit [b738a50a:
genirq: Warn when handler enables interrupts]).
So now this flag is a NOOP and can be removed.
Signed-off-by: Yong Zhang <yong.zhang0@gmail.com>
Acked-by: David Brown <davidb@codeaurora.org>
---
drivers/video/au1200fb.c | 2 +-
drivers/video/bf54x-lq043fb.c | 2 +-
drivers/video/bfin-lq035q1-fb.c | 2 +-
drivers/video/bfin-t350mcqb-fb.c | 2 +-
drivers/video/bfin_adv7393fb.c | 2 +-
drivers/video/mb862xx/mb862xxfbdrv.c | 4 ++--
drivers/video/msm/mddi.c | 2 +-
drivers/video/msm/mdp.c | 2 +-
drivers/video/nuc900fb.c | 2 +-
drivers/video/omap2/displays/panel-taal.c | 2 +-
drivers/video/ps3fb.c | 2 +-
drivers/video/pxa3xx-gcu.c | 2 +-
drivers/video/pxafb.c | 2 +-
drivers/video/s3c2410fb.c | 2 +-
drivers/video/sa1100fb.c | 3 +--
drivers/video/sh_mobile_lcdcfb.c | 2 +-
drivers/video/tmiofb.c | 2 +-
drivers/video/vt8500lcdfb.c | 2 +-
18 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index a19a40e..7200559 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1673,7 +1673,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev)
/* Now hook interrupt too */
irq = platform_get_irq(dev, 0);
ret = request_irq(irq, au1200fb_handle_irq,
- IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev);
+ IRQF_SHARED, "lcd", (void *)dev);
if (ret) {
print_err("fail to request interrupt line %d (err: %d)",
irq, ret);
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 2464b91..56720fb 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -633,7 +633,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
goto out7;
}
- if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED,
+ if (request_irq(info->irq, bfin_bf54x_irq_error, 0,
"PPI ERROR", info) < 0) {
printk(KERN_ERR DRIVER_NAME
": unable to request PPI ERROR IRQ\n");
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
index 23b6c4b..c633068 100644
--- a/drivers/video/bfin-lq035q1-fb.c
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -695,7 +695,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
goto out7;
}
- ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED,
+ ret = request_irq(info->irq, bfin_lq035q1_irq_error, 0,
DRIVER_NAME" PPI ERROR", info);
if (ret < 0) {
dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n");
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index d8de29f..d5e1267 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -529,7 +529,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
goto out7;
}
- ret = request_irq(info->irq, bfin_t350mcqb_irq_error, IRQF_DISABLED,
+ ret = request_irq(info->irq, bfin_t350mcqb_irq_error, 0,
"PPI ERROR", info);
if (ret < 0) {
printk(KERN_ERR DRIVER_NAME
diff --git a/drivers/video/bfin_adv7393fb.c b/drivers/video/bfin_adv7393fb.c
index 8486f54..811dd7f 100644
--- a/drivers/video/bfin_adv7393fb.c
+++ b/drivers/video/bfin_adv7393fb.c
@@ -481,7 +481,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
goto out_4;
}
- if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, IRQF_DISABLED,
+ if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, 0,
"PPI ERROR", fbdev) < 0) {
dev_err(&client->dev, "unable to request PPI ERROR IRQ\n");
ret = -EFAULT;
diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c
index 12a634a..11a7a33 100644
--- a/drivers/video/mb862xx/mb862xxfbdrv.c
+++ b/drivers/video/mb862xx/mb862xxfbdrv.c
@@ -738,7 +738,7 @@ static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev)
if (mb862xx_gdc_init(par))
goto io_unmap;
- if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED,
+ if (request_irq(par->irq, mb862xx_intr, 0,
DRV_NAME, (void *)par)) {
dev_err(dev, "Cannot request irq\n");
goto io_unmap;
@@ -1074,7 +1074,7 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
if (mb862xx_pci_gdc_init(par))
goto io_unmap;
- if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED | IRQF_SHARED,
+ if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED,
DRV_NAME, (void *)par)) {
dev_err(dev, "Cannot request irq\n");
goto io_unmap;
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index 178b072..4527cbf 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -715,7 +715,7 @@ static int __devinit mddi_probe(struct platform_device *pdev)
mddi->int_enable = 0;
mddi_writel(mddi->int_enable, INTEN);
- ret = request_irq(mddi->irq, mddi_isr, IRQF_DISABLED, "mddi",
+ ret = request_irq(mddi->irq, mddi_isr, 0, "mddi",
&mddi->client_data);
if (ret) {
printk(KERN_ERR "mddi: failed to request enable irq!\n");
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 2750ed2..cb2ddf1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -426,7 +426,7 @@ int mdp_probe(struct platform_device *pdev)
goto error_get_clk;
}
- ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp);
+ ret = request_irq(mdp->irq, mdp_isr, 0, "msm_mdp", mdp);
if (ret)
goto error_request_irq;
disable_irq(mdp->irq);
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 37dd850..d1fbbd8 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -587,7 +587,7 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev)
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbi->pseudo_pal;
- ret = request_irq(irq, nuc900fb_irqhandler, IRQF_DISABLED,
+ ret = request_irq(irq, nuc900fb_irqhandler, 0,
pdev->name, fbinfo);
if (ret) {
dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 7f91002..80c3f6a 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -1034,7 +1034,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
gpio_direction_input(gpio);
r = request_irq(gpio_to_irq(gpio), taal_te_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING,
"taal vsync", dssdev);
if (r) {
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 65560a1..213fbbc 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1082,7 +1082,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
}
retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
- IRQF_DISABLED, DEVICE_NAME, &dev->core);
+ 0, DEVICE_NAME, &dev->core);
if (retval) {
dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
retval);
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c
index d8de557..1ed8b36 100644
--- a/drivers/video/pxa3xx-gcu.c
+++ b/drivers/video/pxa3xx-gcu.c
@@ -676,7 +676,7 @@ pxa3xx_gcu_probe(struct platform_device *dev)
}
ret = request_irq(irq, pxa3xx_gcu_handle_irq,
- IRQF_DISABLED, DRV_NAME, priv);
+ 0, DRV_NAME, priv);
if (ret) {
dev_err(&dev->dev, "request_irq failed\n");
ret = -EBUSY;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 0f4e8c9..e89778f 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -2191,7 +2191,7 @@ static int __devinit pxafb_probe(struct platform_device *dev)
goto failed_free_mem;
}
- ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi);
if (ret) {
dev_err(&dev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 798144a..ee4c0df 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -910,7 +910,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
for (i = 0; i < 256; i++)
info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
- ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
+ ret = request_irq(irq, s3c2410fb_irq, 0, pdev->name, info);
if (ret) {
dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
ret = -EBUSY;
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index e8b76d6..98d55d0 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1457,8 +1457,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
if (ret)
goto failed;
- ret = request_irq(irq, sa1100fb_handle_irq, IRQF_DISABLED,
- "LCD", fbi);
+ ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
if (ret) {
printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
goto failed;
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 4636f9d..facffc2 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1577,7 +1577,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
+ error = request_irq(i, sh_mobile_lcdc_irq, 0,
dev_name(&pdev->dev), priv);
if (error) {
dev_err(&pdev->dev, "unable to request irq\n");
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
index cd1c4dc..8e4a446 100644
--- a/drivers/video/tmiofb.c
+++ b/drivers/video/tmiofb.c
@@ -744,7 +744,7 @@ static int __devinit tmiofb_probe(struct platform_device *dev)
goto err_ioremap_vram;
}
- retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
+ retval = request_irq(irq, &tmiofb_irq, 0,
dev_name(&dev->dev), info);
if (retval)
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
index c13c246..777c21d 100644
--- a/drivers/video/vt8500lcdfb.c
+++ b/drivers/video/vt8500lcdfb.c
@@ -355,7 +355,7 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev)
goto failed_free_palette;
}
- ret = request_irq(irq, vt8500lcd_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ ret = request_irq(irq, vt8500lcd_handle_irq, 0, "LCD", fbi);
if (ret) {
dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH 49/57] video: irq: Remove IRQF_DISABLED
From: David Brown @ 2011-09-21 20:22 UTC (permalink / raw)
To: Yong Zhang
Cc: linux-arch, linux-kernel, tglx, Florian Tobias Schandinat,
David Brown, Daniel Walker, Bryan Huntsman, Wan ZongShun,
Tomi Valkeinen, Geoff Levand, Ben Dooks, Kukjin Kim,
Anatolij Gustschin, Paul Gortmaker, Andrew Morton,
Laurent Pinchart, Jiri Kosina, Archit Taneja, linux-fbdev,
linux-arm-msm, linux-arm-kernel, linux-omap, linuxppc-dev,
cbe-oss-dev
In-Reply-To: <1316597339-29861-50-git-send-email-yong.zhang0@gmail.com>
On Wed, Sep 21, 2011 at 05:28:50PM +0800, Yong Zhang wrote:
> Since commit [c58543c8: genirq: Run irq handlers with interrupts disabled],
> We run all interrupt handlers with interrupts disabled
> and we even check and yell when an interrupt handler
> returns with interrupts enabled (see commit [b738a50a:
> genirq: Warn when handler enables interrupts]).
>
> So now this flag is a NOOP and can be removed.
>
> Signed-off-by: Yong Zhang <yong.zhang0@gmail.com>
> ---
> drivers/video/msm/mddi.c | 2 +-
> drivers/video/msm/mdp.c | 2 +-
Acked-by: David Brown <davidb@codeaurora.org>
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* Re: Proposal for a low-level Linux display framework
From: Patrik Jakobsson @ 2011-09-21 18:07 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: linaro-dev, linux-fbdev, dri-devel, linux-kernel, Archit Taneja,
Clark, Rob
In-Reply-To: <1316584875.1949.4.camel@deskari>
On Wed, Sep 21, 2011 at 8:01 AM, Tomi Valkeinen wrote:
> I don't know what MCS is.
MCS is manufacturer specific commands (Manufacturer Command Set).
> But DSI is just a bi-directional transfer
> protocol between the SoC and the peripheral, you can send arbitrary data
> over it.
>
> Normally the SoC composes a pixel stream using overlays and whatnot,
> which goes to the DSI hardware, which then serializes the data and sends
> it to the peripheral.
>
> But you can as well send any data, like commands, and the peripheral can
> respond with any relevant data.
Ok it makes sense now, and I see how it can get more complicated than SDVO.
A DSI lib is a good idea and interfaces for stuff like backlight and mechanisms
for queuing commands that need to go in during blanking.
Thanks for clearing it up
-Patrik
^ permalink raw reply
* [PATCH 2/2] drivers/video: move some definitions from fsl-diu-fb.h to fsl-diu-fb.c
From: Timur Tabi @ 2011-09-21 16:54 UTC (permalink / raw)
To: linux-fbdev
Move several macros and structures from the Freescale DIU driver's header
file into the source file, because they're only used by that file. Also
delete a few unused macros.
The diu and diu_ad structures cannot be moved because they're being used
by the MPC5121 platform file. A future patch eliminate the need for
the platform file to access these structs, so they'll be moved also.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 46 +++++++++++++++++++++++++++++++++++++
include/linux/fsl-diu-fb.h | 54 --------------------------------------------
2 files changed, 46 insertions(+), 54 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index e5905b7..3e20291 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -30,11 +30,57 @@
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
#include <sysdev/fsl_soc.h>
#include <linux/fsl-diu-fb.h>
#include "edid.h"
+#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
+ /* 1 for plane 0, 2 for plane 1&2 each */
+
+/* HW cursor parameters */
+#define MAX_CURS 32
+
+/* Modes of operation of DIU */
+#define MFB_MODE0 0 /* DIU off */
+#define MFB_MODE1 1 /* All three planes output to display */
+#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
+#define MFB_MODE3 3 /* All three planes written back to memory */
+#define MFB_MODE4 4 /* Color bar generation */
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC 0x01 /* Vsync interrupt */
+#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
+#define INT_UNDRUN 0x04 /* Under run exception interrupt */
+#define INT_PARERR 0x08 /* Display parameters error interrupt */
+#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
+
+/* Panels'operation modes */
+#define MFB_TYPE_OUTPUT 0 /* Panel output to display */
+#define MFB_TYPE_OFF 1 /* Panel off */
+#define MFB_TYPE_WB 2 /* Panel written back to memory */
+#define MFB_TYPE_TEST 3 /* Panel generate color bar */
+
+struct diu_hw {
+ struct diu __iomem *diu_reg;
+ spinlock_t reg_lock;
+ unsigned int mode; /* DIU operation mode */
+};
+
+struct diu_addr {
+ void *vaddr; /* Virtual address */
+ dma_addr_t paddr; /* Physical address */
+ __u32 offset;
+};
+
+struct diu_pool {
+ struct diu_addr ad;
+ struct diu_addr gamma;
+ struct diu_addr pallete;
+ struct diu_addr cursor;
+};
+
/*
* List of supported video modes
*
diff --git a/include/linux/fsl-diu-fb.h b/include/linux/fsl-diu-fb.h
index 5efb407..c12de4e 100644
--- a/include/linux/fsl-diu-fb.h
+++ b/include/linux/fsl-diu-fb.h
@@ -47,7 +47,6 @@ struct aoi_display_offset {
#define MFB_GET_PIXFMT _IOR('M', 8, __u32)
#ifdef __KERNEL__
-#include <linux/spinlock.h>
/*
* These are the fields of area descriptor(in DDR memory) for every plane
@@ -145,58 +144,5 @@ struct diu {
__be32 plut;
} __attribute__ ((packed));
-struct diu_hw {
- struct diu *diu_reg;
- spinlock_t reg_lock;
-
- __u32 mode; /* DIU operation mode */
-};
-
-struct diu_addr {
- void *vaddr; /* Virtual address */
- dma_addr_t paddr; /* Physical address */
- __u32 offset;
-};
-
-struct diu_pool {
- struct diu_addr ad;
- struct diu_addr gamma;
- struct diu_addr pallete;
- struct diu_addr cursor;
-};
-
-#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */
-#define INT_LCDC 64 /* DIU interrupt number */
-
-#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
- /* 1 for plane 0, 2 for plane 1&2 each */
-
-/* Minimum X and Y resolutions */
-#define MIN_XRES 64
-#define MIN_YRES 64
-
-/* HW cursor parameters */
-#define MAX_CURS 32
-
-/* Modes of operation of DIU */
-#define MFB_MODE0 0 /* DIU off */
-#define MFB_MODE1 1 /* All three planes output to display */
-#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
-#define MFB_MODE3 3 /* All three planes written back to memory */
-#define MFB_MODE4 4 /* Color bar generation */
-
-/* INT_STATUS/INT_MASK field descriptions */
-#define INT_VSYNC 0x01 /* Vsync interrupt */
-#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
-#define INT_UNDRUN 0x04 /* Under run exception interrupt */
-#define INT_PARERR 0x08 /* Display parameters error interrupt */
-#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
-
-/* Panels'operation modes */
-#define MFB_TYPE_OUTPUT 0 /* Panel output to display */
-#define MFB_TYPE_OFF 1 /* Panel off */
-#define MFB_TYPE_WB 2 /* Panel written back to memory */
-#define MFB_TYPE_TEST 3 /* Panel generate color bar */
-
#endif /* __KERNEL__ */
#endif /* __FSL_DIU_FB_H__ */
--
1.7.3.4
^ permalink raw reply related
* [PATCH 1/2] drivers/video: fix ioctls in the Freescale DIU framebuffer driver
From: Timur Tabi @ 2011-09-21 16:54 UTC (permalink / raw)
To: linux-fbdev
Use the _IOx macros to define the ioctl commands, instead of hard-coded
numbers. Unfortunately, the original definitions of MFB_SET_PIXFMT and
MFB_GET_PIXFMT used the wrong value for the size, so this will break
binary compatibility with older applications.
Also remove the FBIOGET_GWINFO and FBIOPUT_GWINFO ioctls. FBIOPUT_GWINFO
was never implemented, and FBIOGET_GWINFO was never used by any
application.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 8 --------
include/linux/fsl-diu-fb.h | 20 ++++++++------------
2 files changed, 8 insertions(+), 20 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 5137fbb..e5905b7 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1030,14 +1030,6 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
ad->ckmin_b = ck.blue_min;
}
break;
- case FBIOGET_GWINFO:
- if (mfbi->type = MFB_TYPE_OFF)
- return -ENODEV;
- /* get graphic window information */
- if (copy_to_user(buf, ad, sizeof(*ad)))
- return -EFAULT;
- break;
-
default:
dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd);
return -ENOIOCTLCMD;
diff --git a/include/linux/fsl-diu-fb.h b/include/linux/fsl-diu-fb.h
index df23f59..5efb407 100644
--- a/include/linux/fsl-diu-fb.h
+++ b/include/linux/fsl-diu-fb.h
@@ -33,22 +33,18 @@ struct mfb_chroma_key {
};
struct aoi_display_offset {
- int x_aoi_d;
- int y_aoi_d;
+ __s32 x_aoi_d;
+ __s32 y_aoi_d;
};
#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key)
#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8)
-
-#define MFB_SET_ALPHA 0x80014d00
-#define MFB_GET_ALPHA 0x40014d00
-#define MFB_SET_AOID 0x80084d04
-#define MFB_GET_AOID 0x40084d04
-#define MFB_SET_PIXFMT 0x80014d08
-#define MFB_GET_PIXFMT 0x40014d08
-
-#define FBIOGET_GWINFO 0x46E0
-#define FBIOPUT_GWINFO 0x46E1
+#define MFB_SET_ALPHA _IOW('M', 0, __u8)
+#define MFB_GET_ALPHA _IOR('M', 0, __u8)
+#define MFB_SET_AOID _IOW('M', 4, struct aoi_display_offset)
+#define MFB_GET_AOID _IOR('M', 4, struct aoi_display_offset)
+#define MFB_SET_PIXFMT _IOW('M', 8, __u32)
+#define MFB_GET_PIXFMT _IOR('M', 8, __u32)
#ifdef __KERNEL__
#include <linux/spinlock.h>
--
1.7.3.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox