omapfb: add support for rotation on the Blizzard LCD ctrl
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>
This commit is contained in:
parent
8fea8844a7
commit
2f21a62f16
2 changed files with 124 additions and 19 deletions
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) |
|
||||
|
@ -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,
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
var = &fbi->var;
|
||||
if (win->x >= var->xres || win->y >= var->yres ||
|
||||
win->out_x > var->xres || win->out_y >= var->yres)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue