Skip to content

Commit

Permalink
omapfb: add support for rotation on the Blizzard LCD ctrl
Browse files Browse the repository at this point in the history
The LCD controller (EPSON S1D13744) supports rotation (0, 90, 180 and 270
degrees) on hardware just setting the bits 0 and 1 of 0x28 register (LCD
Panel Configuration Register).  Now it is possible to use this caps only
setting the angle degree on var rotate of fb_var_screeninfo using the
FBIOPUT_VSCREENINFO ioctl.

Fixed-by: Siarhei Siamashka <siarhei.siamashka@nokia.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@openbossa.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Imre Deak <imre.deak@nokia.com>
Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Rodrigo Vivi authored and Linus Torvalds committed Sep 23, 2009
1 parent 8fea884 commit 2f21a62
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 19 deletions.
91 changes: 86 additions & 5 deletions drivers/video/omap/blizzard.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#define BLIZZARD_CLK_SRC 0x0e
#define BLIZZARD_MEM_BANK0_ACTIVATE 0x10
#define BLIZZARD_MEM_BANK0_STATUS 0x14
#define BLIZZARD_PANEL_CONFIGURATION 0x28
#define BLIZZARD_HDISP 0x2a
#define BLIZZARD_HNDP 0x2c
#define BLIZZARD_VDISP0 0x2e
Expand Down Expand Up @@ -162,6 +163,10 @@ struct blizzard_struct {
int vid_scaled;
int last_color_mode;
int zoom_on;
int zoom_area_gx1;
int zoom_area_gx2;
int zoom_area_gy1;
int zoom_area_gy2;
int screen_width;
int screen_height;
unsigned te_connected:1;
Expand Down Expand Up @@ -513,6 +518,13 @@ static int do_full_screen_update(struct blizzard_request *req)
return REQ_PENDING;
}

static int check_1d_intersect(int a1, int a2, int b1, int b2)
{
if (a2 <= b1 || b2 <= a1)
return 0;
return 1;
}

