2013-04-24 12:00:24

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform

From: Lad, Prabhakar <[email protected]>

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


2013-04-24 12:00:51

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 1/6] media: davinci: vpbe: fix checkpatch warning for CamelCase

From: Lad, Prabhakar <[email protected]>

This patch fixes checkpatch warning to avoid CamelCase.

Signed-off-by: Lad, Prabhakar <[email protected]>
---
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

2013-04-24 12:01:12

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 2/6] media: davinci: vpbe: enable vpbe for fbdev addition

From: Lad, Prabhakar <[email protected]>

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 <[email protected]>
---
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

2013-04-24 12:01:28

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 3/6] davinci: vpbe: add fbdev driver

From: Lad, Prabhakar <[email protected]>

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 <[email protected]>
---
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 ([email protected]), 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:osd0=720x480x16@0,0:osd1=720x480: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

2013-04-24 12:01:38

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 4/6] ARM: davinci: dm355: enable fbdev driver

From: Lad, Prabhakar <[email protected]>

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 <[email protected]>
---
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

2013-04-24 12:01:44

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 6/6] ARM: davinci: dm644x: enable fbdev driver

From: Lad, Prabhakar <[email protected]>

This patch enables fbdev driver by creating fbdev device and register it.

Signed-off-by: Lad, Prabhakar <[email protected]>
---
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

2013-04-24 12:02:14

by Lad, Prabhakar

[permalink] [raw]
Subject: [PATCH 5/6] ARM: davinci: dm365: enable fbdev driver

From: Lad, Prabhakar <[email protected]>

This patch enables fbdev driver by creating fbdev device and register it.

Signed-off-by: Lad, Prabhakar <[email protected]>
---
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

2013-04-24 21:02:17

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform

Hi Prabhakar,

Thank you for the patch.

On Wednesday 24 April 2013 17:30:02 Prabhakar Lad wrote:
> From: Lad, Prabhakar <[email protected]>
>
> 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

2013-04-26 05:46:51

by Lad, Prabhakar

[permalink] [raw]
Subject: Re: [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform

Hi Laurent,

On Thu, Apr 25, 2013 at 2:32 AM, Laurent Pinchart
<[email protected]> wrote:
> Hi Prabhakar,
>
> Thank you for the patch.
>
> On Wednesday 24 April 2013 17:30:02 Prabhakar Lad wrote:
>> From: Lad, Prabhakar <[email protected]>
>>
>> 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 ? :-)
>
I did go through the KMS model (thanks for pointing to your work and the video)
and it looks like this would require a fair amount of development, at this point
of time I would go with the current implementation and revisit on KMS model
at later point of time.

Regards,
--Prabhakar

2013-05-03 09:56:20

by Sekhar Nori

[permalink] [raw]
Subject: Re: [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform

On 4/26/2013 11:16 AM, Prabhakar Lad wrote:
> Hi Laurent,
>
> On Thu, Apr 25, 2013 at 2:32 AM, Laurent Pinchart
> <[email protected]> wrote:
>> Hi Prabhakar,
>>
>> Thank you for the patch.
>>
>> On Wednesday 24 April 2013 17:30:02 Prabhakar Lad wrote:
>>> From: Lad, Prabhakar <[email protected]>
>>>
>>> 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 ? :-)
>>
> I did go through the KMS model (thanks for pointing to your work and the video)
> and it looks like this would require a fair amount of development, at this point
> of time I would go with the current implementation and revisit on KMS model
> at later point of time.

But I doubt you will be able to sneak a new fbdev driver through. Last
time I heard, Andrew is only taking in fixes not new features.

Thanks,
Sekhar

2013-05-03 10:16:09

by Lad, Prabhakar

[permalink] [raw]
Subject: Re: [PATCH 0/6] Davinci fbdev driver and enable it for DMx platform

On Fri, May 3, 2013 at 3:25 PM, Sekhar Nori <[email protected]> wrote:
> On 4/26/2013 11:16 AM, Prabhakar Lad wrote:
>> Hi Laurent,
>>
>> On Thu, Apr 25, 2013 at 2:32 AM, Laurent Pinchart
>> <[email protected]> wrote:
>>> Hi Prabhakar,
>>>
>>> Thank you for the patch.
>>>
>>> On Wednesday 24 April 2013 17:30:02 Prabhakar Lad wrote:
>>>> From: Lad, Prabhakar <[email protected]>
>>>>
>>>> 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 ? :-)
>>>
>> I did go through the KMS model (thanks for pointing to your work and the video)
>> and it looks like this would require a fair amount of development, at this point
>> of time I would go with the current implementation and revisit on KMS model
>> at later point of time.
>
> But I doubt you will be able to sneak a new fbdev driver through. Last
> time I heard, Andrew is only taking in fixes not new features.
>
Then we have no choice left and go with KMS driver itself though it would take
some time since KMS is a new inclusion into DRM.

Regards,
--Prabhakar