diff options
author | Rodrigo Vivi <rodrigo.vivi@openbossa.org> | 2009-09-22 19:46:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:49 -0400 |
commit | 2f21a62f16136f369788795a98aa5c313261f07b (patch) | |
tree | 1974092ab93bee721536018d7890d77e268af7cd /drivers/video/omap | |
parent | 8fea8844a72f95ef22b108f5dc5c4237019771dd (diff) |
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>
Diffstat (limited to 'drivers/video/omap')
-rw-r--r-- | drivers/video/omap/blizzard.c | 91 | ||||
-rw-r--r-- | drivers/video/omap/omapfb_main.c | 52 |
2 files changed, 124 insertions, 19 deletions
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c index 9dfcf39d3367..d5e59556f9e2 100644 --- a/drivers/video/omap/blizzard.c +++ b/drivers/video/omap/blizzard.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #define BLIZZARD_CLK_SRC 0x0e | 44 | #define BLIZZARD_CLK_SRC 0x0e |
45 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 | 45 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 |
46 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 | 46 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 |
47 | #define BLIZZARD_PANEL_CONFIGURATION 0x28 | ||
47 | #define BLIZZARD_HDISP 0x2a | 48 | #define BLIZZARD_HDISP 0x2a |
48 | #define BLIZZARD_HNDP 0x2c | 49 | #define BLIZZARD_HNDP 0x2c |
49 | #define BLIZZARD_VDISP0 0x2e | 50 | #define BLIZZARD_VDISP0 0x2e |
@@ -162,6 +163,10 @@ struct blizzard_struct { | |||
162 | int vid_scaled; | 163 | int vid_scaled; |
163 | int last_color_mode; | 164 | int last_color_mode; |
164 | int zoom_on; | 165 | int zoom_on; |
166 | int zoom_area_gx1; | ||
167 | int zoom_area_gx2; | ||
168 | int zoom_area_gy1; | ||
169 | int zoom_area_gy2; | ||
165 | int screen_width; | 170 | int screen_width; |
166 | int screen_height; | 171 | int screen_height; |
167 | unsigned te_connected:1; | 172 | unsigned te_connected:1; |
@@ -513,6 +518,13 @@ static int do_full_screen_update(struct blizzard_request *req) | |||
513 | return REQ_PENDING; | 518 | return REQ_PENDING; |
514 | } | 519 | } |
515 | 520 | ||
521 | static int check_1d_intersect(int a1, int a2, int b1, int b2) | ||
522 | { | ||
523 | if (a2 <= b1 || b2 <= a1) | ||
524 | return 0; | ||
525 | return 1; | ||
526 | } | ||
527 | |||
516 | /* Setup all planes with an overlapping area with the update window. */ | 528 | /* Setup all planes with an overlapping area with the update window. */ |
517 | static int do_partial_update(struct blizzard_request *req, int plane, | 529 | static int do_partial_update(struct blizzard_request *req, int plane, |
518 | int x, int y, int w, int h, | 530 | int x, int y, int w, int h, |
@@ -525,6 +537,7 @@ static int do_partial_update(struct blizzard_request *req, int plane, | |||
525 | int color_mode; | 537 | int color_mode; |
526 | int flags; | 538 | int flags; |
527 | int zoom_off; | 539 | int zoom_off; |
540 | int have_zoom_for_this_update = 0; | ||
528 | 541 | ||
529 | /* Global coordinates, relative to pixel 0,0 of the LCD */ | 542 | /* Global coordinates, relative to pixel 0,0 of the LCD */ |
530 | gx1 = x + blizzard.plane[plane].pos_x; | 543 | gx1 = x + blizzard.plane[plane].pos_x; |
@@ -544,10 +557,6 @@ static int do_partial_update(struct blizzard_request *req, int plane, | |||
544 | gx2_out = gx1_out + w_out; | 557 | gx2_out = gx1_out + w_out; |
545 | gy2_out = gy1_out + h_out; | 558 | gy2_out = gy1_out + h_out; |
546 | } | 559 | } |
547 | zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 && | ||
548 | w == blizzard.screen_width && h == blizzard.screen_height; | ||
549 | blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) || | ||
550 | (w < w_out || h < h_out); | ||
551 | 560 | ||
552 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) { | 561 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) { |
553 | struct plane_info *p = &blizzard.plane[i]; | 562 | struct plane_info *p = &blizzard.plane[i]; |
@@ -653,8 +662,49 @@ static int do_partial_update(struct blizzard_request *req, int plane, | |||
653 | else | 662 | else |
654 | disable_tearsync(); | 663 | disable_tearsync(); |
655 | 664 | ||
665 | if ((gx2_out - gx1_out) != (gx2 - gx1) || | ||
666 | (gy2_out - gy1_out) != (gy2 - gy1)) | ||
667 | have_zoom_for_this_update = 1; | ||
668 | |||
669 | /* 'background' type of screen update (as opposed to 'destructive') | ||
670 | can be used to disable scaling if scaling is active */ | ||
671 | zoom_off = blizzard.zoom_on && !have_zoom_for_this_update && | ||
672 | (gx1_out == 0) && (gx2_out == blizzard.screen_width) && | ||
673 | (gy1_out == 0) && (gy2_out == blizzard.screen_height) && | ||
674 | (gx1 == 0) && (gy1 == 0); | ||
675 | |||
676 | if (blizzard.zoom_on && !have_zoom_for_this_update && !zoom_off && | ||
677 | check_1d_intersect(blizzard.zoom_area_gx1, blizzard.zoom_area_gx2, | ||
678 | gx1_out, gx2_out) && | ||
679 | check_1d_intersect(blizzard.zoom_area_gy1, blizzard.zoom_area_gy2, | ||
680 | gy1_out, gy2_out)) { | ||
681 | /* Previous screen update was using scaling, current update | ||
682 | * is not using it. Additionally, current screen update is | ||
683 | * going to overlap with the scaled area. Scaling needs to be | ||
684 | * disabled in order to avoid 'magnifying glass' effect. | ||
685 | * Dummy setup of background window can be used for this. | ||
686 | */ | ||
687 | set_window_regs(0, 0, blizzard.screen_width, | ||
688 | blizzard.screen_height, | ||
689 | 0, 0, blizzard.screen_width, | ||
690 | blizzard.screen_height, | ||
691 | BLIZZARD_COLOR_RGB565, 1, flags); | ||
692 | blizzard.zoom_on = 0; | ||
693 | } | ||
694 | |||
695 | /* remember scaling settings if we have scaled update */ | ||
696 | if (have_zoom_for_this_update) { | ||
697 | blizzard.zoom_on = 1; | ||
698 | blizzard.zoom_area_gx1 = gx1_out; | ||
699 | blizzard.zoom_area_gx2 = gx2_out; | ||
700 | blizzard.zoom_area_gy1 = gy1_out; | ||
701 | blizzard.zoom_area_gy2 = gy2_out; | ||
702 | } | ||
703 | |||
656 | set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out, | 704 | set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out, |
657 | color_mode, zoom_off, flags); | 705 | color_mode, zoom_off, flags); |
706 | if (zoom_off) | ||
707 | blizzard.zoom_on = 0; | ||
658 | 708 | ||
659 | blizzard.extif->set_bits_per_cycle(16); | 709 | blizzard.extif->set_bits_per_cycle(16); |
660 | /* set_window_regs has left the register index at the right | 710 | /* 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, | |||
908 | return 0; | 958 | return 0; |
909 | } | 959 | } |
910 | 960 | ||
961 | static int blizzard_set_rotate(int angle) | ||
962 | { | ||
963 | u32 l; | ||
964 | |||
965 | l = blizzard_read_reg(BLIZZARD_PANEL_CONFIGURATION); | ||
966 | l &= ~0x03; | ||
967 | |||
968 | switch (angle) { | ||
969 | case 0: | ||
970 | l = l | 0x00; | ||
971 | break; | ||
972 | case 90: | ||
973 | l = l | 0x03; | ||
974 | break; | ||
975 | case 180: | ||
976 | l = l | 0x02; | ||
977 | break; | ||
978 | case 270: | ||
979 | l = l | 0x01; | ||
980 | break; | ||
981 | default: | ||
982 | return -EINVAL; | ||
983 | } | ||
984 | |||
985 | blizzard_write_reg(BLIZZARD_PANEL_CONFIGURATION, l); | ||
986 | |||
987 | return 0; | ||
988 | } | ||
989 | |||
911 | static int blizzard_enable_plane(int plane, int enable) | 990 | static int blizzard_enable_plane(int plane, int enable) |
912 | { | 991 | { |
913 | if (enable) | 992 | if (enable) |
@@ -1285,7 +1364,8 @@ static void blizzard_get_caps(int plane, struct omapfb_caps *caps) | |||
1285 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | 1364 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | |
1286 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE | | 1365 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE | |
1287 | OMAPFB_CAPS_WINDOW_SCALE | | 1366 | OMAPFB_CAPS_WINDOW_SCALE | |
1288 | OMAPFB_CAPS_WINDOW_OVERLAY; | 1367 | OMAPFB_CAPS_WINDOW_OVERLAY | |
1368 | OMAPFB_CAPS_WINDOW_ROTATE; | ||
1289 | if (blizzard.te_connected) | 1369 | if (blizzard.te_connected) |
1290 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | 1370 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; |
1291 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | 1371 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | |
@@ -1560,6 +1640,7 @@ struct lcd_ctrl blizzard_ctrl = { | |||
1560 | .setup_plane = blizzard_setup_plane, | 1640 | .setup_plane = blizzard_setup_plane, |
1561 | .set_scale = blizzard_set_scale, | 1641 | .set_scale = blizzard_set_scale, |
1562 | .enable_plane = blizzard_enable_plane, | 1642 | .enable_plane = blizzard_enable_plane, |
1643 | .set_rotate = blizzard_set_rotate, | ||
1563 | .update_window = blizzard_update_window_async, | 1644 | .update_window = blizzard_update_window_async, |
1564 | .sync = blizzard_sync, | 1645 | .sync = blizzard_sync, |
1565 | .suspend = blizzard_suspend, | 1646 | .suspend = blizzard_suspend, |
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 8862233d57b6..db05f7e316e7 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c | |||
@@ -67,6 +67,7 @@ static struct caps_table_struct ctrl_caps[] = { | |||
67 | { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, | 67 | { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, |
68 | { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, | 68 | { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, |
69 | { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, | 69 | { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, |
70 | { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" }, | ||
70 | { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, | 71 | { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, |
71 | }; | 72 | }; |
72 | 73 | ||
@@ -215,6 +216,15 @@ static int ctrl_change_mode(struct fb_info *fbi) | |||
215 | offset, var->xres_virtual, | 216 | offset, var->xres_virtual, |
216 | plane->info.pos_x, plane->info.pos_y, | 217 | plane->info.pos_x, plane->info.pos_y, |
217 | var->xres, var->yres, plane->color_mode); | 218 | var->xres, var->yres, plane->color_mode); |
219 | if (r < 0) | ||
220 | return r; | ||
221 | |||
222 | if (fbdev->ctrl->set_rotate != NULL) { | ||
223 | r = fbdev->ctrl->set_rotate(var->rotate); | ||
224 | if (r < 0) | ||
225 | return r; | ||
226 | } | ||
227 | |||
218 | if (fbdev->ctrl->set_scale != NULL) | 228 | if (fbdev->ctrl->set_scale != NULL) |
219 | r = fbdev->ctrl->set_scale(plane->idx, | 229 | r = fbdev->ctrl->set_scale(plane->idx, |
220 | var->xres, var->yres, | 230 | var->xres, var->yres, |
@@ -600,7 +610,7 @@ static void omapfb_rotate(struct fb_info *fbi, int rotate) | |||
600 | struct omapfb_device *fbdev = plane->fbdev; | 610 | struct omapfb_device *fbdev = plane->fbdev; |
601 | 611 | ||
602 | omapfb_rqueue_lock(fbdev); | 612 | omapfb_rqueue_lock(fbdev); |
603 | if (cpu_is_omap15xx() && rotate != fbi->var.rotate) { | 613 | if (rotate != fbi->var.rotate) { |
604 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | 614 | struct fb_var_screeninfo *new_var = &fbdev->new_var; |
605 | 615 | ||
606 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | 616 | memcpy(new_var, &fbi->var, sizeof(*new_var)); |
@@ -707,28 +717,42 @@ int omapfb_update_window_async(struct fb_info *fbi, | |||
707 | void (*callback)(void *), | 717 | void (*callback)(void *), |
708 | void *callback_data) | 718 | void *callback_data) |
709 | { | 719 | { |
720 | int xres, yres; | ||
710 | struct omapfb_plane_struct *plane = fbi->par; | 721 | struct omapfb_plane_struct *plane = fbi->par; |
711 | struct omapfb_device *fbdev = plane->fbdev; | 722 | struct omapfb_device *fbdev = plane->fbdev; |
712 | struct fb_var_screeninfo *var; | 723 | struct fb_var_screeninfo *var = &fbi->var; |
724 | |||
725 | switch (var->rotate) { | ||
726 | case 0: | ||
727 | case 180: | ||
728 | xres = fbdev->panel->x_res; | ||
729 | yres = fbdev->panel->y_res; | ||
730 | break; | ||
731 | case 90: | ||
732 | case 270: | ||
733 | xres = fbdev->panel->y_res; | ||
734 | yres = fbdev->panel->x_res; | ||
735 | break; | ||
736 | default: | ||
737 | return -EINVAL; | ||
738 | } | ||
713 | 739 | ||
714 | var = &fbi->var; | 740 | if (win->x >= xres || win->y >= yres || |
715 | if (win->x >= var->xres || win->y >= var->yres || | 741 | win->out_x > xres || win->out_y > yres) |
716 | win->out_x > var->xres || win->out_y >= var->yres) | ||
717 | return -EINVAL; | 742 | return -EINVAL; |
718 | 743 | ||
719 | if (!fbdev->ctrl->update_window || | 744 | if (!fbdev->ctrl->update_window || |
720 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | 745 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) |
721 | return -ENODEV; | 746 | return -ENODEV; |
722 | 747 | ||
723 | if (win->x + win->width >= var->xres) | 748 | if (win->x + win->width > xres) |
724 | win->width = var->xres - win->x; | 749 | win->width = xres - win->x; |
725 | if (win->y + win->height >= var->yres) | 750 | if (win->y + win->height > yres) |
726 | win->height = var->yres - win->y; | 751 | win->height = yres - win->y; |
727 | /* The out sizes should be cropped to the LCD size */ | 752 | if (win->out_x + win->out_width > xres) |
728 | if (win->out_x + win->out_width > fbdev->panel->x_res) | 753 | win->out_width = xres - win->out_x; |
729 | win->out_width = fbdev->panel->x_res - win->out_x; | 754 | if (win->out_y + win->out_height > yres) |
730 | if (win->out_y + win->out_height > fbdev->panel->y_res) | 755 | win->out_height = yres - win->out_y; |
731 | win->out_height = fbdev->panel->y_res - win->out_y; | ||
732 | if (!win->width || !win->height || !win->out_width || !win->out_height) | 756 | if (!win->width || !win->height || !win->out_width || !win->out_height) |
733 | return 0; | 757 | return 0; |
734 | 758 | ||