diff options
Diffstat (limited to 'drivers/video/omap2/dss/manager.c')
-rw-r--r-- | drivers/video/omap2/dss/manager.c | 204 |
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 | ||
445 | static struct { | 449 | static 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 */ |
962 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | 987 | void 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; |