aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/manager.c')
-rw-r--r--drivers/video/omap2/dss/manager.c204
1 files changed, 124 insertions, 80 deletions
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 9e1fbe531bf..6a649ab5539 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -440,6 +440,10 @@ struct manager_cache_data {
440 440
441 /* manual update region */ 441 /* manual update region */
442 u16 x, y, w, h; 442 u16 x, y, w, h;
443
444 /* enlarge the update area if the update area contains scaled
445 * overlays */
446 bool enlarge_update_area;
443}; 447};
444 448
445static struct { 449static struct {
@@ -525,7 +529,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
525 int i; 529 int i;
526 struct omap_dss_device *dssdev = mgr->device; 530 struct omap_dss_device *dssdev = mgr->device;
527 531
528 if (!dssdev) 532 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
529 return 0; 533 return 0;
530 534
531 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { 535 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
@@ -596,11 +600,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
596 int r; 600 int r;
597 int i; 601 int i;
598 602
599 if (!ovl->manager || !ovl->manager->device) 603 if (!ovl->manager)
600 return 0; 604 return 0;
601 605
602 dssdev = ovl->manager->device; 606 dssdev = ovl->manager->device;
603 607
608 if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
609 return 0;
610
604 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { 611 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
605 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; 612 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
606 channel = OMAP_DSS_CHANNEL_DIGIT; 613 channel = OMAP_DSS_CHANNEL_DIGIT;
@@ -718,6 +725,7 @@ static int configure_overlay(enum omap_plane plane)
718 u16 x, y, w, h; 725 u16 x, y, w, h;
719 u32 paddr; 726 u32 paddr;
720 int r; 727 int r;
728 u16 orig_w, orig_h, orig_outw, orig_outh;
721 729
722 DSSDBGF("%d", plane); 730 DSSDBGF("%d", plane);
723 731
@@ -738,8 +746,16 @@ static int configure_overlay(enum omap_plane plane)
738 outh = c->out_height == 0 ? c->height : c->out_height; 746 outh = c->out_height == 0 ? c->height : c->out_height;
739 paddr = c->paddr; 747 paddr = c->paddr;
740 748
749 orig_w = w;
750 orig_h = h;
751 orig_outw = outw;
752 orig_outh = outh;
753
741 if (c->manual_update && mc->do_manual_update) { 754 if (c->manual_update && mc->do_manual_update) {
742 unsigned bpp; 755 unsigned bpp;
756 unsigned scale_x_m = w, scale_x_d = outw;
757 unsigned scale_y_m = h, scale_y_d = outh;
758
743 /* If the overlay is outside the update region, disable it */ 759 /* If the overlay is outside the update region, disable it */
744 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, 760 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
745 x, y, outw, outh)) { 761 x, y, outw, outh)) {
@@ -770,38 +786,47 @@ static int configure_overlay(enum omap_plane plane)
770 BUG(); 786 BUG();
771 } 787 }
772 788
773 if (dispc_is_overlay_scaled(c)) { 789 if (mc->x > c->pos_x) {
774 /* If the overlay is scaled, the update area has 790 x = 0;
775 * already been enlarged to cover the whole overlay. We 791 outw -= (mc->x - c->pos_x);
776 * only need to adjust x/y here */ 792 paddr += (mc->x - c->pos_x) *
777 x = c->pos_x - mc->x; 793 scale_x_m / scale_x_d * bpp / 8;
778 y = c->pos_y - mc->y;
779 } else { 794 } else {
780 if (mc->x > c->pos_x) { 795 x = c->pos_x - mc->x;
781 x = 0; 796 }
782 w -= (mc->x - c->pos_x);
783 paddr += (mc->x - c->pos_x) * bpp / 8;
784 } else {
785 x = c->pos_x - mc->x;
786 }
787
788 if (mc->y > c->pos_y) {
789 y = 0;
790 h -= (mc->y - c->pos_y);
791 paddr += (mc->y - c->pos_y) * c->screen_width *
792 bpp / 8;
793 } else {
794 y = c->pos_y - mc->y;
795 }
796
797 if (mc->w < (x+w))
798 w -= (x+w) - (mc->w);
799 797
800 if (mc->h < (y+h)) 798 if (mc->y > c->pos_y) {
801 h -= (y+h) - (mc->h); 799 y = 0;
800 outh -= (mc->y - c->pos_y);
801 paddr += (mc->y - c->pos_y) *
802 scale_y_m / scale_y_d *
803 c->screen_width * bpp / 8;
804 } else {
805 y = c->pos_y - mc->y;
806 }
802 807
803 outw = w; 808 if (mc->w < (x + outw))
804 outh = h; 809 outw -= (x + outw) - (mc->w);
810
811 if (mc->h < (y + outh))
812 outh -= (y + outh) - (mc->h);
813
814 w = w * outw / orig_outw;
815 h = h * outh / orig_outh;
816
817 /* YUV mode overlay's input width has to be even and the
818 * algorithm above may adjust the width to be odd.
819 *
820 * Here we adjust the width if needed, preferring to increase
821 * the width if the original width was bigger.
822 */
823 if ((w & 1) &&
824 (c->color_mode == OMAP_DSS_COLOR_YUV2 ||
825 c->color_mode == OMAP_DSS_COLOR_UYVY)) {
826 if (orig_w > w)
827 w += 1;
828 else
829 w -= 1;
805 } 830 }
806 } 831 }
807 832
@@ -960,7 +985,7 @@ static void make_even(u16 *x, u16 *w)
960/* Configure dispc for partial update. Return possibly modified update 985/* Configure dispc for partial update. Return possibly modified update
961 * area */ 986 * area */
962void dss_setup_partial_planes(struct omap_dss_device *dssdev, 987void dss_setup_partial_planes(struct omap_dss_device *dssdev,
963 u16 *xi, u16 *yi, u16 *wi, u16 *hi) 988 u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
964{ 989{
965 struct overlay_cache_data *oc; 990 struct overlay_cache_data *oc;
966 struct manager_cache_data *mc; 991 struct manager_cache_data *mc;
@@ -969,6 +994,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
969 int i; 994 int i;
970 u16 x, y, w, h; 995 u16 x, y, w, h;
971 unsigned long flags; 996 unsigned long flags;
997 bool area_changed;
972 998
973 x = *xi; 999 x = *xi;
974 y = *yi; 1000 y = *yi;
@@ -989,73 +1015,91 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
989 1015
990 spin_lock_irqsave(&dss_cache.lock, flags); 1016 spin_lock_irqsave(&dss_cache.lock, flags);
991 1017
992 /* We need to show the whole overlay if it is scaled. So look for 1018 /*
993 * those, and make the update area larger if found. 1019 * Execute the outer loop until the inner loop has completed
994 * Also mark the overlay cache dirty */ 1020 * once without increasing the update area. This will ensure that
995 for (i = 0; i < num_ovls; ++i) { 1021 * all scaled overlays end up completely within the update area.
996 unsigned x1, y1, x2, y2; 1022 */
997 unsigned outw, outh; 1023 do {
1024 area_changed = false;
998 1025
999 oc = &dss_cache.overlay_cache[i]; 1026 /* We need to show the whole overlay if it is scaled. So look
1027 * for those, and make the update area larger if found.
1028 * Also mark the overlay cache dirty */
1029 for (i = 0; i < num_ovls; ++i) {
1030 unsigned x1, y1, x2, y2;
1031 unsigned outw, outh;
1000 1032
1001 if (oc->channel != mgr->id) 1033 oc = &dss_cache.overlay_cache[i];
1002 continue;
1003 1034
1004 oc->dirty = true; 1035 if (oc->channel != mgr->id)
1036 continue;
1005 1037
1006 if (!oc->enabled) 1038 oc->dirty = true;
1007 continue;
1008 1039
1009 if (!dispc_is_overlay_scaled(oc)) 1040 if (!enlarge_update_area)
1010 continue; 1041 continue;
1011 1042
1012 outw = oc->out_width == 0 ? oc->width : oc->out_width; 1043 if (!oc->enabled)
1013 outh = oc->out_height == 0 ? oc->height : oc->out_height; 1044 continue;
1014 1045
1015 /* is the overlay outside the update region? */ 1046 if (!dispc_is_overlay_scaled(oc))
1016 if (!rectangle_intersects(x, y, w, h, 1047 continue;
1017 oc->pos_x, oc->pos_y,
1018 outw, outh))
1019 continue;
1020 1048
1021 /* if the overlay totally inside the update region? */ 1049 outw = oc->out_width == 0 ?
1022 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, 1050 oc->width : oc->out_width;
1023 x, y, w, h)) 1051 outh = oc->out_height == 0 ?
1024 continue; 1052 oc->height : oc->out_height;
1053
1054 /* is the overlay outside the update region? */
1055 if (!rectangle_intersects(x, y, w, h,
1056 oc->pos_x, oc->pos_y,
1057 outw, outh))
1058 continue;
1025 1059
1026 if (x > oc->pos_x) 1060 /* if the overlay totally inside the update region? */
1027 x1 = oc->pos_x; 1061 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
1028 else 1062 x, y, w, h))
1029 x1 = x; 1063 continue;
1030 1064
1031 if (y > oc->pos_y) 1065 if (x > oc->pos_x)
1032 y1 = oc->pos_y; 1066 x1 = oc->pos_x;
1033 else 1067 else
1034 y1 = y; 1068 x1 = x;
1035 1069
1036 if ((x + w) < (oc->pos_x + outw)) 1070 if (y > oc->pos_y)
1037 x2 = oc->pos_x + outw; 1071 y1 = oc->pos_y;
1038 else 1072 else
1039 x2 = x + w; 1073 y1 = y;
1040 1074
1041 if ((y + h) < (oc->pos_y + outh)) 1075 if ((x + w) < (oc->pos_x + outw))
1042 y2 = oc->pos_y + outh; 1076 x2 = oc->pos_x + outw;
1043 else 1077 else
1044 y2 = y + h; 1078 x2 = x + w;
1045 1079
1046 x = x1; 1080 if ((y + h) < (oc->pos_y + outh))
1047 y = y1; 1081 y2 = oc->pos_y + outh;
1048 w = x2 - x1; 1082 else
1049 h = y2 - y1; 1083 y2 = y + h;
1050 1084
1051 make_even(&x, &w); 1085 x = x1;
1086 y = y1;
1087 w = x2 - x1;
1088 h = y2 - y1;
1052 1089
1053 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n", 1090 make_even(&x, &w);
1091
1092 DSSDBG("changing upd area due to ovl(%d) "
1093 "scaling %d,%d %dx%d\n",
1054 i, x, y, w, h); 1094 i, x, y, w, h);
1055 } 1095
1096 area_changed = true;
1097 }
1098 } while (area_changed);
1056 1099
1057 mc = &dss_cache.manager_cache[mgr->id]; 1100 mc = &dss_cache.manager_cache[mgr->id];
1058 mc->do_manual_update = true; 1101 mc->do_manual_update = true;
1102 mc->enlarge_update_area = enlarge_update_area;
1059 mc->x = x; 1103 mc->x = x;
1060 mc->y = y; 1104 mc->y = y;
1061 mc->w = w; 1105 mc->w = w;