* Re: [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform
From: Laurent Pinchart @ 2013-04-24 21:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
Hi Prabhakar,
Thank you for the patch.
On Wednesday 24 April 2013 17:30:02 Prabhakar Lad wrote:
> From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
>
> 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.
The obvious question is: why not a KMS driver instead ? :-)
> Lad, Prabhakar (6):
> media: davinci: vpbe: fix checkpatch warning for CamelCase
> media: davinci: vpbe: enable vpbe for fbdev addition
> davinci: vpbe: add fbdev driver
> ARM: davinci: dm355: enable fbdev driver
> ARM: davinci: dm365: enable fbdev driver
> ARM: davinci: dm644x: enable fbdev driver
>
> arch/arm/mach-davinci/dm355.c | 24 +-
> arch/arm/mach-davinci/dm365.c | 10 +
> arch/arm/mach-davinci/dm644x.c | 10 +
> drivers/media/platform/davinci/vpbe_display.c | 8 +-
> drivers/media/platform/davinci/vpbe_osd.c | 820 ++++++++-
> drivers/media/platform/davinci/vpbe_venc.c | 43 +
> drivers/video/Kconfig | 12 +
> drivers/video/Makefile | 1 +
> drivers/video/davincifb.c | 2523 ++++++++++++++++++++++
> drivers/video/davincifb.h | 194 ++
> include/media/davinci/vpbe_osd.h | 66 +-
> include/media/davinci/vpbe_venc.h | 21 +
> 12 files changed, 3702 insertions(+), 30 deletions(-)
> create mode 100644 drivers/video/davincifb.c
> create mode 100644 drivers/video/davincifb.h
--
Regards,
Laurent Pinchart
^ permalink raw reply
* asus_nb_wmi bug
From: Lonnie Best @ 2013-04-24 19:50 UTC (permalink / raw)
To: linux-fbdev
I just discovered a work-around for a bug I was having with asus_nb_wmi:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1172151
What steps can I take to ensure that others won't have to encounter this
bug?
Lonnie Best
^ permalink raw reply
* [PATCH v5 2/2] video: imxfb: Add DT support
From: Markus Pargmann @ 2013-04-24 13:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366810751-26860-1-git-send-email-mpa@pengutronix.de>
Add devicetree support for imx framebuffer driver. It uses the generic
display bindings and helper functions.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
---
Notes:
Changed in v5:
- Fix compatible property of the example
- Rename property fsl,bpp to bits-per-pixel
- Add selects for FB_MODE_HELPERS and VIDEOMODE_HELPERS to Kconfig FB_IMX
Changes in v4:
- Remove eukrea specific dmacr property.
- Add optional dmacr property. If not present, the dmacr reset value is not
changed.
Changes in v3:
- Fix returncodes of of_read_mode function and print error messages
- Introduce a lower bound check for bits per pixel
- Calculate correct bytes per pixel value before using it for the calculation of
memory size
- Change DT property names
Changes in v2:
- Removed pwmr register property
- Cleanup of devicetree binding documentation
- Use default values for pwmr and lscr1
.../devicetree/bindings/video/fsl,imx-fb.txt | 51 ++++++
drivers/video/Kconfig | 2 +
drivers/video/imxfb.c | 194 +++++++++++++++++----
3 files changed, 212 insertions(+), 35 deletions(-)
create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
new file mode 100644
index 0000000..46da08d
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
@@ -0,0 +1,51 @@
+Freescale imx21 Framebuffer
+
+This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
+
+Required properties:
+- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : One interrupt of the fb dev
+
+Required nodes:
+- display: Phandle to a display node as described in
+ Documentation/devicetree/bindings/video/display-timing.txt
+ Additional, the display node has to define properties:
+ - bits-per-pixel: Bits per pixel
+ - fsl,pcr: LCDC PCR value
+
+Optional properties:
+- fsl,dmacr: DMA Control Register value. This is optional. By default, the
+ register is not modified as recommended by the datasheet.
+- fsl,lscr1: LCDC Sharp Configuration Register value.
+
+Example:
+
+ imxfb: fb@10021000 {
+ compatible = "fsl,imx21-fb";
+ interrupts = <61>;
+ reg = <0x10021000 0x1000>;
+ display = <&display0>;
+ };
+
+ ...
+
+ display0: display0 {
+ model = "Primeview-PD050VL1";
+ native-mode = <&timing_disp0>;
+ bits-per-pixel = <16>;
+ fsl,pcr = <0xf0c88080>; /* non-standard but required */
+ display-timings {
+ timing_disp0: 640x480 {
+ hactive = <640>;
+ vactive = <480>;
+ hback-porch = <112>;
+ hfront-porch = <36>;
+ hsync-len = <32>;
+ vback-porch = <33>;
+ vfront-porch = <33>;
+ vsync-len = <2>;
+ clock-frequency = <25000000>;
+ };
+ };
+ };
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c1546f..44b1af4 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -391,6 +391,8 @@ config FB_IMX
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
config FB_CYBER2000
tristate "CyberPro 2000/2010/5000 support"
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index ef2b587..7bb3728 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -32,6 +32,12 @@
#include <linux/io.h>
#include <linux/math64.h>
#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
#include <linux/platform_data/video-imxfb.h>
@@ -117,10 +123,11 @@
#define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
#define LGWCR_GWE (1 << 22)
+#define IMXFB_LSCR1_DEFAULT 0x00120300
+
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
-
/*
* These are the bitfields for each
* display depth that we support.
@@ -192,6 +199,19 @@ static struct platform_device_id imxfb_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, imxfb_devtype);
+static struct of_device_id imxfb_of_dev_id[] = {
+ {
+ .compatible = "fsl,imx1-fb",
+ .data = &imxfb_devtype[IMX1_FB],
+ }, {
+ .compatible = "fsl,imx21-fb",
+ .data = &imxfb_devtype[IMX21_FB],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
+
static inline int is_imx1_fb(struct imxfb_info *fbi)
{
return fbi->devtype = IMX1_FB;
@@ -324,6 +344,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
struct imx_fb_videomode *m;
int i;
+ if (!fb_mode)
+ return &fbi->mode[0];
+
for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
if (!strcmp(m->mode.name, fb_mode))
return m;
@@ -479,6 +502,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
struct imxfb_info *fbi = bl_get_data(bl);
int brightness = bl->props.brightness;
+ if (!fbi->pwmr)
+ return 0;
+
if (bl->props.power != FB_BLANK_UNBLANK)
brightness = 0;
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
@@ -719,10 +745,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
writel(fbi->pcr, fbi->regs + LCDC_PCR);
#ifndef PWMR_BACKLIGHT_AVAILABLE
- writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+ if (fbi->pwmr)
+ writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
#endif
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
- writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
+
+ /* dmacr = 0 is no valid value, as we need DMA control marks. */
+ if (fbi->dmacr)
+ writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
return 0;
}
@@ -758,13 +788,12 @@ static int imxfb_resume(struct platform_device *dev)
#define imxfb_resume NULL
#endif
-static int __init imxfb_init_fbinfo(struct platform_device *pdev)
+static int imxfb_init_fbinfo(struct platform_device *pdev)
{
struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
struct fb_info *info = dev_get_drvdata(&pdev->dev);
struct imxfb_info *fbi = info->par;
- struct imx_fb_videomode *m;
- int i;
+ struct device_node *np;
pr_debug("%s\n",__func__);
@@ -795,41 +824,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
info->fbops = &imxfb_ops;
info->flags = FBINFO_FLAG_DEFAULT |
FBINFO_READS_FAST;
- info->var.grayscale = pdata->cmap_greyscale;
- fbi->cmap_inverse = pdata->cmap_inverse;
- fbi->cmap_static = pdata->cmap_static;
- fbi->lscr1 = pdata->lscr1;
- fbi->dmacr = pdata->dmacr;
- fbi->pwmr = pdata->pwmr;
- fbi->lcd_power = pdata->lcd_power;
- fbi->backlight_power = pdata->backlight_power;
-
- for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
- info->fix.smem_len = max_t(size_t, info->fix.smem_len,
- m->mode.xres * m->mode.yres * m->bpp / 8);
+ if (pdata) {
+ info->var.grayscale = pdata->cmap_greyscale;
+ fbi->cmap_inverse = pdata->cmap_inverse;
+ fbi->cmap_static = pdata->cmap_static;
+ fbi->lscr1 = pdata->lscr1;
+ fbi->dmacr = pdata->dmacr;
+ fbi->pwmr = pdata->pwmr;
+ fbi->lcd_power = pdata->lcd_power;
+ fbi->backlight_power = pdata->backlight_power;
+ } else {
+ np = pdev->dev.of_node;
+ info->var.grayscale = of_property_read_bool(np,
+ "cmap-greyscale");
+ fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
+ fbi->cmap_static = of_property_read_bool(np, "cmap-static");
+
+ fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
+ of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
+
+ of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
+
+ /* These two function pointers could be used by some specific
+ * platforms. */
+ fbi->lcd_power = NULL;
+ fbi->backlight_power = NULL;
+ }
+
+ return 0;
+}
+
+static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
+ struct imx_fb_videomode *imxfb_mode)
+{
+ int ret;
+ struct fb_videomode *of_mode = &imxfb_mode->mode;
+ u32 bpp;
+ u32 pcr;
+
+ ret = of_property_read_string(np, "model", &of_mode->name);
+ if (ret)
+ of_mode->name = NULL;
+
+ ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
+ if (ret) {
+ dev_err(dev, "Failed to get videomode from DT\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "bits-per-pixel", &bpp);
+ ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
+
+ if (ret) {
+ dev_err(dev, "Failed to read bpp and pcr from DT\n");
+ return -EINVAL;
+ }
+
+ if (bpp < 1 || bpp > 255) {
+ dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
+ return -EINVAL;
+ }
+
+ imxfb_mode->bpp = bpp;
+ imxfb_mode->pcr = pcr;
return 0;
}
-static int __init imxfb_probe(struct platform_device *pdev)
+static int imxfb_probe(struct platform_device *pdev)
{
struct imxfb_info *fbi;
struct fb_info *info;
struct imx_fb_platform_data *pdata;
struct resource *res;
+ struct imx_fb_videomode *m;
+ const struct of_device_id *of_id;
int ret, i;
+ int bytes_per_pixel;
dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
+ of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev,"No platform_data available\n");
- return -ENOMEM;
- }
info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
if (!info)
@@ -837,15 +920,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
fbi = info->par;
- if (!fb_mode)
- fb_mode = pdata->mode[0].mode.name;
-
platform_set_drvdata(pdev, info);
ret = imxfb_init_fbinfo(pdev);
if (ret < 0)
goto failed_init;
+ if (pdata) {
+ if (!fb_mode)
+ fb_mode = pdata->mode[0].mode.name;
+
+ fbi->mode = pdata->mode;
+ fbi->num_modes = pdata->num_modes;
+ } else {
+ struct device_node *display_np;
+ fb_mode = NULL;
+
+ display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
+ if (!display_np) {
+ dev_err(&pdev->dev, "No display defined in devicetree\n");
+ ret = -EINVAL;
+ goto failed_of_parse;
+ }
+
+ /*
+ * imxfb does not support more modes, we choose only the native
+ * mode.
+ */
+ fbi->num_modes = 1;
+
+ fbi->mode = devm_kzalloc(&pdev->dev,
+ sizeof(struct imx_fb_videomode), GFP_KERNEL);
+ if (!fbi->mode) {
+ ret = -ENOMEM;
+ goto failed_of_parse;
+ }
+
+ ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
+ if (ret)
+ goto failed_of_parse;
+ }
+
+ /* Calculate maximum bytes used per pixel. In most cases this should
+ * be the same as m->bpp/8 */
+ m = &fbi->mode[0];
+ bytes_per_pixel = (m->bpp + 7) / 8;
+ for (i = 0; i < fbi->num_modes; i++, m++)
+ info->fix.smem_len = max_t(size_t, info->fix.smem_len,
+ m->mode.xres * m->mode.yres * bytes_per_pixel);
+
res = request_mem_region(res->start, resource_size(res),
DRIVER_NAME);
if (!res) {
@@ -878,7 +1001,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
goto failed_ioremap;
}
- if (!pdata->fixed_screen_cpu) {
+ /* Seems not being used by anyone, so no support for oftree */
+ if (!pdata || !pdata->fixed_screen_cpu) {
fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
fbi->map_size, &fbi->map_dma, GFP_KERNEL);
@@ -903,18 +1027,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
info->fix.smem_start = fbi->screen_dma;
}
- if (pdata->init) {
+ if (pdata && pdata->init) {
ret = pdata->init(fbi->pdev);
if (ret)
goto failed_platform_init;
}
- fbi->mode = pdata->mode;
- fbi->num_modes = pdata->num_modes;
INIT_LIST_HEAD(&info->modelist);
- for (i = 0; i < pdata->num_modes; i++)
- fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
+ for (i = 0; i < fbi->num_modes; i++)
+ fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
/*
* This makes sure that our colour bitfield
@@ -944,10 +1066,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
failed_register:
fb_dealloc_cmap(&info->cmap);
failed_cmap:
- if (pdata->exit)
+ if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
failed_platform_init:
- if (!pdata->fixed_screen_cpu)
+ if (pdata && !pdata->fixed_screen_cpu)
dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
fbi->map_dma);
failed_map:
@@ -956,6 +1078,7 @@ failed_ioremap:
failed_getclock:
release_mem_region(res->start, resource_size(res));
failed_req:
+failed_of_parse:
kfree(info->pseudo_palette);
failed_init:
platform_set_drvdata(pdev, NULL);
@@ -980,7 +1103,7 @@ static int imxfb_remove(struct platform_device *pdev)
unregister_framebuffer(info);
pdata = pdev->dev.platform_data;
- if (pdata->exit)
+ if (pdata && pdata->exit)
pdata->exit(fbi->pdev);
fb_dealloc_cmap(&info->cmap);
@@ -1009,6 +1132,7 @@ static struct platform_driver imxfb_driver = {
.shutdown = imxfb_shutdown,
.driver = {
.name = DRIVER_NAME,
+ .of_match_table = imxfb_of_dev_id,
},
.id_table = imxfb_devtype,
};
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 1/2] imxfb: Set alpha value of the framebuffer
From: Markus Pargmann @ 2013-04-24 13:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366810751-26860-1-git-send-email-mpa@pengutronix.de>
From: Christian Hemp <c.hemp@phytec.de>
Based on Sascha Hauer's patch i.MX27 clock: Do not disable lcd clocks during
startup.
This patch gives a interface to chance the alphavalue of the framebuffer.
Signed-off-by: Christian Hemp <c.hemp@phytec.de>
rebased to 3.7
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
drivers/video/imxfb.c | 35 +++++++++++++++++++++++++++++++
include/linux/platform_data/video-imxfb.h | 3 +++
2 files changed, 38 insertions(+)
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 0abf2bf..ef2b587 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/math64.h>
+#include <linux/uaccess.h>
#include <linux/platform_data/video-imxfb.h>
@@ -112,6 +113,10 @@
#define LCDISR_EOF (1<<1)
#define LCDISR_BOF (1<<0)
+#define LCDC_LGWCR 0x64
+#define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
+#define LGWCR_GWE (1 << 22)
+
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
@@ -610,6 +615,35 @@ static int imxfb_blank(int blank, struct fb_info *info)
return 0;
}
+static int imxfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct imxfb_info *fbi = info->par;
+ int alpha, ret = 0;
+ unsigned int tmp;
+
+ switch (cmd) {
+ case IMXFB_ALPHA:
+ if (get_user(alpha, (int __user *)arg)) {
+ ret = -EFAULT;
+ } else {
+ tmp = readl(fbi->regs + LCDC_LGWCR);
+ tmp &= ~LGWCR_GWAV(0xff);
+ tmp |= LGWCR_GWAV(alpha);
+ if (!alpha)
+ tmp &= ~LGWCR_GWE;
+ else
+ tmp |= LGWCR_GWE;
+ writel(tmp , fbi->regs + LCDC_LGWCR);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static struct fb_ops imxfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = imxfb_check_var,
@@ -619,6 +653,7 @@ static struct fb_ops imxfb_ops = {
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = imxfb_blank,
+ .fb_ioctl = imxfb_ioctl,
};
/*
diff --git a/include/linux/platform_data/video-imxfb.h b/include/linux/platform_data/video-imxfb.h
index 9de8f06..ce3875f 100644
--- a/include/linux/platform_data/video-imxfb.h
+++ b/include/linux/platform_data/video-imxfb.h
@@ -51,6 +51,9 @@
#define DMACR_HM(x) (((x) & 0xf) << 16)
#define DMACR_TM(x) ((x) & 0xf)
+#define IMXFB_IOW(num, dtype) _IOW('I', num, dtype)
+#define IMXFB_ALPHA IMXFB_IOW(31, int)
+
struct imx_fb_videomode {
struct fb_videomode mode;
u32 pcr;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 0/2] video: imxfb DT support
From: Markus Pargmann @ 2013-04-24 13:39 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds DT support for imxfb. Changes are listed in the notes section
of each patch.
Regards,
Markus
Christian Hemp (1):
imxfb: Set alpha value of the framebuffer
Markus Pargmann (1):
video: imxfb: Add DT support
Documentation/devicetree/bindings/video/fsl,imx-fb.txt | 51 +++++++++++++
drivers/video/Kconfig | 2 +
drivers/video/imxfb.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++---------
include/linux/platform_data/video-imxfb.h | 3 +
4 files changed, 250 insertions(+), 35 deletions(-)
create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
^ permalink raw reply
* Re: [PATCH v4 2/2] video: imxfb: Add DT support
From: Markus Pargmann @ 2013-04-24 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130422155125.GI4998@game.jcrosoft.org>
On Mon, Apr 22, 2013 at 05:51:25PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 10:11 Sun 21 Apr , Markus Pargmann wrote:
> > On Thu, Apr 18, 2013 at 06:06:14PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > > On 15:03 Thu 18 Apr , Markus Pargmann wrote:
> > > > Add devicetree support for imx framebuffer driver. It uses the generic
> > > > display bindings and helper functions.
> > > >
> > > > Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
> > > > Cc: Fabio Estevam <festevam@gmail.com>
> > > > Cc: Mark Rutland <mark.rutland@arm.com>
> > > > ---
> > > >
> > > > Notes:
> > > > Changes in v4:
> > > > - Remove eukrea specific dmacr property.
> > > > - Add optional dmacr property. If not present, the dmacr reset value is not
> > > > changed.
> > > >
> > > > Changes in v3:
> > > > - Fix returncodes of of_read_mode function and print error messages
> > > > - Introduce a lower bound check for bits per pixel
> > > > - Calculate correct bytes per pixel value before using it for the calculation of
> > > > memory size
> > > > - Change DT property names
> > > >
> > > > Changes in v2:
> > > > - Removed pwmr register property
> > > > - Cleanup of devicetree binding documentation
> > > > - Use default values for pwmr and lscr1
> > > >
> > > > .../devicetree/bindings/video/fsl,imx-fb.txt | 51 ++++++
> > > > drivers/video/imxfb.c | 194 +++++++++++++++++----
> > > > 2 files changed, 210 insertions(+), 35 deletions(-)
> > > > create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > > > new file mode 100644
> > > > index 0000000..aff16a4
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > > > @@ -0,0 +1,51 @@
> > > > +Freescale imx21 Framebuffer
> > > > +
> > > > +This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
> > > > +
> > > > +Required properties:
> > > > +- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
> > > > +- reg : Should contain 1 register ranges(address and length)
> > > > +- interrupts : One interrupt of the fb dev
> > > > +
> > > > +Required nodes:
> > > > +- display: Phandle to a display node as described in
> > > > + Documentation/devicetree/bindings/video/display-timing.txt
> > > > + Additional, the display node has to define properties:
> > > > + - fsl,bpp: Bits per pixel
> > > > + - fsl,pcr: LCDC PCR value
> > > > +
> > > > +Optional properties:
> > > > +- fsl,dmacr: DMA Control Register value. This is optional. By default, the
> > > > + register is not modified as recommended by the datasheet.
> > > > +- fsl,lscr1: LCDC Sharp Configuration Register value.
> > > > +
> > > > +Example:
> > > > +
> > > > + imxfb: fb@10021000 {
> > > > + compatible = "fsl,imx27-fb", "fsl,imx21-fb";
> > > you put both when in the doc you request one
> >
> > Thanks, fixed.
> >
> > > > + interrupts = <61>;
> > > > + reg = <0x10021000 0x1000>;
> > > > + display = <&display0>;
> > > > + };
> > > > +
> > > > + ...
> > > > +
> > > > + display0: display0 {
> > > > + model = "Primeview-PD050VL1";
> > > > + native-mode = <&timing_disp0>;
> > > > + fsl,bpp = <16>; /* non-standard but required */
> > > there is a generic binding bit-per-pixel use a cross other IP
> >
> > I can't find a generic binding for that. There are only 2 other drivers
> > using a "bpp" property, but they both use it within different contexts.
> > tilcdc panel uses it within a "panel-info" property and via,vt8500-fb
> > within modes. So I think it would be better to use a clear distinction
> > because there is no generic binding. That was also suggested in comments
> > on version 2 of this patch:
> > https://patchwork.kernel.org/patch/2220511/
>
> via use bits-per-pixel
> atmel ditto
> mxs ditto IIRC
>
> Best Regards,
> J.
Thanks, I renamed fsl,bpp to bits-per-pixel in v5.
Regards,
Markus
> >
> > Regards,
> >
> > Markus
> >
> > > > + fsl,pcr = <0xf0c88080>; /* non-standard but required */
> > > > + display-timings {
> > > > + timing_disp0: 640x480 {
> > > > + hactive = <640>;
> > > > + vactive = <480>;
> > > > + hback-porch = <112>;
> > > > + hfront-porch = <36>;
> > > > + hsync-len = <32>;
> > > > + vback-porch = <33>;
> > > > + vfront-porch = <33>;
> > > > + vsync-len = <2>;
> > > > + clock-frequency = <25000000>;
> > > > + };
> > > > + };
> > > > + };
> > > > diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
> > > > index ef2b587..e0230f8 100644
> > > > --- a/drivers/video/imxfb.c
> > > > +++ b/drivers/video/imxfb.c
> > > > @@ -32,6 +32,12 @@
> > > > #include <linux/io.h>
> > > > #include <linux/math64.h>
> > > > #include <linux/uaccess.h>
> > > > +#include <linux/of.h>
> > > > +#include <linux/of_device.h>
> > > > +
> > > > +#include <video/of_display_timing.h>
> > > > +#include <video/of_videomode.h>
> > > > +#include <video/videomode.h>
> > > >
> > > > #include <linux/platform_data/video-imxfb.h>
> > > >
> > > > @@ -117,10 +123,11 @@
> > > > #define LGWCR_GWAV(alpha) (((alpha) & 0xff) << 24)
> > > > #define LGWCR_GWE (1 << 22)
> > > >
> > > > +#define IMXFB_LSCR1_DEFAULT 0x00120300
> > > > +
> > > > /* Used fb-mode. Can be set on kernel command line, therefore file-static. */
> > > > static const char *fb_mode;
> > > >
> > > > -
> > > > /*
> > > > * These are the bitfields for each
> > > > * display depth that we support.
> > > > @@ -192,6 +199,19 @@ static struct platform_device_id imxfb_devtype[] = {
> > > > };
> > > > MODULE_DEVICE_TABLE(platform, imxfb_devtype);
> > > >
> > > > +static struct of_device_id imxfb_of_dev_id[] = {
> > > > + {
> > > > + .compatible = "fsl,imx1-fb",
> > > > + .data = &imxfb_devtype[IMX1_FB],
> > > > + }, {
> > > > + .compatible = "fsl,imx21-fb",
> > > > + .data = &imxfb_devtype[IMX21_FB],
> > > > + }, {
> > > > + /* sentinel */
> > > > + }
> > > > +};
> > > > +MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
> > > > +
> > > > static inline int is_imx1_fb(struct imxfb_info *fbi)
> > > > {
> > > > return fbi->devtype = IMX1_FB;
> > > > @@ -324,6 +344,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
> > > > struct imx_fb_videomode *m;
> > > > int i;
> > > >
> > > > + if (!fb_mode)
> > > > + return &fbi->mode[0];
> > > > +
> > > > for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
> > > > if (!strcmp(m->mode.name, fb_mode))
> > > > return m;
> > > > @@ -479,6 +502,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
> > > > struct imxfb_info *fbi = bl_get_data(bl);
> > > > int brightness = bl->props.brightness;
> > > >
> > > > + if (!fbi->pwmr)
> > > > + return 0;
> > > > +
> > > > if (bl->props.power != FB_BLANK_UNBLANK)
> > > > brightness = 0;
> > > > if (bl->props.fb_blank != FB_BLANK_UNBLANK)
> > > > @@ -719,10 +745,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
> > > >
> > > > writel(fbi->pcr, fbi->regs + LCDC_PCR);
> > > > #ifndef PWMR_BACKLIGHT_AVAILABLE
> > > > - writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
> > > > + if (fbi->pwmr)
> > > > + writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
> > > > #endif
> > > > writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
> > > > - writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
> > > > +
> > > > + /* dmacr = 0 is no valid value, as we need DMA control marks. */
> > > > + if (fbi->dmacr)
> > > > + writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
> > > >
> > > > return 0;
> > > > }
> > > > @@ -758,13 +788,12 @@ static int imxfb_resume(struct platform_device *dev)
> > > > #define imxfb_resume NULL
> > > > #endif
> > > >
> > > > -static int __init imxfb_init_fbinfo(struct platform_device *pdev)
> > > > +static int imxfb_init_fbinfo(struct platform_device *pdev)
> > > > {
> > > > struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
> > > > struct fb_info *info = dev_get_drvdata(&pdev->dev);
> > > > struct imxfb_info *fbi = info->par;
> > > > - struct imx_fb_videomode *m;
> > > > - int i;
> > > > + struct device_node *np;
> > > >
> > > > pr_debug("%s\n",__func__);
> > > >
> > > > @@ -795,41 +824,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
> > > > info->fbops = &imxfb_ops;
> > > > info->flags = FBINFO_FLAG_DEFAULT |
> > > > FBINFO_READS_FAST;
> > > > - info->var.grayscale = pdata->cmap_greyscale;
> > > > - fbi->cmap_inverse = pdata->cmap_inverse;
> > > > - fbi->cmap_static = pdata->cmap_static;
> > > > - fbi->lscr1 = pdata->lscr1;
> > > > - fbi->dmacr = pdata->dmacr;
> > > > - fbi->pwmr = pdata->pwmr;
> > > > - fbi->lcd_power = pdata->lcd_power;
> > > > - fbi->backlight_power = pdata->backlight_power;
> > > > -
> > > > - for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
> > > > - info->fix.smem_len = max_t(size_t, info->fix.smem_len,
> > > > - m->mode.xres * m->mode.yres * m->bpp / 8);
> > > > + if (pdata) {
> > > > + info->var.grayscale = pdata->cmap_greyscale;
> > > > + fbi->cmap_inverse = pdata->cmap_inverse;
> > > > + fbi->cmap_static = pdata->cmap_static;
> > > > + fbi->lscr1 = pdata->lscr1;
> > > > + fbi->dmacr = pdata->dmacr;
> > > > + fbi->pwmr = pdata->pwmr;
> > > > + fbi->lcd_power = pdata->lcd_power;
> > > > + fbi->backlight_power = pdata->backlight_power;
> > > > + } else {
> > > > + np = pdev->dev.of_node;
> > > > + info->var.grayscale = of_property_read_bool(np,
> > > > + "cmap-greyscale");
> > > > + fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
> > > > + fbi->cmap_static = of_property_read_bool(np, "cmap-static");
> > > > +
> > > > + fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
> > > > + of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
> > > > +
> > > > + of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
> > > > +
> > > > + /* These two function pointers could be used by some specific
> > > > + * platforms. */
> > > > + fbi->lcd_power = NULL;
> > > > + fbi->backlight_power = NULL;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
> > > > + struct imx_fb_videomode *imxfb_mode)
> > > > +{
> > > > + int ret;
> > > > + struct fb_videomode *of_mode = &imxfb_mode->mode;
> > > > + u32 bpp;
> > > > + u32 pcr;
> > > > +
> > > > + ret = of_property_read_string(np, "model", &of_mode->name);
> > > > + if (ret)
> > > > + of_mode->name = NULL;
> > > > +
> > > > + ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
> > > > + if (ret) {
> > > > + dev_err(dev, "Failed to get videomode from DT\n");
> > > > + return ret;
> > > > + }
> > > > +
> > > > + ret = of_property_read_u32(np, "fsl,bpp", &bpp);
> > > > + ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
> > > > +
> > > > + if (ret) {
> > > > + dev_err(dev, "Failed to read bpp and pcr from DT\n");
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + if (bpp < 1 || bpp > 255) {
> > > > + dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + imxfb_mode->bpp = bpp;
> > > > + imxfb_mode->pcr = pcr;
> > > >
> > > > return 0;
> > > > }
> > > >
> > > > -static int __init imxfb_probe(struct platform_device *pdev)
> > > > +static int imxfb_probe(struct platform_device *pdev)
> > > > {
> > > > struct imxfb_info *fbi;
> > > > struct fb_info *info;
> > > > struct imx_fb_platform_data *pdata;
> > > > struct resource *res;
> > > > + struct imx_fb_videomode *m;
> > > > + const struct of_device_id *of_id;
> > > > int ret, i;
> > > > + int bytes_per_pixel;
> > > >
> > > > dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
> > > >
> > > > + of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
> > > > + if (of_id)
> > > > + pdev->id_entry = of_id->data;
> > > > +
> > > > res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > if (!res)
> > > > return -ENODEV;
> > > >
> > > > pdata = pdev->dev.platform_data;
> > > > - if (!pdata) {
> > > > - dev_err(&pdev->dev,"No platform_data available\n");
> > > > - return -ENOMEM;
> > > > - }
> > > >
> > > > info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
> > > > if (!info)
> > > > @@ -837,15 +920,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > > >
> > > > fbi = info->par;
> > > >
> > > > - if (!fb_mode)
> > > > - fb_mode = pdata->mode[0].mode.name;
> > > > -
> > > > platform_set_drvdata(pdev, info);
> > > >
> > > > ret = imxfb_init_fbinfo(pdev);
> > > > if (ret < 0)
> > > > goto failed_init;
> > > >
> > > > + if (pdata) {
> > > > + if (!fb_mode)
> > > > + fb_mode = pdata->mode[0].mode.name;
> > > > +
> > > > + fbi->mode = pdata->mode;
> > > > + fbi->num_modes = pdata->num_modes;
> > > > + } else {
> > > > + struct device_node *display_np;
> > > > + fb_mode = NULL;
> > > > +
> > > > + display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
> > > > + if (!display_np) {
> > > > + dev_err(&pdev->dev, "No display defined in devicetree\n");
> > > > + ret = -EINVAL;
> > > > + goto failed_of_parse;
> > > > + }
> > > > +
> > > > + /*
> > > > + * imxfb does not support more modes, we choose only the native
> > > > + * mode.
> > > > + */
> > > > + fbi->num_modes = 1;
> > > > +
> > > > + fbi->mode = devm_kzalloc(&pdev->dev,
> > > > + sizeof(struct imx_fb_videomode), GFP_KERNEL);
> > > > + if (!fbi->mode) {
> > > > + ret = -ENOMEM;
> > > > + goto failed_of_parse;
> > > > + }
> > > > +
> > > > + ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
> > > > + if (ret)
> > > > + goto failed_of_parse;
> > > > + }
> > > > +
> > > > + /* Calculate maximum bytes used per pixel. In most cases this should
> > > > + * be the same as m->bpp/8 */
> > > > + m = &fbi->mode[0];
> > > > + bytes_per_pixel = (m->bpp + 7) / 8;
> > > > + for (i = 0; i < fbi->num_modes; i++, m++)
> > > > + info->fix.smem_len = max_t(size_t, info->fix.smem_len,
> > > > + m->mode.xres * m->mode.yres * bytes_per_pixel);
> > > > +
> > > > res = request_mem_region(res->start, resource_size(res),
> > > > DRIVER_NAME);
> > > > if (!res) {
> > > > @@ -878,7 +1001,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > > > goto failed_ioremap;
> > > > }
> > > >
> > > > - if (!pdata->fixed_screen_cpu) {
> > > > + /* Seems not being used by anyone, so no support for oftree */
> > > > + if (!pdata || !pdata->fixed_screen_cpu) {
> > > > fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
> > > > fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
> > > > fbi->map_size, &fbi->map_dma, GFP_KERNEL);
> > > > @@ -903,18 +1027,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > > > info->fix.smem_start = fbi->screen_dma;
> > > > }
> > > >
> > > > - if (pdata->init) {
> > > > + if (pdata && pdata->init) {
> > > > ret = pdata->init(fbi->pdev);
> > > > if (ret)
> > > > goto failed_platform_init;
> > > > }
> > > >
> > > > - fbi->mode = pdata->mode;
> > > > - fbi->num_modes = pdata->num_modes;
> > > >
> > > > INIT_LIST_HEAD(&info->modelist);
> > > > - for (i = 0; i < pdata->num_modes; i++)
> > > > - fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
> > > > + for (i = 0; i < fbi->num_modes; i++)
> > > > + fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
> > > >
> > > > /*
> > > > * This makes sure that our colour bitfield
> > > > @@ -944,10 +1066,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
> > > > failed_register:
> > > > fb_dealloc_cmap(&info->cmap);
> > > > failed_cmap:
> > > > - if (pdata->exit)
> > > > + if (pdata && pdata->exit)
> > > > pdata->exit(fbi->pdev);
> > > > failed_platform_init:
> > > > - if (!pdata->fixed_screen_cpu)
> > > > + if (pdata && !pdata->fixed_screen_cpu)
> > > > dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
> > > > fbi->map_dma);
> > > > failed_map:
> > > > @@ -956,6 +1078,7 @@ failed_ioremap:
> > > > failed_getclock:
> > > > release_mem_region(res->start, resource_size(res));
> > > > failed_req:
> > > > +failed_of_parse:
> > > > kfree(info->pseudo_palette);
> > > > failed_init:
> > > > platform_set_drvdata(pdev, NULL);
> > > > @@ -980,7 +1103,7 @@ static int imxfb_remove(struct platform_device *pdev)
> > > > unregister_framebuffer(info);
> > > >
> > > > pdata = pdev->dev.platform_data;
> > > > - if (pdata->exit)
> > > > + if (pdata && pdata->exit)
> > > > pdata->exit(fbi->pdev);
> > > >
> > > > fb_dealloc_cmap(&info->cmap);
> > > > @@ -1009,6 +1132,7 @@ static struct platform_driver imxfb_driver = {
> > > > .shutdown = imxfb_shutdown,
> > > > .driver = {
> > > > .name = DRIVER_NAME,
> > > > + .of_match_table = imxfb_of_dev_id,
> > > > },
> > > > .id_table = imxfb_devtype,
> > > > };
> > > > --
> > > > 1.8.1.5
> > > >
> > >
> >
> > --
> > Pengutronix e.K. | |
> > Industrial Linux Solutions | http://www.pengutronix.de/ |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
> > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH 6/6] ARM: davinci: dm644x: enable fbdev driver
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
This patch enables fbdev driver by creating fbdev device and register it.
Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
---
arch/arm/mach-davinci/dm644x.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index c2a9273..a4fee07 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -745,6 +745,15 @@ static struct platform_device dm644x_vpbe_display = {
},
};
+static struct platform_device dm644x_davincifb = {
+ .name = "davinci-vpbe-fb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &dm644x_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
static struct venc_platform_data dm644x_venc_pdata = {
.setup_clock = dm644x_venc_setup_clock,
};
@@ -909,6 +918,7 @@ int __init dm644x_init_video(struct vpfe_config *vpfe_cfg,
platform_device_register(&dm644x_venc_dev);
platform_device_register(&dm644x_vpbe_dev);
platform_device_register(&dm644x_vpbe_display);
+ platform_device_register(&dm644x_davincifb);
}
return 0;
--
1.7.4.1
^ permalink raw reply related
* [PATCH 5/6] ARM: davinci: dm365: enable fbdev driver
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
This patch enables fbdev driver by creating fbdev device and register it.
Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
---
arch/arm/mach-davinci/dm365.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index ff771ce..b06623c 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -1349,6 +1349,15 @@ static struct platform_device dm365_vpbe_display = {
},
};
+static struct platform_device dm365_davincifb = {
+ .name = "davinci-vpbe-fb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &dm365_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
struct venc_platform_data dm365_venc_pdata = {
.setup_pinmux = dm365_vpbe_setup_pinmux,
.setup_clock = dm365_venc_setup_clock,
@@ -1392,6 +1401,7 @@ int __init dm365_init_video(struct vpfe_config *vpfe_cfg,
platform_device_register(&dm365_venc_dev);
platform_device_register(&dm365_vpbe_dev);
platform_device_register(&dm365_vpbe_display);
+ platform_device_register(&dm365_davincifb);
}
return 0;
--
1.7.4.1
^ permalink raw reply related
* [PATCH 4/6] ARM: davinci: dm355: enable fbdev driver
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
This patch enables fbdev driver by creating fbdev device and register it.
Alongside renames 'vpfe_capture_dma_mask' to 'dm355_video_dma_mask' for better
clarity since it was reused by capture and diplay aswell.
Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
---
arch/arm/mach-davinci/dm355.c | 24 +++++++++++++++++-------
1 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index bf9a9d4..fe50814 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -714,7 +714,7 @@ static struct resource vpfe_resources[] = {
},
};
-static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
+static u64 dm355_video_dma_mask = DMA_BIT_MASK(32);
static struct resource dm355_ccdc_resource[] = {
/* CCDC Base address */
{
@@ -729,7 +729,7 @@ static struct platform_device dm355_ccdc_dev = {
.num_resources = ARRAY_SIZE(dm355_ccdc_resource),
.resource = dm355_ccdc_resource,
.dev = {
- .dma_mask = &vpfe_capture_dma_mask,
+ .dma_mask = &dm355_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = dm355_ccdc_setup_pinmux,
},
@@ -741,7 +741,7 @@ static struct platform_device vpfe_capture_dev = {
.num_resources = ARRAY_SIZE(vpfe_resources),
.resource = vpfe_resources,
.dev = {
- .dma_mask = &vpfe_capture_dma_mask,
+ .dma_mask = &dm355_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
@@ -760,7 +760,7 @@ static struct platform_device dm355_osd_dev = {
.num_resources = ARRAY_SIZE(dm355_osd_resources),
.resource = dm355_osd_resources,
.dev = {
- .dma_mask = &vpfe_capture_dma_mask,
+ .dma_mask = &dm355_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
@@ -855,7 +855,16 @@ static struct platform_device dm355_vpbe_display = {
.num_resources = ARRAY_SIZE(dm355_v4l2_disp_resources),
.resource = dm355_v4l2_disp_resources,
.dev = {
- .dma_mask = &vpfe_capture_dma_mask,
+ .dma_mask = &dm355_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct platform_device dm355_davincifb = {
+ .name = "davinci-vpbe-fb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &dm355_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
@@ -871,7 +880,7 @@ static struct platform_device dm355_venc_dev = {
.num_resources = ARRAY_SIZE(dm355_venc_resources),
.resource = dm355_venc_resources,
.dev = {
- .dma_mask = &vpfe_capture_dma_mask,
+ .dma_mask = &dm355_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = (void *)&dm355_venc_pdata,
},
@@ -881,7 +890,7 @@ static struct platform_device dm355_vpbe_dev = {
.name = "vpbe_controller",
.id = -1,
.dev = {
- .dma_mask = &vpfe_capture_dma_mask,
+ .dma_mask = &dm355_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
@@ -1023,6 +1032,7 @@ int __init dm355_init_video(struct vpfe_config *vpfe_cfg,
platform_device_register(&dm355_venc_dev);
platform_device_register(&dm355_vpbe_dev);
platform_device_register(&dm355_vpbe_display);
+ platform_device_register(&dm355_davincifb);
}
return 0;
--
1.7.4.1
^ permalink raw reply related
* [PATCH 3/6] davinci: vpbe: add fbdev driver
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
add the fbdev driver for DMX 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: Lad, Prabhakar <prabhakar.csengg@gmail.com>
---
drivers/video/Kconfig | 12 +
drivers/video/Makefile | 1 +
drivers/video/davincifb.c | 2523 +++++++++++++++++++++++++++++++++++++++++++++
drivers/video/davincifb.h | 194 ++++
4 files changed, 2730 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/davincifb.c
create mode 100644 drivers/video/davincifb.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c1546f..fa264a3 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2451,6 +2451,18 @@ config FB_PUV3_UNIGFX
Choose this option if you want to use the Unigfx device as a
framebuffer device. Without the support of PCI & AGP.
+config FB_DAVINCI_DMX
+ tristate "Davinci Framebuffer driver"
+ depends on FB && ARCH_DAVINCI
+ select VIDEO_DMXXX_VPBE
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Enables Davinci Framebuffer driver on a DMX device
+ To compile this driver as a module, choose M here: the
+ module will be called vpbe_fb.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9df3873..bf4f5f2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -165,6 +165,7 @@ obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
+obj-$(CONFIG_FB_DAVINCI_DMX) += davincifb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/davincifb.c b/drivers/video/davincifb.c
new file mode 100644
index 0000000..59b6cf7
--- /dev/null
+++ b/drivers/video/davincifb.c
@@ -0,0 +1,2523 @@
+/*
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2013 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/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <mach/cputype.h>
+
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/v4l2-subdev.h>
+
+#include "davincifb.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 = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->nonstd = 0;
+
+ if (lconfig->pixfmt = PIXFMT_1BPP ||
+ lconfig->pixfmt = PIXFMT_2BPP ||
+ lconfig->pixfmt = PIXFMT_4BPP ||
+ lconfig->pixfmt = PIXFMT_8BPP) {
+ var->red.length = var->bits_per_pixel;
+ var->green.length = var->bits_per_pixel;
+ var->blue.length = var->bits_per_pixel;
+ }
+
+ switch (lconfig->pixfmt) {
+ case PIXFMT_1BPP:
+ var->bits_per_pixel = 1;
+ break;
+ case PIXFMT_2BPP:
+ var->bits_per_pixel = 2;
+ break;
+ case PIXFMT_4BPP:
+ var->bits_per_pixel = 4;
+ break;
+ case PIXFMT_8BPP:
+ var->bits_per_pixel = 8;
+ 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 = 0;
+ var->green.length = 0;
+ var->blue.length = 0;
+ var->nonstd = 1;
+ break;
+ case PIXFMT_NV12:
+ if (cpu_is_davinci_dm365()) {
+ var->bits_per_pixel = 8;
+ var->red.length = 0;
+ var->green.length = 0;
+ 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 = 0;
+ var->green.length = 0;
+ 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_TIMINGS))
+ 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_DV_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 davincifb_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 davincifb_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 davincifb_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 davincifb_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 davincifb_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 davincifb_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 davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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
+davincifb_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;
+}
+
+static int
+davincifb_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 davincifb_wait_for_vsync(info);
+
+ case FBIO_SETATTRIBUTE:
+ if (copy_from_user(&rect, argp, sizeof(rect)))
+ return -EFAULT;
+ return davincifb_set_attr_blend(info, &rect);
+
+ case FBIO_SETPOSX:
+ return davincifb_setposx(info, arg);
+
+ case FBIO_SETPOSY:
+ return davincifb_setposy(info, arg);
+
+ case FBIO_SETZOOM:
+ if (copy_from_user(&zoom, argp, sizeof(zoom)))
+ return -EFAULT;
+ return davincifb_set_zoom(info, &zoom);
+
+ case FBIO_ENABLE_DISABLE_WIN:
+ return davincifb_enable_disable_win(info, arg);
+
+ case FBIO_SET_BITMAP_BLEND_FACTOR:
+ if (copy_from_user(&blend_para, argp, sizeof(blend_para)))
+ return -EFAULT;
+ return davincifb_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 davincifb_bitmap_set_ram_clut(info, win->dm->ram_clut);
+
+ case FBIO_ENABLE_DISABLE_ATTRIBUTE_WIN:
+ return davincifb_enable_disable_attribute_window(info, arg);
+
+ case FBIO_GET_BLINK_INTERVAL:
+ retval = davincifb_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 davincifb_set_blinking(info, &blink_option);
+
+ case FBIO_GET_VIDEO_CONFIG_PARAMS:
+ retval = davincifb_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 davincifb_set_vid_params(info, &vid_conf_params);
+
+ case FBIO_GET_BITMAP_CONFIG_PARAMS:
+ retval = davincifb_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 davincifb_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 davincifb_set_backg_color(info, &backg_color);
+
+ case FBIO_SETPOS:
+ if (copy_from_user(&win_pos, argp, sizeof(win_pos)))
+ return -EFAULT;
+ return davincifb_setpos(info, &win_pos);
+
+ case FBIO_SET_CURSOR:
+ if (copy_from_user(&cursor, argp, sizeof(cursor)))
+ return -EFAULT;
+ return davincifb_set_cursor_params(info, &cursor);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+davincifb_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;
+}
+
+static int davincifb_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);
+
+ /*
+ * 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 = win->dm->mode.vmode;
+ 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)
+
+static int davincifb_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;
+}
+
+/*
+ * davincifb_pan_display(): 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
+davincifb_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;
+}
+
+/*
+ * davincifb_blank(): Blank the screen if blank_mode != 0, else unblank.
+ */
+int davincifb_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 = davincifb_check_var,
+ .fb_set_par = davincifb_set_par,
+ .fb_setcolreg = davincifb_setcolreg,
+ .fb_blank = davincifb_blank,
+ .fb_pan_display = davincifb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_rotate = NULL,
+ .fb_sync = NULL,
+ .fb_ioctl = davincifb_ioctl,
+};
+
+static void davincifb_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 davincifb_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\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 davincifb_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);
+
+ davincifb_release_window(&pdev->dev, &dm->win[WIN_VID1]);
+ davincifb_release_window(&pdev->dev, &dm->win[WIN_OSD1]);
+ davincifb_release_window(&pdev->dev, &dm->win[WIN_VID0]);
+ davincifb_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 davincifb_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)
+{
+ char *s, *p, c = 0;
+ unsigned bits_per_pixel;
+
+ if (!opt)
+ return;
+
+ /* xsize */
+ p = strpbrk(opt, "x,@");
+ if (p)
+ c = *p;
+ s = strsep(&opt, "x,@");
+ if (s = NULL)
+ return;
+ if (*s && kstrtoul(s, 0, (long unsigned*)&lconfig->xsize))
+ goto parse_error;
+ 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 && kstrtoul(s, 0, (long unsigned*)&lconfig->ysize))
+ goto parse_error;
+ 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) {
+ if (kstrtoul(s, 0, (long unsigned*)&bits_per_pixel))
+ goto parse_error;
+ 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;
+ }
+ }
+ 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 && kstrtoul(s, 0, (long unsigned*)&lconfig->xpos))
+ goto parse_error;
+ if (!p || !opt)
+ return;
+ }
+
+ /* ypos */
+ if (c = ',') {
+ s = opt;
+ if (*s && kstrtoul(s, 0, (long unsigned*)&lconfig->ypos))
+ goto parse_error;
+ }
+
+ return;
+parse_error:
+ pr_err("davincifb bootparams parse error\n");
+}
+
+/*
+ * 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
+davincifb_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 = davincifb_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 davincifb_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 davincifb_device_get(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ if (strstr(pdev->name, "vpbe-osd") != NULL)
+ osd_device = platform_get_drvdata(pdev);
+
+ return 0;
+}
+
+static int davincifb_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, davincifb_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,
+ davincifb_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;
+ davincifb_get_default_win_config(&pdev->dev, &dm->win[WIN_OSD0],
+ &lconfig, &fb_size, options);
+ err = davincifb_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 (!davincifb_get_default_win_config(&pdev->dev, &dm->win[WIN_VID0],
+ &lconfig, &fb_size, options)) {
+ err = davincifb_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;
+ davincifb_get_default_win_config(&pdev->dev, &dm->win[WIN_OSD1],
+ &lconfig, &fb_size, options);
+ err + davincifb_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 (!davincifb_get_default_win_config(&pdev->dev, &dm->win[WIN_VID1],
+ &lconfig, &fb_size, options)) {
+ err = davincifb_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 = davincifb_vsync_callback;
+ dm->vsync_callback.arg = dm;
+
+ v4l2_subdev_call(dm->vpbe_dev->venc, core, ioctl,
+ VENC_REG_CALLBACK, &dm->vsync_callback);
+
+ dev_info(&pdev->dev, "Davinci VPBE FB Driver probe success\n");
+
+ return 0;
+
+vid1_out:
+ davincifb_release_window(&pdev->dev, &dm->win[WIN_OSD1]);
+osd1_out:
+ davincifb_release_window(&pdev->dev, &dm->win[WIN_VID0]);
+vid0_out:
+ davincifb_release_window(&pdev->dev, &dm->win[WIN_OSD0]);
+osd0_out:
+ kfree(dm);
+
+ return err;
+}
+
+static struct platform_driver davincifb_driver = {
+ .driver = {
+ .name = "davinci-vpbe-fb",
+ .owner = THIS_MODULE,
+ .bus = &platform_bus_type,
+ },
+ .probe = davincifb_probe,
+ .remove = davincifb_remove,
+};
+
+
+static int __init davincifb_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)) {
+ pr_err("Disabled on command-line.\n");
+ return -ENODEV;
+ }
+ if (options)
+ break;
+ }
+ }
+#endif
+ /* Register the driver with LDM */
+ if (platform_driver_register(&davincifb_driver)) {
+ pr_err("failed to register vpbe_fb driver\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit davincifb_cleanup(void)
+{
+ platform_driver_unregister(&davincifb_driver);
+}
+
+late_initcall(davincifb_init);
+module_exit(davincifb_cleanup);
+
+MODULE_DESCRIPTION("TI VPBE Framebuffer driver");
+MODULE_AUTHOR("Texas Instruments Ltd");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/davincifb.h b/drivers/video/davincifb.h
new file mode 100644
index 0000000..8166b9d9
--- /dev/null
+++ b/drivers/video/davincifb.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2009 MontaVista Software Inc.
+ * Copyright (C) 2013 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_H
+#define DAVINCIFB_H
+
+/* 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;
+};
+
+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 /* DAVINCIFB_H */
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/6] media: davinci: vpbe: enable vpbe for fbdev addition
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
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: Lad, Prabhakar <prabhakar.csengg@gmail.com>
---
drivers/media/platform/davinci/vpbe_display.c | 6 +
drivers/media/platform/davinci/vpbe_osd.c | 796 ++++++++++++++++++++++++-
drivers/media/platform/davinci/vpbe_venc.c | 43 ++
include/media/davinci/vpbe_osd.h | 62 ++
include/media/davinci/vpbe_venc.h | 21 +
5 files changed, 920 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 1c4ba89..0341dcc 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -121,10 +121,12 @@ 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 fid;
+ int ret;
int i;
if ((NULL = arg) || (NULL = disp_dev->dev[0]))
@@ -195,6 +197,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/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index 6ed82e8..455b0ca 100644
--- a/drivers/media/platform/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -175,6 +175,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;
@@ -185,6 +192,365 @@ 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->xpos = min_t(unsigned, cursor->xpos, (unsigned)OSD_CURXP_RCSX);
+ cursor->ypos = min_t(unsigned, cursor->ypos, (unsigned)OSD_CURYP_RCSY);
+ cursor->xsize + min_t(unsigned, cursor->xsize, (unsigned)OSD_CURXL_RCSW);
+ cursor->ysize + min_t(unsigned, cursor->ysize, (unsigned)OSD_CURYL_RCSH);
+ 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)
{
@@ -199,6 +565,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)
{
@@ -208,6 +597,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,
@@ -257,14 +790,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,
@@ -276,9 +850,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,
@@ -292,6 +863,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)
@@ -308,6 +908,25 @@ 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)
{
@@ -388,6 +1007,28 @@ 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)
{
@@ -421,6 +1062,69 @@ static void _osd_set_osd_clut(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)
+{
+ 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)
@@ -454,6 +1158,31 @@ static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
break;
}
}
+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)
{
@@ -497,7 +1226,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)
@@ -811,7 +1540,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:
@@ -910,6 +1639,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)
{
/*
@@ -1530,16 +2275,51 @@ 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,
.start_layer = osd_start_layer,
.set_left_margin = osd_set_left_margin,
.set_top_margin = osd_set_top_margin,
+ .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,
};
static int osd_probe(struct platform_device *pdev)
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index 87eef9b..787a3ca 100644
--- a/drivers/media/platform/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <linux/slab.h>
+#include <linux/v4l2-dv-timings.h>
#include <mach/hardware.h>
#include <mach/mux.h>
@@ -31,6 +32,7 @@
#include <linux/io.h>
+#include <media/v4l2-mediabus.h>
#include <media/davinci/vpbe_types.h>
#include <media/davinci/vpbe_venc.h>
#include <media/davinci/vpss.h>
@@ -66,6 +68,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;
@@ -539,6 +542,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) {
@@ -547,6 +554,42 @@ 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;
+
+ 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 de59364..3df34c6 100644
--- a/include/media/davinci/vpbe_osd.h
+++ b/include/media/davinci/vpbe_osd.h
@@ -327,14 +327,59 @@ 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,
@@ -343,6 +388,13 @@ struct vpbe_osd_ops {
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 (*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);
int (*set_vid_expansion)(struct osd_state *sd,
enum osd_h_exp_ratio h_exp,
enum osd_v_exp_ratio v_exp);
@@ -352,6 +404,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 476fafc..98d73a9 100644
--- a/include/media/davinci/vpbe_venc.h
+++ b/include/media/davinci/vpbe_venc.h
@@ -29,6 +29,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 {
int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type,
int field);
@@ -42,6 +60,9 @@ struct venc_platform_data {
enum venc_ioctls {
VENC_GET_FLD = 1,
+ VENC_REG_CALLBACK,
+ VENC_UNREG_CALLBACK,
+ VENC_INTERRUPT,
};
/* exported functions */
--
1.7.4.1
^ permalink raw reply related
* [PATCH 1/6] media: davinci: vpbe: fix checkpatch warning for CamelCase
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366804808-22720-1-git-send-email-prabhakar.csengg@gmail.com>
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
This patch fixes checkpatch warning to avoid CamelCase.
Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
---
drivers/media/platform/davinci/vpbe_display.c | 2 +-
drivers/media/platform/davinci/vpbe_osd.c | 24 ++++++++++++------------
include/media/davinci/vpbe_osd.h | 4 ++--
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 1802f11..1c4ba89 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -929,7 +929,7 @@ static int vpbe_display_s_fmt(struct file *file, void *priv,
cfg->interlaced = vpbe_dev->current_timings.interlaced;
if (V4L2_PIX_FMT_UYVY = pixfmt->pixelformat)
- cfg->pixfmt = PIXFMT_YCbCrI;
+ cfg->pixfmt = PIXFMT_YCBCRI;
/* Change of the default pixel format for both video windows */
if (V4L2_PIX_FMT_NV12 = pixfmt->pixelformat) {
diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index 396a51c..6ed82e8 100644
--- a/drivers/media/platform/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -119,7 +119,7 @@ static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val,
#define is_rgb_pixfmt(pixfmt) \
(((pixfmt) = PIXFMT_RGB565) || ((pixfmt) = PIXFMT_RGB888))
#define is_yc_pixfmt(pixfmt) \
- (((pixfmt) = PIXFMT_YCbCrI) || ((pixfmt) = PIXFMT_YCrCbI) || \
+ (((pixfmt) = PIXFMT_YCBCRI) || ((pixfmt) = PIXFMT_YCRCBI) || \
((pixfmt) = PIXFMT_NV12))
#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X
#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5)
@@ -360,8 +360,8 @@ static void _osd_enable_color_key(struct osd_state *sd,
osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
OSD_TRANSPVALL);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
if (sd->vpbe_type = VPBE_VERSION_3)
osd_modify(sd, OSD_TRANSPVALU_Y, colorkey,
OSD_TRANSPVALU);
@@ -813,8 +813,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
if (osd->vpbe_type = VPBE_VERSION_1)
bad_config = !is_vid_win(layer);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
bad_config = !is_vid_win(layer);
break;
case PIXFMT_RGB888:
@@ -950,9 +950,9 @@ static void _osd_set_cbcr_order(struct osd_state *sd,
* The caller must ensure that all windows using YC pixfmt use the same
* Cb/Cr order.
*/
- if (pixfmt = PIXFMT_YCbCrI)
+ if (pixfmt = PIXFMT_YCBCRI)
osd_clear(sd, OSD_MODE_CS, OSD_MODE);
- else if (pixfmt = PIXFMT_YCrCbI)
+ else if (pixfmt = PIXFMT_YCRCBI)
osd_set(sd, OSD_MODE_CS, OSD_MODE);
}
@@ -981,8 +981,8 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
_osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
break;
default:
@@ -1128,8 +1128,8 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
_osd_enable_rgb888_pixblend(sd,
OSDWIN_OSD1);
break;
- case PIXFMT_YCbCrI:
- case PIXFMT_YCrCbI:
+ case PIXFMT_YCBCRI:
+ case PIXFMT_YCRCBI:
winmd | (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
break;
@@ -1508,7 +1508,7 @@ static int osd_initialize(struct osd_state *osd)
_osd_init(osd);
/* set default Cb/Cr order */
- osd->yc_pixfmt = PIXFMT_YCbCrI;
+ osd->yc_pixfmt = PIXFMT_YCBCRI;
if (osd->vpbe_type = VPBE_VERSION_3) {
/*
diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h
index 42628fc..de59364 100644
--- a/include/media/davinci/vpbe_osd.h
+++ b/include/media/davinci/vpbe_osd.h
@@ -82,9 +82,9 @@ enum osd_pix_format {
PIXFMT_4BPP,
PIXFMT_8BPP,
PIXFMT_RGB565,
- PIXFMT_YCbCrI,
+ PIXFMT_YCBCRI,
PIXFMT_RGB888,
- PIXFMT_YCrCbI,
+ PIXFMT_YCRCBI,
PIXFMT_NV12,
PIXFMT_OSD_ATTR,
};
--
1.7.4.1
^ permalink raw reply related
* [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform
From: Prabhakar Lad @ 2013-04-24 12:12 UTC (permalink / raw)
To: linux-arm-kernel
From: Lad, Prabhakar <prabhakar.csengg@gmail.com>
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.
Lad, Prabhakar (6):
media: davinci: vpbe: fix checkpatch warning for CamelCase
media: davinci: vpbe: enable vpbe for fbdev addition
davinci: vpbe: add fbdev driver
ARM: davinci: dm355: enable fbdev driver
ARM: davinci: dm365: enable fbdev driver
ARM: davinci: dm644x: enable fbdev driver
arch/arm/mach-davinci/dm355.c | 24 +-
arch/arm/mach-davinci/dm365.c | 10 +
arch/arm/mach-davinci/dm644x.c | 10 +
drivers/media/platform/davinci/vpbe_display.c | 8 +-
drivers/media/platform/davinci/vpbe_osd.c | 820 ++++++++-
drivers/media/platform/davinci/vpbe_venc.c | 43 +
drivers/video/Kconfig | 12 +
drivers/video/Makefile | 1 +
drivers/video/davincifb.c | 2523 +++++++++++++++++++++++++
drivers/video/davincifb.h | 194 ++
include/media/davinci/vpbe_osd.h | 66 +-
include/media/davinci/vpbe_venc.h | 21 +
12 files changed, 3702 insertions(+), 30 deletions(-)
create mode 100644 drivers/video/davincifb.c
create mode 100644 drivers/video/davincifb.h
--
1.7.4.1
^ permalink raw reply
* [PATCH V5 5/5] fbcon: queue work on power efficient wq
From: Viresh Kumar @ 2013-04-24 11:54 UTC (permalink / raw)
To: tj
Cc: davem, airlied, axboe, tglx, peterz, mingo, rostedt,
linux-rt-users, linux-kernel, robin.randhawa, Steve.Bannister,
Liviu.Dudau, charles.garcia-tobin, arvind.chauhan, linaro-kernel,
patches, Viresh Kumar, linux-fbdev
In-Reply-To: <cover.1366803121.git.viresh.kumar@linaro.org>
fbcon uses workqueues and it has no real dependency of scheduling these on the
cpu which scheduled them.
On a idle system, it is observed that and idle cpu wakes up many times just to
service this work. It would be better if we can schedule it on a cpu which the
scheduler believes to be the most appropriate one.
This patch replaces system_wq with system_power_efficient_wq.
Cc: Dave Airlie <airlied@redhat.com>
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/video/console/fbcon.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3cd6759..0cae83d 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -404,7 +404,7 @@ static void cursor_timer_handler(unsigned long dev_addr)
struct fb_info *info = (struct fb_info *) dev_addr;
struct fbcon_ops *ops = info->fbcon_par;
- schedule_work(&info->queue);
+ queue_work(system_power_efficient_wq, &info->queue);
mod_timer(&ops->cursor_timer, jiffies + HZ/5);
}
--
1.7.12.rc2.18.g61b472e
^ permalink raw reply related
* Re: [PATCH 0/2] drivers/video: mxs-fb: build fixes
From: Shawn Guo @ 2013-04-24 11:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366790894-20426-1-git-send-email-mpa@pengutronix.de>
On Wed, Apr 24, 2013 at 10:08:12AM +0200, Markus Pargmann wrote:
> Hi,
>
> mxs-fb commit
>
> 669406534b4abb827d1bdc39bb5e2d5255818ae2 video: mxsfb: get display timings from device tree
>
> creates a build failure together with those commits:
>
> a38884f681a4d044befd30d9f3d19a0821bae63a videomode: simplify videomode Kconfig and Makefile
> 6cd2c7db41eab204b6474534df4ca68a7dc53d86 videomode: videomode_from_timing work
>
> All of them are in linux-next, so mxs-fb fails to build there.
Fabio already had a patch [1] for that. I will send it mainline during
3.10-rc.
Shawn
[1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/230938
^ permalink raw reply
* Re: [PATCH 0/2] drivers/video: mxs-fb: build fixes
From: Markus Pargmann @ 2013-04-24 9:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366790894-20426-1-git-send-email-mpa@pengutronix.de>
On Wed, Apr 24, 2013 at 10:08:12AM +0200, Markus Pargmann wrote:
> Hi,
>
> mxs-fb commit
>
> 669406534b4abb827d1bdc39bb5e2d5255818ae2 video: mxsfb: get display timings from device tree
>
> creates a build failure together with those commits:
>
> a38884f681a4d044befd30d9f3d19a0821bae63a videomode: simplify videomode Kconfig and Makefile
> 6cd2c7db41eab204b6474534df4ca68a7dc53d86 videomode: videomode_from_timing work
>
> All of them are in linux-next, so mxs-fb fails to build there.
>
> Regards,
>
> Markus
>
>
>
Sorry for the noise. This was already fixed and queued for 3.10-rc.
Regards,
Markus
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH 2/2] drivers/video: mxs-fb: Fix build, use renamed function
From: Markus Pargmann @ 2013-04-24 8:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366791772-11133-1-git-send-email-mpa@pengutronix.de>
Kernel build fails with commit 669406534b4abb827d1bdc39bb5e2d5255818ae2
This patch renames videomode_from_timing to videomode_from_timings and
vm.data_flags to vm.flags.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
drivers/video/mxsfb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 1b2c26d..d78827e 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -777,16 +777,16 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
struct videomode vm;
struct fb_videomode fb_vm;
- ret = videomode_from_timing(timings, &vm, i);
+ ret = videomode_from_timings(timings, &vm, i);
if (ret < 0)
goto put_timings_node;
ret = fb_videomode_from_videomode(&vm, &fb_vm);
if (ret < 0)
goto put_timings_node;
- if (vm.data_flags & DISPLAY_FLAGS_DE_HIGH)
+ if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
- if (vm.data_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
fb_add_videomode(&fb_vm, &fb_info->modelist);
}
--
1.8.1.5
^ permalink raw reply related
* [PATCH 1/2] drivers/video: Kconfig, fix mxsfb build
From: Markus Pargmann @ 2013-04-24 8:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366791772-11133-1-git-send-email-mpa@pengutronix.de>
Kernel build fails with commit 669406534b4abb827d1bdc39bb5e2d5255818ae2
This patch replaces OF_VIDEOMODE symbol by VIDEOMODE_HELPERS.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
drivers/video/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d8ecc52..6246056 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2429,7 +2429,7 @@ config FB_MXS
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_MODE_HELPERS
- select OF_VIDEOMODE
+ select VIDEOMODE_HELPERS
help
Framebuffer support for the MXS SoC.
--
1.8.1.5
^ permalink raw reply related
* [PATCH 0/2] drivers/video: mxs-fb: build fixes
From: Markus Pargmann @ 2013-04-24 8:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366790894-20426-1-git-send-email-mpa@pengutronix.de>
Sorry, I messed up the email addresses in the last two patches, the following
two are exactly the same just with the correct addresses.
Regards,
Markus
^ permalink raw reply
* [PATCH 2/2] drivers/video: mxs-fb: Fix build, use renamed function
From: Markus Pargmann @ 2013-04-24 8:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366790894-20426-1-git-send-email-mpa@pengutronix.de>
From: Markus Pargmann <mpargmann@allfex.org>
Kernel build fails with commit 669406534b4abb827d1bdc39bb5e2d5255818ae2
This patch renames videomode_from_timing to videomode_from_timings and
vm.data_flags to vm.flags.
Signed-off-by: Markus Pargmann <mpargmann@allfex.org>
---
drivers/video/mxsfb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 1b2c26d..d78827e 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -777,16 +777,16 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
struct videomode vm;
struct fb_videomode fb_vm;
- ret = videomode_from_timing(timings, &vm, i);
+ ret = videomode_from_timings(timings, &vm, i);
if (ret < 0)
goto put_timings_node;
ret = fb_videomode_from_videomode(&vm, &fb_vm);
if (ret < 0)
goto put_timings_node;
- if (vm.data_flags & DISPLAY_FLAGS_DE_HIGH)
+ if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
- if (vm.data_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
fb_add_videomode(&fb_vm, &fb_info->modelist);
}
--
1.8.1.5
^ permalink raw reply related
* [PATCH 1/2] drivers/video: Kconfig, fix mxsfb build
From: Markus Pargmann @ 2013-04-24 8:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1366790894-20426-1-git-send-email-mpa@pengutronix.de>
From: Markus Pargmann <mpargmann@allfex.org>
Kernel build fails with commit 669406534b4abb827d1bdc39bb5e2d5255818ae2
This patch replaces OF_VIDEOMODE symbol by VIDEOMODE_HELPERS.
Signed-off-by: Markus Pargmann <mpargmann@allfex.org>
---
drivers/video/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d8ecc52..6246056 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2429,7 +2429,7 @@ config FB_MXS
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_MODE_HELPERS
- select OF_VIDEOMODE
+ select VIDEOMODE_HELPERS
help
Framebuffer support for the MXS SoC.
--
1.8.1.5
^ permalink raw reply related
* [PATCH 0/2] drivers/video: mxs-fb: build fixes
From: Markus Pargmann @ 2013-04-24 8:08 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
mxs-fb commit
669406534b4abb827d1bdc39bb5e2d5255818ae2 video: mxsfb: get display timings from device tree
creates a build failure together with those commits:
a38884f681a4d044befd30d9f3d19a0821bae63a videomode: simplify videomode Kconfig and Makefile
6cd2c7db41eab204b6474534df4ca68a7dc53d86 videomode: videomode_from_timing work
All of them are in linux-next, so mxs-fb fails to build there.
Regards,
Markus
^ permalink raw reply
* Re: [PATCH 07/11] fbdev/sa1100fb: use vm_iomap_memory()
From: Russell King - ARM Linux @ 2013-04-23 18:53 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1366699018-5439-7-git-send-email-tomi.valkeinen@ti.com>
On Tue, Apr 23, 2013 at 09:36:54AM +0300, Tomi Valkeinen wrote:
> Use vm_iomap_memory() instead of [io_]remap_pfn_range().
> vm_iomap_memory() gives us much simpler API to map memory to userspace,
> and reduces possibilities for bugs.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Thanks.
^ permalink raw reply
* [PATCH] Handle efifb with no lfb_base better.
From: Peter Jones @ 2013-04-23 15:23 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: Josh Boyer, linux-fbdev, linux-kernel, Peter Jones
Right now we get a WARN from platform_device_unregister() because our
platform_device has no ->release function. This is clearly wrong, but
we should be warning so we can figure out what happened, as this failure
results in bug reports. So WARN() about the real problem, and use the
registration function that gives us a default release() function.
This fixes the tracback reported at
https://bugzilla.redhat.com/show_bug.cgi?id„0621 , though it does not
fix the actual /problem/ the user is seeing.
Signed-off-by: Peter Jones <pjones@redhat.com>
---
drivers/video/efifb.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 50fe668..390b61b 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -285,6 +285,7 @@ static void efifb_destroy(struct fb_info *info)
{
if (info->screen_base)
iounmap(info->screen_base);
+ fb_dealloc_cmap(&info->cmap);
if (request_mem_succeeded)
release_mem_region(info->apertures->ranges[0].base,
info->apertures->ranges[0].size);
@@ -382,6 +383,8 @@ static int __init efifb_probe(struct platform_device *dev)
if (!screen_info.pages)
screen_info.pages = 1;
if (!screen_info.lfb_base) {
+ WARN(1, KERN_WARNING, "invalid framebuffer address for "
+ "device '%s'\n", dev_name(dev));
printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
return -ENODEV;
}
@@ -544,9 +547,7 @@ static struct platform_driver efifb_driver = {
},
};
-static struct platform_device efifb_device = {
- .name = "efifb",
-};
+static struct platform_device *efifb_device;
static int __init efifb_init(void)
{
@@ -571,9 +572,9 @@ static int __init efifb_init(void)
if (!screen_info.lfb_linelength)
return -ENODEV;
- ret = platform_device_register(&efifb_device);
- if (ret)
- return ret;
+ efifb_device = platform_device_register_simple("efifb", 0, NULL, 0);
+ if (IS_ERROR(efifb_device))
+ return PTR_ERR(efifb_device);
/*
* This is not just an optimization. We will interfere
@@ -582,7 +583,7 @@ static int __init efifb_init(void)
*/
ret = platform_driver_probe(&efifb_driver, efifb_probe);
if (ret) {
- platform_device_unregister(&efifb_device);
+ platform_device_unregister(efifb_device);
return ret;
}
--
1.8.1.4
^ permalink raw reply related
* [PATCH 11/11] fbdev: improve fb_mmap bounds checks
From: Tomi Valkeinen @ 2013-04-23 6:36 UTC (permalink / raw)
To: linux-fbdev, linux-kernel
Cc: Tomi Valkeinen, Steve Glendinning, Bernie Thompson
In-Reply-To: <1366699018-5439-1-git-send-email-tomi.valkeinen@ti.com>
Improve fb_mmap bounds checks in gbefb, smscufx, udlfb and vfb drivers to
prevent possible uint overflows.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Steve Glendinning <steve.glendinning@smsc.com>
Cc: Bernie Thompson <bernie@plugable.com>
---
drivers/video/gbefb.c | 4 +++-
drivers/video/smscufx.c | 6 +++++-
drivers/video/udlfb.c | 6 +++++-
drivers/video/vfb.c | 7 +++++--
4 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index bda5e39..ceab370 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -1016,7 +1016,9 @@ static int gbefb_mmap(struct fb_info *info,
/* check range */
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
- if (offset + size > gbe_mem_size)
+ if (size > gbe_mem_size)
+ return -EINVAL;
+ if (offset > gbe_mem_size - size)
return -EINVAL;
/* remap using the fastest write-through mode on architecture */
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
index 97bd662..b2b33fc 100644
--- a/drivers/video/smscufx.c
+++ b/drivers/video/smscufx.c
@@ -782,7 +782,11 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- if (offset + size > info->fix.smem_len)
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (size > info->fix.smem_len)
+ return -EINVAL;
+ if (offset > info->fix.smem_len - size)
return -EINVAL;
pos = (unsigned long)info->fix.smem_start + offset;
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 86d449e..ec03e72 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -324,7 +324,11 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- if (offset + size > info->fix.smem_len)
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (size > info->fix.smem_len)
+ return -EINVAL;
+ if (offset > info->fix.smem_len - size)
return -EINVAL;
pos = (unsigned long)info->fix.smem_start + offset;
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 8bc1f93..ee5985e 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -420,9 +420,12 @@ static int vfb_mmap(struct fb_info *info,
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- if (offset + size > info->fix.smem_len) {
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (size > info->fix.smem_len)
+ return -EINVAL;
+ if (offset > info->fix.smem_len - size)
return -EINVAL;
- }
pos = (unsigned long)info->fix.smem_start + offset;
--
1.7.10.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