From 826edf9b2b9af7b9bc32f4363724af174911175c Mon Sep 17 00:00:00 2001
From: Tim Yamin <plasm@roo.me.uk>
Date: Tue, 7 Apr 2009 11:52:35 -0700
Subject: [PATCH] DSS2: Add YUV VRFB rotation support
This is a rebased version of Hardik Shah's patch with a few additional
tweaks from me.
Signed-off-by: Tim Yamin <plasm@roo.me.uk>
---
arch/arm/plat-omap/include/mach/display.h | 6 ++
arch/arm/plat-omap/vrfb.c | 4 +-
drivers/video/omap2/dss/dispc.c | 87 ++++++++++++++++++++++++++--
drivers/video/omap2/dss/dss.h | 1 +
drivers/video/omap2/dss/manager.c | 1 +
drivers/video/omap2/omapfb/omapfb-main.c | 66 +++++++++++-----------
drivers/video/omap2/omapfb/omapfb.h | 7 +--
7 files changed, 126 insertions(+), 46 deletions(-)
@@ -341,6 +341,11 @@ enum omap_dss_overlay_managers {
struct omap_overlay_manager;
+enum omap_dss_rotation_type {
+ OMAP_DSS_ROT_DMA = 0,
+ OMAP_DSS_ROT_VRFB = 1,
+};
+
struct omap_overlay_info {
bool enabled;
@@ -351,6 +356,7 @@ struct omap_overlay_info {
u16 height;
enum omap_color_mode color_mode;
u8 rotation;
+ enum omap_dss_rotation_type rotation_type;
bool mirror;
u16 pos_x;
@@ -61,8 +61,10 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
width, height, bytespp);
if (bytespp == 4)
+ {
pixel_size_exp = 2;
- else if (bytespp == 2)
+ width >>= 1;
+ } else if (bytespp == 2)
pixel_size_exp = 1;
else
BUG();
@@ -1106,7 +1106,7 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
case 0: vidrot = 0; break;
case 1: vidrot = 1; break;
case 2: vidrot = 2; break;
- case 3: vidrot = 1; break;
+ case 3: vidrot = 3; break;
}
}
@@ -1134,7 +1134,70 @@ static s32 pixinc(int pixels, u8 ps)
BUG();
}
-static void calc_rotation_offset(u8 rotation, bool mirror,
+static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
+ u16 screen_width,
+ u16 width, u16 height,
+ enum omap_color_mode color_mode, bool fieldmode,
+ unsigned *offset0, unsigned *offset1,
+ s32 *row_inc, s32 *pix_inc)
+{
+ u8 ps;
+
+ switch (color_mode) {
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_ARGB16:
+ ps = 2;
+ break;
+
+ case OMAP_DSS_COLOR_RGB24P:
+ ps = 3;
+ break;
+
+ case OMAP_DSS_COLOR_RGB24U:
+ case OMAP_DSS_COLOR_ARGB32:
+ case OMAP_DSS_COLOR_RGBA32:
+ case OMAP_DSS_COLOR_RGBX32:
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ ps = 4;
+ break;
+
+ default:
+ BUG();
+ return;
+ }
+
+ DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
+ width, height);
+ switch (rotation + mirror * 4) {
+ case 0:
+ case 2:
+ /*
+ * If the pixel format is YUV or UYVY divide the width
+ * of the image by 2.
+ */
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ width = width >> 1;
+ case 1:
+ case 3:
+ *offset0 = 0;
+ if (fieldmode)
+ *offset1 = screen_width * ps;
+ else
+ *offset1 = 0;
+
+ *row_inc = pixinc(1 + (screen_width - width) +
+ (fieldmode ? screen_width : 0),
+ ps);
+ *pix_inc = pixinc(1, ps);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static void calc_dma_rotation_offset(u8 rotation, bool mirror,
u16 screen_width,
u16 width, u16 height,
enum omap_color_mode color_mode, bool fieldmode,
@@ -1357,6 +1420,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode,
bool ilace,
+ enum omap_dss_rotation_type rotation_type,
u8 rotation, int mirror)
{
const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
@@ -1463,10 +1527,16 @@ static int _dispc_setup_plane(enum omap_plane plane,
return -EINVAL;
}
- calc_rotation_offset(rotation, mirror,
- screen_width, width, frame_height, color_mode,
- fieldmode,
- &offset0, &offset1, &row_inc, &pix_inc);
+ if (rotation_type == OMAP_DSS_ROT_DMA)
+ calc_dma_rotation_offset(rotation, mirror,
+ screen_width, width, height, color_mode,
+ fieldmode,
+ &offset0, &offset1, &row_inc, &pix_inc);
+ else
+ calc_vrfb_rotation_offset(rotation, mirror,
+ screen_width, width, height, color_mode,
+ fieldmode,
+ &offset0, &offset1, &row_inc, &pix_inc);
DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
offset0, offset1, row_inc, pix_inc);
@@ -2879,6 +2949,7 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode,
bool ilace,
+ enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror)
{
int r = 0;
@@ -2899,6 +2970,7 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out,
width, height,
out_width, out_height,
color_mode, ilace,
+ rotation_type,
rotation, mirror);
enable_clocks(0);
@@ -3112,7 +3184,8 @@ void dispc_setup_partial_planes(struct omap_display *display,
pw, ph,
pow, poh,
pi->color_mode, 0,
- pi->rotation, // XXX rotation probably wrong
+ pi->rotation_type,
+ pi->rotation,
pi->mirror);
dispc_enable_plane(ovl->id, 1);
@@ -269,6 +269,7 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode,
bool ilace,
+ enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror);
void dispc_go(enum omap_channel channel);
@@ -395,6 +395,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
outh,
ovl->info.color_mode,
ilace,
+ ovl->info.rotation_type,
ovl->info.rotation,
ovl->info.mirror);
@@ -176,15 +176,9 @@ static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi)
{
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
- unsigned offset;
- int rot;
-
- rot = ofbi->rotation;
-
- offset = omapfb_get_vrfb_offset(ofbi, rot);
-
- return ofbi->region.vrfb.paddr[rot] + offset;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
+ return ofbi->region.vrfb.paddr[ofbi->rotation]
+ + omapfb_get_vrfb_offset(ofbi, ofbi->rotation);
} else {
return ofbi->region.paddr;
}
@@ -192,7 +186,7 @@ static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi)
u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
{
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.paddr[0];
else
return ofbi->region.paddr;
@@ -200,7 +194,7 @@ u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
{
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.vaddr[0];
else
return ofbi->region.vaddr;
@@ -383,7 +377,7 @@ void set_fb_fix(struct fb_info *fbi)
fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
/* used by mmap in fbmem.c */
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
fix->line_length =
(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
else
@@ -419,11 +413,21 @@ void set_fb_fix(struct fb_info *fbi)
fix->xpanstep = 1;
fix->ypanstep = 1;
- if (rg->size) {
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
- omap_vrfb_setup(&rg->vrfb, rg->paddr,
- var->xres_virtual, var->yres_virtual,
- var->bits_per_pixel >> 3);
+ if (rg->size && ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
+ switch(var->nonstd)
+ {
+ case OMAPFB_COLOR_YUV422:
+ case OMAPFB_COLOR_YUV420:
+ case OMAPFB_COLOR_YUY422:
+ omap_vrfb_setup(&rg->vrfb, rg->paddr,
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel >> 2);
+ break;
+ default:
+ omap_vrfb_setup(&rg->vrfb, rg->paddr,
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel >> 3);
+ }
}
}
@@ -512,7 +516,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
if (var->yres > var->yres_virtual)
var->yres = var->yres_virtual;
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
line_size = OMAP_VRFB_LINE_LEN * bytespp;
else
line_size = var->xres_virtual * bytespp;
@@ -534,7 +538,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
if (line_size * var->yres_virtual > max_frame_size) {
DBG("can't fit FB into memory, reducing x\n");
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB)
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return -EINVAL;
var->xres_virtual = max_frame_size / var->yres_virtual /
@@ -657,7 +661,7 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
struct omap_overlay_info info;
int xres, yres;
int screen_width;
- int rot, mirror;
+ int mirror;
DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
posx, posy, outw, outh);
@@ -673,7 +677,7 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
offset = ((var->yoffset * var->xres_virtual +
var->xoffset) * var->bits_per_pixel) >> 3;
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
data_start_p = omapfb_get_region_rot_paddr(ofbi);
data_start_v = NULL;
} else {
@@ -696,13 +700,10 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
ovl->get_overlay_info(ovl, &info);
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
- rot = 0;
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
mirror = 0;
- } else {
- rot = ofbi->rotation;
+ else
mirror = ofbi->mirror;
- }
info.paddr = data_start_p;
info.vaddr = data_start_v;
@@ -710,7 +711,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
info.width = xres;
info.height = yres;
info.color_mode = mode;
- info.rotation = rot;
+ info.rotation_type = ofbi->rotation_type;
+ info.rotation = ofbi->rotation;
info.mirror = mirror;
info.pos_x = posx;
@@ -1106,7 +1108,7 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
if (rg->vaddr)
iounmap(rg->vaddr);
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
/* unmap the 0 angle rotation */
if (rg->vrfb.vaddr[0]) {
iounmap(rg->vrfb.vaddr[0]);
@@ -1166,7 +1168,7 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
return -ENOMEM;
}
- if (ofbi->rotation_type != OMAPFB_ROT_VRFB) {
+ if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
vaddr = ioremap_wc(paddr, size);
if (!vaddr) {
@@ -1245,7 +1247,7 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
display->get_resolution(display, &w, &h);
- if (ofbi->rotation_type == OMAPFB_ROT_VRFB) {
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
#ifdef DEBUG
int oldw = w, oldh = h;
#endif
@@ -1602,8 +1604,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->id = i;
/* assign these early, so that fb alloc can use them */
- ofbi->rotation_type = def_vrfb ? OMAPFB_ROT_VRFB :
- OMAPFB_ROT_DMA;
+ ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
+ OMAP_DSS_ROT_DMA;
ofbi->rotation = def_rotate;
ofbi->mirror = def_mirror;
@@ -51,11 +51,6 @@ struct omapfb2_mem_region {
bool map; /* kernel mapped by the driver */
};
-enum omapfb_rotation_type {
- OMAPFB_ROT_DMA = 0,
- OMAPFB_ROT_VRFB = 1,
-};
-
/* appended to fb_info */
struct omapfb_info {
int id;
@@ -64,7 +59,7 @@ struct omapfb_info {
int num_overlays;
struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
struct omapfb2_device *fbdev;
- enum omapfb_rotation_type rotation_type;
+ enum omap_dss_rotation_type rotation_type;
u8 rotation;
bool mirror;
};
--
1.5.6.3