/* Setup all planes with an overlapping area with the update window. */
static int do_partial_update(struct blizzard_request *req, int plane,
int x, int y, int w, int h,
Expand All @@ -525,6 +537,7 @@ static int do_partial_update(struct blizzard_request *req, int plane,
int color_mode;
int flags;
int zoom_off;
int have_zoom_for_this_update = 0;

/* Global coordinates, relative to pixel 0,0 of the LCD */
gx1 = x + blizzard.plane[plane].pos_x;
Expand All @@ -544,10 +557,6 @@ static int do_partial_update(struct blizzard_request *req, int plane,
gx2_out = gx1_out + w_out;
gy2_out = gy1_out + h_out;
}
zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 &&
w == blizzard.screen_width && h == blizzard.screen_height;
blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) ||
(w < w_out || h < h_out);

for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
struct plane_info *p = &blizzard.plane[i];
Expand Down Expand Up @@ -653,8 +662,49 @@ static int do_partial_update(struct blizzard_request *req, int plane,
else
disable_tearsync();

if ((gx2_out - gx1_out) != (gx2 - gx1) ||
(gy2_out - gy1_out) != (gy2 - gy1))
have_zoom_for_this_update = 1;

/* 'background' type of screen update (as opposed to 'destructive')
can be used to disable scaling if scaling is active */
zoom_off = blizzard.zoom_on && !have_zoom_for_this_update &&
(gx1_out == 0) && (gx2_out == blizzard.screen_width) &&
(gy1_out == 0) && (gy2_out == blizzard.screen_height) &&
(gx1 == 0) && (gy1 == 0);

if (blizzard.zoom_on && !have_zoom_for_this_update && !zoom_off &&
check_1d_intersect(blizzard.zoom_area_gx1, blizzard.zoom_area_gx2,
gx1_out, gx2_out) &&
check_1d_intersect(blizzard.zoom_area_gy1, blizzard.zoom_area_gy2,
gy1_out, gy2_out)) {
/* Previous screen update was using scaling, current update
* is not using it. Additionally, current screen update is
* going to overlap with the scaled area. Scaling needs to be
* disabled in order to avoid 'magnifying glass' effect.
* Dummy setup of background window can be used for this.
*/
set_window_regs(0, 0, blizzard.screen_width,
blizzard.screen_height,
0, 0, blizzard.screen_width,
blizzard.screen_height,
BLIZZARD_COLOR_RGB565, 1, flags);
blizzard.zoom_on = 0;
}

/* remember scaling settings if we have scaled update */
if (have_zoom_for_this_update) {
blizzard.zoom_on = 1;
blizzard.zoom_area_gx1 = gx1_out;
blizzard.zoom_area_gx2 = gx2_out;
blizzard.zoom_area_gy1 = gy1_out;
blizzard.zoom_area_gy2 = gy2_out;
}

set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out,
color_mode, zoom_off, flags);
if (zoom_off)
blizzard.zoom_on = 0;

blizzard.extif->set_bits_per_cycle(16);
/* set_window_regs has left the register index at the right
Expand Down Expand Up @@ -908,6 +958,35 @@ static int blizzard_set_scale(int plane, int orig_w, int orig_h,
return 0;
}

static int blizzard_set_rotate(int angle)
{
u32 l;

l = blizzard_read_reg(BLIZZARD_PANEL_CONFIGURATION);
l &= ~0x03;

switch (angle) {
case 0:
l = l | 0x00;
break;
case 90:
l = l | 0x03;
break;
case 180:
l = l | 0x02;
break;
case 270:
l = l | 0x01;
break;
default:
return -EINVAL;
}

blizzard_write_reg(BLIZZARD_PANEL_CONFIGURATION, l);

return 0;
}

static int blizzard_enable_plane(int plane, int enable)
{
if (enable)
Expand Down Expand Up @@ -1285,7 +1364,8 @@ static void blizzard_get_caps(int plane, struct omapfb_caps *caps)
caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
OMAPFB_CAPS_WINDOW_SCALE |
OMAPFB_CAPS_WINDOW_OVERLAY;
OMAPFB_CAPS_WINDOW_OVERLAY |
OMAPFB_CAPS_WINDOW_ROTATE;
if (blizzard.te_connected)
caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
Expand Down Expand Up @@ -1560,6 +1640,7 @@ struct lcd_ctrl blizzard_ctrl = {
.setup_plane = blizzard_setup_plane,
.set_scale = blizzard_set_scale,
.enable_plane = blizzard_enable_plane,
.set_rotate = blizzard_set_rotate,
.update_window = blizzard_update_window_async,
.sync = blizzard_sync,
.suspend = blizzard_suspend,
Expand Down
52 changes: 38 additions & 14 deletions drivers/video/omap/omapfb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ static struct caps_table_struct ctrl_caps[] = {
{ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
{ OMAPFB_CAPS_WINDOW_SCALE, "scale window" },
{ OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
{ OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" },
{ OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
};

Expand Down Expand Up @@ -215,6 +216,15 @@ static int ctrl_change_mode(struct fb_info *fbi)
offset, var->xres_virtual,
plane->info.pos_x, plane->info.pos_y,
var->xres, var->yres, plane->color_mode);
if (r < 0)
return r;

if (fbdev->ctrl->set_rotate != NULL) {
r = fbdev->ctrl->set_rotate(var->rotate);
if (r < 0)
return r;
}

if (fbdev->ctrl->set_scale != NULL)
r = fbdev->ctrl->set_scale(plane->idx,
var->xres, var->yres,
Expand Down Expand Up @@ -600,7 +610,7 @@ static void omapfb_rotate(struct fb_info *fbi, int rotate)
struct omapfb_device *fbdev = plane->fbdev;

omapfb_rqueue_lock(fbdev);
if (cpu_is_omap15xx() && rotate != fbi->var.rotate) {
if (rotate != fbi->var.rotate) {
struct fb_var_screeninfo *new_var = &fbdev->new_var;

memcpy(new_var, &fbi->var, sizeof(*new_var));
Expand Down Expand Up @@ -707,28 +717,42 @@ int omapfb_update_window_async(struct fb_info *fbi,
void (*callback)(void *),
void *callback_data)
{
int xres, yres;
struct omapfb_plane_struct *plane = fbi->par;
struct omapfb_device *fbdev = plane->fbdev;
struct fb_var_screeninfo *var;
struct fb_var_screeninfo *var = &fbi->var;

switch (var->rotate) {
case 0:
case 180:
xres = fbdev->panel->x_res;
yres = fbdev->panel->y_res;
break;
case 90:
case 270:
xres = fbdev->panel->y_res;
yres = fbdev->panel->x_res;
break;
default:
return -EINVAL;
}

var = &fbi->var;
if (win->x >= var->xres || win->y >= var->yres ||
win->out_x > var->xres || win->out_y >= var->yres)
if (win->x >= xres || win->y >= yres ||
win->out_x > xres || win->out_y > yres)
return -EINVAL;

if (!fbdev->ctrl->update_window ||
fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
return -ENODEV;

if (win->x + win->width >= var->xres)
win->width = var->xres - win->x;
if (win->y + win->height >= var->yres)
win->height = var->yres - win->y;
/* The out sizes should be cropped to the LCD size */
if (win->out_x + win->out_width > fbdev->panel->x_res)
win->out_width = fbdev->panel->x_res - win->out_x;
if (win->out_y + win->out_height > fbdev->panel->y_res)
win->out_height = fbdev->panel->y_res - win->out_y;
if (win->x + win->width > xres)
win->width = xres - win->x;
if (win->y + win->height > yres)
win->height = yres - win->y;
if (win->out_x + win->out_width > xres)
win->out_width = xres - win->out_x;
if (win->out_y + win->out_height > yres)
win->out_height = yres - win->out_y;
if (!win->width || !win->height || !win->out_width || !win->out_height)
return 0;

Expand Down

0 comments on commit 2f21a62

Please sign in to comment.