diff options
Diffstat (limited to 'drivers/video/omap2/dss/dispc.c')
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 1018 |
1 files changed, 712 insertions, 306 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee9e29639dcc..b43477a5fae8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/pm_runtime.h> | 38 | #include <linux/pm_runtime.h> |
39 | 39 | ||
40 | #include <plat/cpu.h> | 40 | #include <plat/cpu.h> |
41 | #include <plat/clock.h> | ||
42 | 41 | ||
43 | #include <video/omapdss.h> | 42 | #include <video/omapdss.h> |
44 | 43 | ||
@@ -82,6 +81,30 @@ struct dispc_irq_stats { | |||
82 | unsigned irqs[32]; | 81 | unsigned irqs[32]; |
83 | }; | 82 | }; |
84 | 83 | ||
84 | struct dispc_features { | ||
85 | u8 sw_start; | ||
86 | u8 fp_start; | ||
87 | u8 bp_start; | ||
88 | u16 sw_max; | ||
89 | u16 vp_max; | ||
90 | u16 hp_max; | ||
91 | int (*calc_scaling) (enum omap_plane plane, | ||
92 | const struct omap_video_timings *mgr_timings, | ||
93 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
94 | enum omap_color_mode color_mode, bool *five_taps, | ||
95 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
96 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem); | ||
97 | unsigned long (*calc_core_clk) (enum omap_plane plane, | ||
98 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
99 | bool mem_to_mem); | ||
100 | u8 num_fifos; | ||
101 | |||
102 | /* swap GFX & WB fifos */ | ||
103 | bool gfx_fifo_workaround:1; | ||
104 | }; | ||
105 | |||
106 | #define DISPC_MAX_NR_FIFOS 5 | ||
107 | |||
85 | static struct { | 108 | static struct { |
86 | struct platform_device *pdev; | 109 | struct platform_device *pdev; |
87 | void __iomem *base; | 110 | void __iomem *base; |
@@ -91,7 +114,9 @@ static struct { | |||
91 | int irq; | 114 | int irq; |
92 | struct clk *dss_clk; | 115 | struct clk *dss_clk; |
93 | 116 | ||
94 | u32 fifo_size[MAX_DSS_OVERLAYS]; | 117 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; |
118 | /* maps which plane is using a fifo. fifo-id -> plane-id */ | ||
119 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; | ||
95 | 120 | ||
96 | spinlock_t irq_lock; | 121 | spinlock_t irq_lock; |
97 | u32 irq_error_mask; | 122 | u32 irq_error_mask; |
@@ -102,6 +127,8 @@ static struct { | |||
102 | bool ctx_valid; | 127 | bool ctx_valid; |
103 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; | 128 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; |
104 | 129 | ||
130 | const struct dispc_features *feat; | ||
131 | |||
105 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 132 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
106 | spinlock_t irq_stats_lock; | 133 | spinlock_t irq_stats_lock; |
107 | struct dispc_irq_stats irq_stats; | 134 | struct dispc_irq_stats irq_stats; |
@@ -211,7 +238,14 @@ static const struct { | |||
211 | }, | 238 | }, |
212 | }; | 239 | }; |
213 | 240 | ||
241 | struct color_conv_coef { | ||
242 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
243 | int full_range; | ||
244 | }; | ||
245 | |||
214 | static void _omap_dispc_set_irqs(void); | 246 | static void _omap_dispc_set_irqs(void); |
247 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); | ||
248 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); | ||
215 | 249 | ||
216 | static inline void dispc_write_reg(const u16 idx, u32 val) | 250 | static inline void dispc_write_reg(const u16 idx, u32 val) |
217 | { | 251 | { |
@@ -509,6 +543,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | |||
509 | return mgr_desc[channel].framedone_irq; | 543 | return mgr_desc[channel].framedone_irq; |
510 | } | 544 | } |
511 | 545 | ||
546 | u32 dispc_wb_get_framedone_irq(void) | ||
547 | { | ||
548 | return DISPC_IRQ_FRAMEDONEWB; | ||
549 | } | ||
550 | |||
512 | bool dispc_mgr_go_busy(enum omap_channel channel) | 551 | bool dispc_mgr_go_busy(enum omap_channel channel) |
513 | { | 552 | { |
514 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; | 553 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; |
@@ -536,6 +575,30 @@ void dispc_mgr_go(enum omap_channel channel) | |||
536 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); | 575 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); |
537 | } | 576 | } |
538 | 577 | ||
578 | bool dispc_wb_go_busy(void) | ||
579 | { | ||
580 | return REG_GET(DISPC_CONTROL2, 6, 6) == 1; | ||
581 | } | ||
582 | |||
583 | void dispc_wb_go(void) | ||
584 | { | ||
585 | enum omap_plane plane = OMAP_DSS_WB; | ||
586 | bool enable, go; | ||
587 | |||
588 | enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; | ||
589 | |||
590 | if (!enable) | ||
591 | return; | ||
592 | |||
593 | go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; | ||
594 | if (go) { | ||
595 | DSSERR("GO bit not down for WB\n"); | ||
596 | return; | ||
597 | } | ||
598 | |||
599 | REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); | ||
600 | } | ||
601 | |||
539 | static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) | 602 | static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) |
540 | { | 603 | { |
541 | dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); | 604 | dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); |
@@ -618,41 +681,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, | |||
618 | } | 681 | } |
619 | } | 682 | } |
620 | 683 | ||
621 | static void _dispc_setup_color_conv_coef(void) | ||
622 | { | ||
623 | int i; | ||
624 | const struct color_conv_coef { | ||
625 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
626 | int full_range; | ||
627 | } ctbl_bt601_5 = { | ||
628 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
629 | }; | ||
630 | |||
631 | const struct color_conv_coef *ct; | ||
632 | 684 | ||
685 | static void dispc_ovl_write_color_conv_coef(enum omap_plane plane, | ||
686 | const struct color_conv_coef *ct) | ||
687 | { | ||
633 | #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) | 688 | #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) |
634 | 689 | ||
635 | ct = &ctbl_bt601_5; | 690 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); |
691 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); | ||
692 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); | ||
693 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); | ||
694 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); | ||
636 | 695 | ||
637 | for (i = 1; i < dss_feat_get_num_ovls(); i++) { | 696 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); |
638 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), | ||
639 | CVAL(ct->rcr, ct->ry)); | ||
640 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), | ||
641 | CVAL(ct->gy, ct->rcb)); | ||
642 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), | ||
643 | CVAL(ct->gcb, ct->gcr)); | ||
644 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), | ||
645 | CVAL(ct->bcr, ct->by)); | ||
646 | dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), | ||
647 | CVAL(0, ct->bcb)); | ||
648 | |||
649 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, | ||
650 | 11, 11); | ||
651 | } | ||
652 | 697 | ||
653 | #undef CVAL | 698 | #undef CVAL |
654 | } | 699 | } |
655 | 700 | ||
701 | static void dispc_setup_color_conv_coef(void) | ||
702 | { | ||
703 | int i; | ||
704 | int num_ovl = dss_feat_get_num_ovls(); | ||
705 | int num_wb = dss_feat_get_num_wbs(); | ||
706 | const struct color_conv_coef ctbl_bt601_5_ovl = { | ||
707 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
708 | }; | ||
709 | const struct color_conv_coef ctbl_bt601_5_wb = { | ||
710 | 66, 112, -38, 129, -94, -74, 25, -18, 112, 0, | ||
711 | }; | ||
712 | |||
713 | for (i = 1; i < num_ovl; i++) | ||
714 | dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); | ||
715 | |||
716 | for (; i < num_wb; i++) | ||
717 | dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb); | ||
718 | } | ||
656 | 719 | ||
657 | static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) | 720 | static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) |
658 | { | 721 | { |
@@ -674,24 +737,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) | |||
674 | dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); | 737 | dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); |
675 | } | 738 | } |
676 | 739 | ||
677 | static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) | 740 | static void dispc_ovl_set_pos(enum omap_plane plane, |
741 | enum omap_overlay_caps caps, int x, int y) | ||
678 | { | 742 | { |
679 | u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); | 743 | u32 val; |
744 | |||
745 | if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) | ||
746 | return; | ||
747 | |||
748 | val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); | ||
680 | 749 | ||
681 | dispc_write_reg(DISPC_OVL_POSITION(plane), val); | 750 | dispc_write_reg(DISPC_OVL_POSITION(plane), val); |
682 | } | 751 | } |
683 | 752 | ||
684 | static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) | 753 | static void dispc_ovl_set_input_size(enum omap_plane plane, int width, |
754 | int height) | ||
685 | { | 755 | { |
686 | u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 756 | u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
687 | 757 | ||
688 | if (plane == OMAP_DSS_GFX) | 758 | if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) |
689 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | 759 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); |
690 | else | 760 | else |
691 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); | 761 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); |
692 | } | 762 | } |
693 | 763 | ||
694 | static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) | 764 | static void dispc_ovl_set_output_size(enum omap_plane plane, int width, |
765 | int height) | ||
695 | { | 766 | { |
696 | u32 val; | 767 | u32 val; |
697 | 768 | ||
@@ -699,14 +770,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) | |||
699 | 770 | ||
700 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 771 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
701 | 772 | ||
702 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | 773 | if (plane == OMAP_DSS_WB) |
774 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); | ||
775 | else | ||
776 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | ||
703 | } | 777 | } |
704 | 778 | ||
705 | static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) | 779 | static void dispc_ovl_set_zorder(enum omap_plane plane, |
780 | enum omap_overlay_caps caps, u8 zorder) | ||
706 | { | 781 | { |
707 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 782 | if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) |
708 | |||
709 | if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) | ||
710 | return; | 783 | return; |
711 | 784 | ||
712 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); | 785 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); |
@@ -723,23 +796,22 @@ static void dispc_ovl_enable_zorder_planes(void) | |||
723 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); | 796 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); |
724 | } | 797 | } |
725 | 798 | ||
726 | static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) | 799 | static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, |
800 | enum omap_overlay_caps caps, bool enable) | ||
727 | { | 801 | { |
728 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 802 | if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) |
729 | |||
730 | if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) | ||
731 | return; | 803 | return; |
732 | 804 | ||
733 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); | 805 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); |
734 | } | 806 | } |
735 | 807 | ||
736 | static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) | 808 | static void dispc_ovl_setup_global_alpha(enum omap_plane plane, |
809 | enum omap_overlay_caps caps, u8 global_alpha) | ||
737 | { | 810 | { |
738 | static const unsigned shifts[] = { 0, 8, 16, 24, }; | 811 | static const unsigned shifts[] = { 0, 8, 16, 24, }; |
739 | int shift; | 812 | int shift; |
740 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | ||
741 | 813 | ||
742 | if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) | 814 | if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) |
743 | return; | 815 | return; |
744 | 816 | ||
745 | shift = shifts[plane]; | 817 | shift = shifts[plane]; |
@@ -947,10 +1019,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | |||
947 | return channel; | 1019 | return channel; |
948 | } | 1020 | } |
949 | 1021 | ||
1022 | void dispc_wb_set_channel_in(enum dss_writeback_channel channel) | ||
1023 | { | ||
1024 | enum omap_plane plane = OMAP_DSS_WB; | ||
1025 | |||
1026 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); | ||
1027 | } | ||
1028 | |||
950 | static void dispc_ovl_set_burst_size(enum omap_plane plane, | 1029 | static void dispc_ovl_set_burst_size(enum omap_plane plane, |
951 | enum omap_burst_size burst_size) | 1030 | enum omap_burst_size burst_size) |
952 | { | 1031 | { |
953 | static const unsigned shifts[] = { 6, 14, 14, 14, }; | 1032 | static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; |
954 | int shift; | 1033 | int shift; |
955 | 1034 | ||
956 | shift = shifts[plane]; | 1035 | shift = shifts[plane]; |
@@ -1027,11 +1106,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) | |||
1027 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 1106 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
1028 | } | 1107 | } |
1029 | 1108 | ||
1030 | static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) | 1109 | static void dispc_ovl_enable_replication(enum omap_plane plane, |
1110 | enum omap_overlay_caps caps, bool enable) | ||
1031 | { | 1111 | { |
1032 | static const unsigned shifts[] = { 5, 10, 10, 10 }; | 1112 | static const unsigned shifts[] = { 5, 10, 10, 10 }; |
1033 | int shift; | 1113 | int shift; |
1034 | 1114 | ||
1115 | if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) | ||
1116 | return; | ||
1117 | |||
1035 | shift = shifts[plane]; | 1118 | shift = shifts[plane]; |
1036 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); | 1119 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); |
1037 | } | 1120 | } |
@@ -1045,10 +1128,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, | |||
1045 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); | 1128 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); |
1046 | } | 1129 | } |
1047 | 1130 | ||
1048 | static void dispc_read_plane_fifo_sizes(void) | 1131 | static void dispc_init_fifos(void) |
1049 | { | 1132 | { |
1050 | u32 size; | 1133 | u32 size; |
1051 | int plane; | 1134 | int fifo; |
1052 | u8 start, end; | 1135 | u8 start, end; |
1053 | u32 unit; | 1136 | u32 unit; |
1054 | 1137 | ||
@@ -1056,16 +1139,53 @@ static void dispc_read_plane_fifo_sizes(void) | |||
1056 | 1139 | ||
1057 | dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); | 1140 | dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); |
1058 | 1141 | ||
1059 | for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { | 1142 | for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { |
1060 | size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); | 1143 | size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); |
1061 | size *= unit; | 1144 | size *= unit; |
1062 | dispc.fifo_size[plane] = size; | 1145 | dispc.fifo_size[fifo] = size; |
1146 | |||
1147 | /* | ||
1148 | * By default fifos are mapped directly to overlays, fifo 0 to | ||
1149 | * ovl 0, fifo 1 to ovl 1, etc. | ||
1150 | */ | ||
1151 | dispc.fifo_assignment[fifo] = fifo; | ||
1152 | } | ||
1153 | |||
1154 | /* | ||
1155 | * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo | ||
1156 | * causes problems with certain use cases, like using the tiler in 2D | ||
1157 | * mode. The below hack swaps the fifos of GFX and WB planes, thus | ||
1158 | * giving GFX plane a larger fifo. WB but should work fine with a | ||
1159 | * smaller fifo. | ||
1160 | */ | ||
1161 | if (dispc.feat->gfx_fifo_workaround) { | ||
1162 | u32 v; | ||
1163 | |||
1164 | v = dispc_read_reg(DISPC_GLOBAL_BUFFER); | ||
1165 | |||
1166 | v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ | ||
1167 | v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ | ||
1168 | v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ | ||
1169 | v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ | ||
1170 | |||
1171 | dispc_write_reg(DISPC_GLOBAL_BUFFER, v); | ||
1172 | |||
1173 | dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; | ||
1174 | dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; | ||
1063 | } | 1175 | } |
1064 | } | 1176 | } |
1065 | 1177 | ||
1066 | static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) | 1178 | static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) |
1067 | { | 1179 | { |
1068 | return dispc.fifo_size[plane]; | 1180 | int fifo; |
1181 | u32 size = 0; | ||
1182 | |||
1183 | for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { | ||
1184 | if (dispc.fifo_assignment[fifo] == plane) | ||
1185 | size += dispc.fifo_size[fifo]; | ||
1186 | } | ||
1187 | |||
1188 | return size; | ||
1069 | } | 1189 | } |
1070 | 1190 | ||
1071 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | 1191 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) |
@@ -1141,6 +1261,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | |||
1141 | if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { | 1261 | if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { |
1142 | *fifo_low = ovl_fifo_size - burst_size * 2; | 1262 | *fifo_low = ovl_fifo_size - burst_size * 2; |
1143 | *fifo_high = total_fifo_size - burst_size; | 1263 | *fifo_high = total_fifo_size - burst_size; |
1264 | } else if (plane == OMAP_DSS_WB) { | ||
1265 | /* | ||
1266 | * Most optimal configuration for writeback is to push out data | ||
1267 | * to the interconnect the moment writeback pushes enough pixels | ||
1268 | * in the FIFO to form a burst | ||
1269 | */ | ||
1270 | *fifo_low = 0; | ||
1271 | *fifo_high = burst_size; | ||
1144 | } else { | 1272 | } else { |
1145 | *fifo_low = ovl_fifo_size - burst_size; | 1273 | *fifo_low = ovl_fifo_size - burst_size; |
1146 | *fifo_high = total_fifo_size - buf_unit; | 1274 | *fifo_high = total_fifo_size - buf_unit; |
@@ -1383,6 +1511,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1383 | { | 1511 | { |
1384 | int scale_x = out_width != orig_width; | 1512 | int scale_x = out_width != orig_width; |
1385 | int scale_y = out_height != orig_height; | 1513 | int scale_y = out_height != orig_height; |
1514 | bool chroma_upscale = plane != OMAP_DSS_WB ? true : false; | ||
1386 | 1515 | ||
1387 | if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) | 1516 | if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) |
1388 | return; | 1517 | return; |
@@ -1390,7 +1519,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1390 | color_mode != OMAP_DSS_COLOR_UYVY && | 1519 | color_mode != OMAP_DSS_COLOR_UYVY && |
1391 | color_mode != OMAP_DSS_COLOR_NV12)) { | 1520 | color_mode != OMAP_DSS_COLOR_NV12)) { |
1392 | /* reset chroma resampling for RGB formats */ | 1521 | /* reset chroma resampling for RGB formats */ |
1393 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); | 1522 | if (plane != OMAP_DSS_WB) |
1523 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); | ||
1394 | return; | 1524 | return; |
1395 | } | 1525 | } |
1396 | 1526 | ||
@@ -1399,23 +1529,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1399 | 1529 | ||
1400 | switch (color_mode) { | 1530 | switch (color_mode) { |
1401 | case OMAP_DSS_COLOR_NV12: | 1531 | case OMAP_DSS_COLOR_NV12: |
1402 | /* UV is subsampled by 2 vertically*/ | 1532 | if (chroma_upscale) { |
1403 | orig_height >>= 1; | 1533 | /* UV is subsampled by 2 horizontally and vertically */ |
1404 | /* UV is subsampled by 2 horz.*/ | 1534 | orig_height >>= 1; |
1405 | orig_width >>= 1; | 1535 | orig_width >>= 1; |
1536 | } else { | ||
1537 | /* UV is downsampled by 2 horizontally and vertically */ | ||
1538 | orig_height <<= 1; | ||
1539 | orig_width <<= 1; | ||
1540 | } | ||
1541 | |||
1406 | break; | 1542 | break; |
1407 | case OMAP_DSS_COLOR_YUV2: | 1543 | case OMAP_DSS_COLOR_YUV2: |
1408 | case OMAP_DSS_COLOR_UYVY: | 1544 | case OMAP_DSS_COLOR_UYVY: |
1409 | /*For YUV422 with 90/270 rotation, | 1545 | /* For YUV422 with 90/270 rotation, we don't upsample chroma */ |
1410 | *we don't upsample chroma | ||
1411 | */ | ||
1412 | if (rotation == OMAP_DSS_ROT_0 || | 1546 | if (rotation == OMAP_DSS_ROT_0 || |
1413 | rotation == OMAP_DSS_ROT_180) | 1547 | rotation == OMAP_DSS_ROT_180) { |
1414 | /* UV is subsampled by 2 hrz*/ | 1548 | if (chroma_upscale) |
1415 | orig_width >>= 1; | 1549 | /* UV is subsampled by 2 horizontally */ |
1550 | orig_width >>= 1; | ||
1551 | else | ||
1552 | /* UV is downsampled by 2 horizontally */ | ||
1553 | orig_width <<= 1; | ||
1554 | } | ||
1555 | |||
1416 | /* must use FIR for YUV422 if rotated */ | 1556 | /* must use FIR for YUV422 if rotated */ |
1417 | if (rotation != OMAP_DSS_ROT_0) | 1557 | if (rotation != OMAP_DSS_ROT_0) |
1418 | scale_x = scale_y = true; | 1558 | scale_x = scale_y = true; |
1559 | |||
1419 | break; | 1560 | break; |
1420 | default: | 1561 | default: |
1421 | BUG(); | 1562 | BUG(); |
@@ -1431,8 +1572,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1431 | out_width, out_height, five_taps, | 1572 | out_width, out_height, five_taps, |
1432 | rotation, DISPC_COLOR_COMPONENT_UV); | 1573 | rotation, DISPC_COLOR_COMPONENT_UV); |
1433 | 1574 | ||
1434 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), | 1575 | if (plane != OMAP_DSS_WB) |
1435 | (scale_x || scale_y) ? 1 : 0, 8, 8); | 1576 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), |
1577 | (scale_x || scale_y) ? 1 : 0, 8, 8); | ||
1578 | |||
1436 | /* set H scaling */ | 1579 | /* set H scaling */ |
1437 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); | 1580 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); |
1438 | /* set V scaling */ | 1581 | /* set V scaling */ |
@@ -1848,22 +1991,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, | |||
1848 | * This function is used to avoid synclosts in OMAP3, because of some | 1991 | * This function is used to avoid synclosts in OMAP3, because of some |
1849 | * undocumented horizontal position and timing related limitations. | 1992 | * undocumented horizontal position and timing related limitations. |
1850 | */ | 1993 | */ |
1851 | static int check_horiz_timing_omap3(enum omap_channel channel, | 1994 | static int check_horiz_timing_omap3(enum omap_plane plane, |
1852 | const struct omap_video_timings *t, u16 pos_x, | 1995 | const struct omap_video_timings *t, u16 pos_x, |
1853 | u16 width, u16 height, u16 out_width, u16 out_height) | 1996 | u16 width, u16 height, u16 out_width, u16 out_height) |
1854 | { | 1997 | { |
1855 | int DS = DIV_ROUND_UP(height, out_height); | 1998 | int DS = DIV_ROUND_UP(height, out_height); |
1856 | unsigned long nonactive, lclk, pclk; | 1999 | unsigned long nonactive; |
1857 | static const u8 limits[3] = { 8, 10, 20 }; | 2000 | static const u8 limits[3] = { 8, 10, 20 }; |
1858 | u64 val, blank; | 2001 | u64 val, blank; |
2002 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
2003 | unsigned long lclk = dispc_plane_lclk_rate(plane); | ||
1859 | int i; | 2004 | int i; |
1860 | 2005 | ||
1861 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; | 2006 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; |
1862 | pclk = dispc_mgr_pclk_rate(channel); | ||
1863 | if (dss_mgr_is_lcd(channel)) | ||
1864 | lclk = dispc_mgr_lclk_rate(channel); | ||
1865 | else | ||
1866 | lclk = dispc_fclk_rate(); | ||
1867 | 2007 | ||
1868 | i = 0; | 2008 | i = 0; |
1869 | if (out_height < height) | 2009 | if (out_height < height) |
@@ -1900,13 +2040,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel, | |||
1900 | return 0; | 2040 | return 0; |
1901 | } | 2041 | } |
1902 | 2042 | ||
1903 | static unsigned long calc_core_clk_five_taps(enum omap_channel channel, | 2043 | static unsigned long calc_core_clk_five_taps(enum omap_plane plane, |
1904 | const struct omap_video_timings *mgr_timings, u16 width, | 2044 | const struct omap_video_timings *mgr_timings, u16 width, |
1905 | u16 height, u16 out_width, u16 out_height, | 2045 | u16 height, u16 out_width, u16 out_height, |
1906 | enum omap_color_mode color_mode) | 2046 | enum omap_color_mode color_mode) |
1907 | { | 2047 | { |
1908 | u32 core_clk = 0; | 2048 | u32 core_clk = 0; |
1909 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); | 2049 | u64 tmp; |
2050 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
1910 | 2051 | ||
1911 | if (height <= out_height && width <= out_width) | 2052 | if (height <= out_height && width <= out_width) |
1912 | return (unsigned long) pclk; | 2053 | return (unsigned long) pclk; |
@@ -1940,11 +2081,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel, | |||
1940 | return core_clk; | 2081 | return core_clk; |
1941 | } | 2082 | } |
1942 | 2083 | ||
1943 | static unsigned long calc_core_clk(enum omap_channel channel, u16 width, | 2084 | static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, |
1944 | u16 height, u16 out_width, u16 out_height) | 2085 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
2086 | { | ||
2087 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
2088 | |||
2089 | if (height > out_height && width > out_width) | ||
2090 | return pclk * 4; | ||
2091 | else | ||
2092 | return pclk * 2; | ||
2093 | } | ||
2094 | |||
2095 | static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, | ||
2096 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | ||
1945 | { | 2097 | { |
1946 | unsigned int hf, vf; | 2098 | unsigned int hf, vf; |
1947 | unsigned long pclk = dispc_mgr_pclk_rate(channel); | 2099 | unsigned long pclk = dispc_plane_pclk_rate(plane); |
1948 | 2100 | ||
1949 | /* | 2101 | /* |
1950 | * FIXME how to determine the 'A' factor | 2102 | * FIXME how to determine the 'A' factor |
@@ -1959,51 +2111,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width, | |||
1959 | hf = 2; | 2111 | hf = 2; |
1960 | else | 2112 | else |
1961 | hf = 1; | 2113 | hf = 1; |
1962 | |||
1963 | if (height > out_height) | 2114 | if (height > out_height) |
1964 | vf = 2; | 2115 | vf = 2; |
1965 | else | 2116 | else |
1966 | vf = 1; | 2117 | vf = 1; |
1967 | 2118 | ||
1968 | if (cpu_is_omap24xx()) { | 2119 | return pclk * vf * hf; |
1969 | if (vf > 1 && hf > 1) | 2120 | } |
1970 | return pclk * 4; | 2121 | |
1971 | else | 2122 | static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, |
1972 | return pclk * 2; | 2123 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
1973 | } else if (cpu_is_omap34xx()) { | 2124 | { |
1974 | return pclk * vf * hf; | 2125 | unsigned long pclk; |
1975 | } else { | 2126 | |
1976 | if (hf > 1) | 2127 | /* |
1977 | return DIV_ROUND_UP(pclk, out_width) * width; | 2128 | * If the overlay/writeback is in mem to mem mode, there are no |
1978 | else | 2129 | * downscaling limitations with respect to pixel clock, return 1 as |
1979 | return pclk; | 2130 | * required core clock to represent that we have sufficient enough |
2131 | * core clock to do maximum downscaling | ||
2132 | */ | ||
2133 | if (mem_to_mem) | ||
2134 | return 1; | ||
2135 | |||
2136 | pclk = dispc_plane_pclk_rate(plane); | ||
2137 | |||
2138 | if (width > out_width) | ||
2139 | return DIV_ROUND_UP(pclk, out_width) * width; | ||
2140 | else | ||
2141 | return pclk; | ||
2142 | } | ||
2143 | |||
2144 | static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, | ||
2145 | const struct omap_video_timings *mgr_timings, | ||
2146 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2147 | enum omap_color_mode color_mode, bool *five_taps, | ||
2148 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2149 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2150 | { | ||
2151 | int error; | ||
2152 | u16 in_width, in_height; | ||
2153 | int min_factor = min(*decim_x, *decim_y); | ||
2154 | const int maxsinglelinewidth = | ||
2155 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2156 | |||
2157 | *five_taps = false; | ||
2158 | |||
2159 | do { | ||
2160 | in_height = DIV_ROUND_UP(height, *decim_y); | ||
2161 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2162 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, | ||
2163 | in_height, out_width, out_height, mem_to_mem); | ||
2164 | error = (in_width > maxsinglelinewidth || !*core_clk || | ||
2165 | *core_clk > dispc_core_clk_rate()); | ||
2166 | if (error) { | ||
2167 | if (*decim_x == *decim_y) { | ||
2168 | *decim_x = min_factor; | ||
2169 | ++*decim_y; | ||
2170 | } else { | ||
2171 | swap(*decim_x, *decim_y); | ||
2172 | if (*decim_x < *decim_y) | ||
2173 | ++*decim_x; | ||
2174 | } | ||
2175 | } | ||
2176 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | ||
2177 | |||
2178 | if (in_width > maxsinglelinewidth) { | ||
2179 | DSSERR("Cannot scale max input width exceeded"); | ||
2180 | return -EINVAL; | ||
1980 | } | 2181 | } |
2182 | return 0; | ||
1981 | } | 2183 | } |
1982 | 2184 | ||
1983 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | 2185 | static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, |
1984 | enum omap_channel channel, | ||
1985 | const struct omap_video_timings *mgr_timings, | 2186 | const struct omap_video_timings *mgr_timings, |
1986 | u16 width, u16 height, u16 out_width, u16 out_height, | 2187 | u16 width, u16 height, u16 out_width, u16 out_height, |
1987 | enum omap_color_mode color_mode, bool *five_taps, | 2188 | enum omap_color_mode color_mode, bool *five_taps, |
1988 | int *x_predecim, int *y_predecim, u16 pos_x) | 2189 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, |
2190 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
1989 | { | 2191 | { |
1990 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 2192 | int error; |
1991 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | 2193 | u16 in_width, in_height; |
2194 | int min_factor = min(*decim_x, *decim_y); | ||
2195 | const int maxsinglelinewidth = | ||
2196 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2197 | |||
2198 | do { | ||
2199 | in_height = DIV_ROUND_UP(height, *decim_y); | ||
2200 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2201 | *core_clk = calc_core_clk_five_taps(plane, mgr_timings, | ||
2202 | in_width, in_height, out_width, out_height, color_mode); | ||
2203 | |||
2204 | error = check_horiz_timing_omap3(plane, mgr_timings, | ||
2205 | pos_x, in_width, in_height, out_width, | ||
2206 | out_height); | ||
2207 | |||
2208 | if (in_width > maxsinglelinewidth) | ||
2209 | if (in_height > out_height && | ||
2210 | in_height < out_height * 2) | ||
2211 | *five_taps = false; | ||
2212 | if (!*five_taps) | ||
2213 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, | ||
2214 | in_height, out_width, out_height, | ||
2215 | mem_to_mem); | ||
2216 | |||
2217 | error = (error || in_width > maxsinglelinewidth * 2 || | ||
2218 | (in_width > maxsinglelinewidth && *five_taps) || | ||
2219 | !*core_clk || *core_clk > dispc_core_clk_rate()); | ||
2220 | if (error) { | ||
2221 | if (*decim_x == *decim_y) { | ||
2222 | *decim_x = min_factor; | ||
2223 | ++*decim_y; | ||
2224 | } else { | ||
2225 | swap(*decim_x, *decim_y); | ||
2226 | if (*decim_x < *decim_y) | ||
2227 | ++*decim_x; | ||
2228 | } | ||
2229 | } | ||
2230 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | ||
2231 | |||
2232 | if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, | ||
2233 | out_width, out_height)){ | ||
2234 | DSSERR("horizontal timing too tight\n"); | ||
2235 | return -EINVAL; | ||
2236 | } | ||
2237 | |||
2238 | if (in_width > (maxsinglelinewidth * 2)) { | ||
2239 | DSSERR("Cannot setup scaling"); | ||
2240 | DSSERR("width exceeds maximum width possible"); | ||
2241 | return -EINVAL; | ||
2242 | } | ||
2243 | |||
2244 | if (in_width > maxsinglelinewidth && *five_taps) { | ||
2245 | DSSERR("cannot setup scaling with five taps"); | ||
2246 | return -EINVAL; | ||
2247 | } | ||
2248 | return 0; | ||
2249 | } | ||
2250 | |||
2251 | static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, | ||
2252 | const struct omap_video_timings *mgr_timings, | ||
2253 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2254 | enum omap_color_mode color_mode, bool *five_taps, | ||
2255 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2256 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2257 | { | ||
2258 | u16 in_width, in_width_max; | ||
2259 | int decim_x_min = *decim_x; | ||
2260 | u16 in_height = DIV_ROUND_UP(height, *decim_y); | ||
1992 | const int maxsinglelinewidth = | 2261 | const int maxsinglelinewidth = |
1993 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | 2262 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); |
2263 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
2264 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | ||
2265 | |||
2266 | if (mem_to_mem) | ||
2267 | in_width_max = DIV_ROUND_UP(out_width, maxdownscale); | ||
2268 | else | ||
2269 | in_width_max = dispc_core_clk_rate() / | ||
2270 | DIV_ROUND_UP(pclk, out_width); | ||
2271 | |||
2272 | *decim_x = DIV_ROUND_UP(width, in_width_max); | ||
2273 | |||
2274 | *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; | ||
2275 | if (*decim_x > *x_predecim) | ||
2276 | return -EINVAL; | ||
2277 | |||
2278 | do { | ||
2279 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2280 | } while (*decim_x <= *x_predecim && | ||
2281 | in_width > maxsinglelinewidth && ++*decim_x); | ||
2282 | |||
2283 | if (in_width > maxsinglelinewidth) { | ||
2284 | DSSERR("Cannot scale width exceeds max line width"); | ||
2285 | return -EINVAL; | ||
2286 | } | ||
2287 | |||
2288 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, | ||
2289 | out_width, out_height, mem_to_mem); | ||
2290 | return 0; | ||
2291 | } | ||
2292 | |||
2293 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | ||
2294 | enum omap_overlay_caps caps, | ||
2295 | const struct omap_video_timings *mgr_timings, | ||
2296 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2297 | enum omap_color_mode color_mode, bool *five_taps, | ||
2298 | int *x_predecim, int *y_predecim, u16 pos_x, | ||
2299 | enum omap_dss_rotation_type rotation_type, bool mem_to_mem) | ||
2300 | { | ||
2301 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | ||
1994 | const int max_decim_limit = 16; | 2302 | const int max_decim_limit = 16; |
1995 | unsigned long core_clk = 0; | 2303 | unsigned long core_clk = 0; |
1996 | int decim_x, decim_y, error, min_factor; | 2304 | int decim_x, decim_y, ret; |
1997 | u16 in_width, in_height, in_width_max = 0; | ||
1998 | 2305 | ||
1999 | if (width == out_width && height == out_height) | 2306 | if (width == out_width && height == out_height) |
2000 | return 0; | 2307 | return 0; |
2001 | 2308 | ||
2002 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) | 2309 | if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) |
2003 | return -EINVAL; | 2310 | return -EINVAL; |
2004 | 2311 | ||
2005 | *x_predecim = max_decim_limit; | 2312 | *x_predecim = max_decim_limit; |
2006 | *y_predecim = max_decim_limit; | 2313 | *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && |
2314 | dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; | ||
2007 | 2315 | ||
2008 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || | 2316 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || |
2009 | color_mode == OMAP_DSS_COLOR_CLUT2 || | 2317 | color_mode == OMAP_DSS_COLOR_CLUT2 || |
@@ -2018,118 +2326,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
2018 | decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); | 2326 | decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); |
2019 | decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); | 2327 | decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); |
2020 | 2328 | ||
2021 | min_factor = min(decim_x, decim_y); | ||
2022 | |||
2023 | if (decim_x > *x_predecim || out_width > width * 8) | 2329 | if (decim_x > *x_predecim || out_width > width * 8) |
2024 | return -EINVAL; | 2330 | return -EINVAL; |
2025 | 2331 | ||
2026 | if (decim_y > *y_predecim || out_height > height * 8) | 2332 | if (decim_y > *y_predecim || out_height > height * 8) |
2027 | return -EINVAL; | 2333 | return -EINVAL; |
2028 | 2334 | ||
2029 | if (cpu_is_omap24xx()) { | 2335 | ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, |
2030 | *five_taps = false; | 2336 | out_width, out_height, color_mode, five_taps, |
2031 | 2337 | x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, | |
2032 | do { | 2338 | mem_to_mem); |
2033 | in_height = DIV_ROUND_UP(height, decim_y); | 2339 | if (ret) |
2034 | in_width = DIV_ROUND_UP(width, decim_x); | 2340 | return ret; |
2035 | core_clk = calc_core_clk(channel, in_width, in_height, | ||
2036 | out_width, out_height); | ||
2037 | error = (in_width > maxsinglelinewidth || !core_clk || | ||
2038 | core_clk > dispc_core_clk_rate()); | ||
2039 | if (error) { | ||
2040 | if (decim_x == decim_y) { | ||
2041 | decim_x = min_factor; | ||
2042 | decim_y++; | ||
2043 | } else { | ||
2044 | swap(decim_x, decim_y); | ||
2045 | if (decim_x < decim_y) | ||
2046 | decim_x++; | ||
2047 | } | ||
2048 | } | ||
2049 | } while (decim_x <= *x_predecim && decim_y <= *y_predecim && | ||
2050 | error); | ||
2051 | |||
2052 | if (in_width > maxsinglelinewidth) { | ||
2053 | DSSERR("Cannot scale max input width exceeded"); | ||
2054 | return -EINVAL; | ||
2055 | } | ||
2056 | } else if (cpu_is_omap34xx()) { | ||
2057 | |||
2058 | do { | ||
2059 | in_height = DIV_ROUND_UP(height, decim_y); | ||
2060 | in_width = DIV_ROUND_UP(width, decim_x); | ||
2061 | core_clk = calc_core_clk_five_taps(channel, mgr_timings, | ||
2062 | in_width, in_height, out_width, out_height, | ||
2063 | color_mode); | ||
2064 | |||
2065 | error = check_horiz_timing_omap3(channel, mgr_timings, | ||
2066 | pos_x, in_width, in_height, out_width, | ||
2067 | out_height); | ||
2068 | |||
2069 | if (in_width > maxsinglelinewidth) | ||
2070 | if (in_height > out_height && | ||
2071 | in_height < out_height * 2) | ||
2072 | *five_taps = false; | ||
2073 | if (!*five_taps) | ||
2074 | core_clk = calc_core_clk(channel, in_width, | ||
2075 | in_height, out_width, out_height); | ||
2076 | error = (error || in_width > maxsinglelinewidth * 2 || | ||
2077 | (in_width > maxsinglelinewidth && *five_taps) || | ||
2078 | !core_clk || core_clk > dispc_core_clk_rate()); | ||
2079 | if (error) { | ||
2080 | if (decim_x == decim_y) { | ||
2081 | decim_x = min_factor; | ||
2082 | decim_y++; | ||
2083 | } else { | ||
2084 | swap(decim_x, decim_y); | ||
2085 | if (decim_x < decim_y) | ||
2086 | decim_x++; | ||
2087 | } | ||
2088 | } | ||
2089 | } while (decim_x <= *x_predecim && decim_y <= *y_predecim | ||
2090 | && error); | ||
2091 | |||
2092 | if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, | ||
2093 | height, out_width, out_height)){ | ||
2094 | DSSERR("horizontal timing too tight\n"); | ||
2095 | return -EINVAL; | ||
2096 | } | ||
2097 | |||
2098 | if (in_width > (maxsinglelinewidth * 2)) { | ||
2099 | DSSERR("Cannot setup scaling"); | ||
2100 | DSSERR("width exceeds maximum width possible"); | ||
2101 | return -EINVAL; | ||
2102 | } | ||
2103 | |||
2104 | if (in_width > maxsinglelinewidth && *five_taps) { | ||
2105 | DSSERR("cannot setup scaling with five taps"); | ||
2106 | return -EINVAL; | ||
2107 | } | ||
2108 | } else { | ||
2109 | int decim_x_min = decim_x; | ||
2110 | in_height = DIV_ROUND_UP(height, decim_y); | ||
2111 | in_width_max = dispc_core_clk_rate() / | ||
2112 | DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), | ||
2113 | out_width); | ||
2114 | decim_x = DIV_ROUND_UP(width, in_width_max); | ||
2115 | |||
2116 | decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; | ||
2117 | if (decim_x > *x_predecim) | ||
2118 | return -EINVAL; | ||
2119 | |||
2120 | do { | ||
2121 | in_width = DIV_ROUND_UP(width, decim_x); | ||
2122 | } while (decim_x <= *x_predecim && | ||
2123 | in_width > maxsinglelinewidth && decim_x++); | ||
2124 | |||
2125 | if (in_width > maxsinglelinewidth) { | ||
2126 | DSSERR("Cannot scale width exceeds max line width"); | ||
2127 | return -EINVAL; | ||
2128 | } | ||
2129 | |||
2130 | core_clk = calc_core_clk(channel, in_width, in_height, | ||
2131 | out_width, out_height); | ||
2132 | } | ||
2133 | 2341 | ||
2134 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); | 2342 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); |
2135 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); | 2343 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); |
@@ -2147,69 +2355,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
2147 | return 0; | 2355 | return 0; |
2148 | } | 2356 | } |
2149 | 2357 | ||
2150 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 2358 | static int dispc_ovl_setup_common(enum omap_plane plane, |
2151 | bool replication, const struct omap_video_timings *mgr_timings) | 2359 | enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, |
2360 | u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, | ||
2361 | u16 out_width, u16 out_height, enum omap_color_mode color_mode, | ||
2362 | u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha, | ||
2363 | u8 global_alpha, enum omap_dss_rotation_type rotation_type, | ||
2364 | bool replication, const struct omap_video_timings *mgr_timings, | ||
2365 | bool mem_to_mem) | ||
2152 | { | 2366 | { |
2153 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | ||
2154 | bool five_taps = true; | 2367 | bool five_taps = true; |
2155 | bool fieldmode = 0; | 2368 | bool fieldmode = 0; |
2156 | int r, cconv = 0; | 2369 | int r, cconv = 0; |
2157 | unsigned offset0, offset1; | 2370 | unsigned offset0, offset1; |
2158 | s32 row_inc; | 2371 | s32 row_inc; |
2159 | s32 pix_inc; | 2372 | s32 pix_inc; |
2160 | u16 frame_height = oi->height; | 2373 | u16 frame_height = height; |
2161 | unsigned int field_offset = 0; | 2374 | unsigned int field_offset = 0; |
2162 | u16 in_height = oi->height; | 2375 | u16 in_height = height; |
2163 | u16 in_width = oi->width; | 2376 | u16 in_width = width; |
2164 | u16 out_width, out_height; | ||
2165 | enum omap_channel channel; | ||
2166 | int x_predecim = 1, y_predecim = 1; | 2377 | int x_predecim = 1, y_predecim = 1; |
2167 | bool ilace = mgr_timings->interlace; | 2378 | bool ilace = mgr_timings->interlace; |
2168 | 2379 | ||
2169 | channel = dispc_ovl_get_channel_out(plane); | 2380 | if (paddr == 0) |
2170 | |||
2171 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | ||
2172 | "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", | ||
2173 | plane, oi->paddr, oi->p_uv_addr, | ||
2174 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | ||
2175 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | ||
2176 | oi->mirror, ilace, channel, replication); | ||
2177 | |||
2178 | if (oi->paddr == 0) | ||
2179 | return -EINVAL; | 2381 | return -EINVAL; |
2180 | 2382 | ||
2181 | out_width = oi->out_width == 0 ? oi->width : oi->out_width; | 2383 | out_width = out_width == 0 ? width : out_width; |
2182 | out_height = oi->out_height == 0 ? oi->height : oi->out_height; | 2384 | out_height = out_height == 0 ? height : out_height; |
2183 | 2385 | ||
2184 | if (ilace && oi->height == out_height) | 2386 | if (ilace && height == out_height) |
2185 | fieldmode = 1; | 2387 | fieldmode = 1; |
2186 | 2388 | ||
2187 | if (ilace) { | 2389 | if (ilace) { |
2188 | if (fieldmode) | 2390 | if (fieldmode) |
2189 | in_height /= 2; | 2391 | in_height /= 2; |
2190 | oi->pos_y /= 2; | 2392 | pos_y /= 2; |
2191 | out_height /= 2; | 2393 | out_height /= 2; |
2192 | 2394 | ||
2193 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " | 2395 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " |
2194 | "out_height %d\n", | 2396 | "out_height %d\n", in_height, pos_y, |
2195 | in_height, oi->pos_y, out_height); | 2397 | out_height); |
2196 | } | 2398 | } |
2197 | 2399 | ||
2198 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | 2400 | if (!dss_feat_color_mode_supported(plane, color_mode)) |
2199 | return -EINVAL; | 2401 | return -EINVAL; |
2200 | 2402 | ||
2201 | r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, | 2403 | r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, |
2202 | in_height, out_width, out_height, oi->color_mode, | 2404 | in_height, out_width, out_height, color_mode, |
2203 | &five_taps, &x_predecim, &y_predecim, oi->pos_x); | 2405 | &five_taps, &x_predecim, &y_predecim, pos_x, |
2406 | rotation_type, mem_to_mem); | ||
2204 | if (r) | 2407 | if (r) |
2205 | return r; | 2408 | return r; |
2206 | 2409 | ||
2207 | in_width = DIV_ROUND_UP(in_width, x_predecim); | 2410 | in_width = DIV_ROUND_UP(in_width, x_predecim); |
2208 | in_height = DIV_ROUND_UP(in_height, y_predecim); | 2411 | in_height = DIV_ROUND_UP(in_height, y_predecim); |
2209 | 2412 | ||
2210 | if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || | 2413 | if (color_mode == OMAP_DSS_COLOR_YUV2 || |
2211 | oi->color_mode == OMAP_DSS_COLOR_UYVY || | 2414 | color_mode == OMAP_DSS_COLOR_UYVY || |
2212 | oi->color_mode == OMAP_DSS_COLOR_NV12) | 2415 | color_mode == OMAP_DSS_COLOR_NV12) |
2213 | cconv = 1; | 2416 | cconv = 1; |
2214 | 2417 | ||
2215 | if (ilace && !fieldmode) { | 2418 | if (ilace && !fieldmode) { |
@@ -2235,70 +2438,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
2235 | row_inc = 0; | 2438 | row_inc = 0; |
2236 | pix_inc = 0; | 2439 | pix_inc = 0; |
2237 | 2440 | ||
2238 | if (oi->rotation_type == OMAP_DSS_ROT_TILER) | 2441 | if (rotation_type == OMAP_DSS_ROT_TILER) |
2239 | calc_tiler_rotation_offset(oi->screen_width, in_width, | 2442 | calc_tiler_rotation_offset(screen_width, in_width, |
2240 | oi->color_mode, fieldmode, field_offset, | 2443 | color_mode, fieldmode, field_offset, |
2241 | &offset0, &offset1, &row_inc, &pix_inc, | 2444 | &offset0, &offset1, &row_inc, &pix_inc, |
2242 | x_predecim, y_predecim); | 2445 | x_predecim, y_predecim); |
2243 | else if (oi->rotation_type == OMAP_DSS_ROT_DMA) | 2446 | else if (rotation_type == OMAP_DSS_ROT_DMA) |
2244 | calc_dma_rotation_offset(oi->rotation, oi->mirror, | 2447 | calc_dma_rotation_offset(rotation, mirror, |
2245 | oi->screen_width, in_width, frame_height, | 2448 | screen_width, in_width, frame_height, |
2246 | oi->color_mode, fieldmode, field_offset, | 2449 | color_mode, fieldmode, field_offset, |
2247 | &offset0, &offset1, &row_inc, &pix_inc, | 2450 | &offset0, &offset1, &row_inc, &pix_inc, |
2248 | x_predecim, y_predecim); | 2451 | x_predecim, y_predecim); |
2249 | else | 2452 | else |
2250 | calc_vrfb_rotation_offset(oi->rotation, oi->mirror, | 2453 | calc_vrfb_rotation_offset(rotation, mirror, |
2251 | oi->screen_width, in_width, frame_height, | 2454 | screen_width, in_width, frame_height, |
2252 | oi->color_mode, fieldmode, field_offset, | 2455 | color_mode, fieldmode, field_offset, |
2253 | &offset0, &offset1, &row_inc, &pix_inc, | 2456 | &offset0, &offset1, &row_inc, &pix_inc, |
2254 | x_predecim, y_predecim); | 2457 | x_predecim, y_predecim); |
2255 | 2458 | ||
2256 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", | 2459 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", |
2257 | offset0, offset1, row_inc, pix_inc); | 2460 | offset0, offset1, row_inc, pix_inc); |
2258 | 2461 | ||
2259 | dispc_ovl_set_color_mode(plane, oi->color_mode); | 2462 | dispc_ovl_set_color_mode(plane, color_mode); |
2260 | 2463 | ||
2261 | dispc_ovl_configure_burst_type(plane, oi->rotation_type); | 2464 | dispc_ovl_configure_burst_type(plane, rotation_type); |
2262 | 2465 | ||
2263 | dispc_ovl_set_ba0(plane, oi->paddr + offset0); | 2466 | dispc_ovl_set_ba0(plane, paddr + offset0); |
2264 | dispc_ovl_set_ba1(plane, oi->paddr + offset1); | 2467 | dispc_ovl_set_ba1(plane, paddr + offset1); |
2265 | 2468 | ||
2266 | if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { | 2469 | if (OMAP_DSS_COLOR_NV12 == color_mode) { |
2267 | dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); | 2470 | dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); |
2268 | dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); | 2471 | dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); |
2269 | } | 2472 | } |
2270 | 2473 | ||
2271 | |||
2272 | dispc_ovl_set_row_inc(plane, row_inc); | 2474 | dispc_ovl_set_row_inc(plane, row_inc); |
2273 | dispc_ovl_set_pix_inc(plane, pix_inc); | 2475 | dispc_ovl_set_pix_inc(plane, pix_inc); |
2274 | 2476 | ||
2275 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, | 2477 | DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, |
2276 | in_height, out_width, out_height); | 2478 | in_height, out_width, out_height); |
2277 | 2479 | ||
2278 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); | 2480 | dispc_ovl_set_pos(plane, caps, pos_x, pos_y); |
2279 | 2481 | ||
2280 | dispc_ovl_set_pic_size(plane, in_width, in_height); | 2482 | dispc_ovl_set_input_size(plane, in_width, in_height); |
2281 | 2483 | ||
2282 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { | 2484 | if (caps & OMAP_DSS_OVL_CAP_SCALE) { |
2283 | dispc_ovl_set_scaling(plane, in_width, in_height, out_width, | 2485 | dispc_ovl_set_scaling(plane, in_width, in_height, out_width, |
2284 | out_height, ilace, five_taps, fieldmode, | 2486 | out_height, ilace, five_taps, fieldmode, |
2285 | oi->color_mode, oi->rotation); | 2487 | color_mode, rotation); |
2286 | dispc_ovl_set_vid_size(plane, out_width, out_height); | 2488 | dispc_ovl_set_output_size(plane, out_width, out_height); |
2287 | dispc_ovl_set_vid_color_conv(plane, cconv); | 2489 | dispc_ovl_set_vid_color_conv(plane, cconv); |
2288 | } | 2490 | } |
2289 | 2491 | ||
2290 | dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, | 2492 | dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); |
2291 | oi->color_mode); | ||
2292 | 2493 | ||
2293 | dispc_ovl_set_zorder(plane, oi->zorder); | 2494 | dispc_ovl_set_zorder(plane, caps, zorder); |
2294 | dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); | 2495 | dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); |
2295 | dispc_ovl_setup_global_alpha(plane, oi->global_alpha); | 2496 | dispc_ovl_setup_global_alpha(plane, caps, global_alpha); |
2296 | 2497 | ||
2297 | dispc_ovl_enable_replication(plane, replication); | 2498 | dispc_ovl_enable_replication(plane, caps, replication); |
2298 | 2499 | ||
2299 | return 0; | 2500 | return 0; |
2300 | } | 2501 | } |
2301 | 2502 | ||
2503 | int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | ||
2504 | bool replication, const struct omap_video_timings *mgr_timings, | ||
2505 | bool mem_to_mem) | ||
2506 | { | ||
2507 | int r; | ||
2508 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | ||
2509 | enum omap_channel channel; | ||
2510 | |||
2511 | channel = dispc_ovl_get_channel_out(plane); | ||
2512 | |||
2513 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | ||
2514 | "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", | ||
2515 | plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, | ||
2516 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, | ||
2517 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); | ||
2518 | |||
2519 | r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, | ||
2520 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | ||
2521 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | ||
2522 | oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, | ||
2523 | oi->rotation_type, replication, mgr_timings, mem_to_mem); | ||
2524 | |||
2525 | return r; | ||
2526 | } | ||
2527 | |||
2528 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | ||
2529 | bool mem_to_mem, const struct omap_video_timings *mgr_timings) | ||
2530 | { | ||
2531 | int r; | ||
2532 | u32 l; | ||
2533 | enum omap_plane plane = OMAP_DSS_WB; | ||
2534 | const int pos_x = 0, pos_y = 0; | ||
2535 | const u8 zorder = 0, global_alpha = 0; | ||
2536 | const bool replication = false; | ||
2537 | bool truncation; | ||
2538 | int in_width = mgr_timings->x_res; | ||
2539 | int in_height = mgr_timings->y_res; | ||
2540 | enum omap_overlay_caps caps = | ||
2541 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; | ||
2542 | |||
2543 | DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " | ||
2544 | "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width, | ||
2545 | in_height, wi->width, wi->height, wi->color_mode, wi->rotation, | ||
2546 | wi->mirror); | ||
2547 | |||
2548 | r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, | ||
2549 | wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, | ||
2550 | wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder, | ||
2551 | wi->pre_mult_alpha, global_alpha, wi->rotation_type, | ||
2552 | replication, mgr_timings, mem_to_mem); | ||
2553 | |||
2554 | switch (wi->color_mode) { | ||
2555 | case OMAP_DSS_COLOR_RGB16: | ||
2556 | case OMAP_DSS_COLOR_RGB24P: | ||
2557 | case OMAP_DSS_COLOR_ARGB16: | ||
2558 | case OMAP_DSS_COLOR_RGBA16: | ||
2559 | case OMAP_DSS_COLOR_RGB12U: | ||
2560 | case OMAP_DSS_COLOR_ARGB16_1555: | ||
2561 | case OMAP_DSS_COLOR_XRGB16_1555: | ||
2562 | case OMAP_DSS_COLOR_RGBX16: | ||
2563 | truncation = true; | ||
2564 | break; | ||
2565 | default: | ||
2566 | truncation = false; | ||
2567 | break; | ||
2568 | } | ||
2569 | |||
2570 | /* setup extra DISPC_WB_ATTRIBUTES */ | ||
2571 | l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | ||
2572 | l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ | ||
2573 | l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ | ||
2574 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); | ||
2575 | |||
2576 | return r; | ||
2577 | } | ||
2578 | |||
2302 | int dispc_ovl_enable(enum omap_plane plane, bool enable) | 2579 | int dispc_ovl_enable(enum omap_plane plane, bool enable) |
2303 | { | 2580 | { |
2304 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); | 2581 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); |
@@ -2451,6 +2728,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable) | |||
2451 | BUG(); | 2728 | BUG(); |
2452 | } | 2729 | } |
2453 | 2730 | ||
2731 | void dispc_wb_enable(bool enable) | ||
2732 | { | ||
2733 | enum omap_plane plane = OMAP_DSS_WB; | ||
2734 | struct completion frame_done_completion; | ||
2735 | bool is_on; | ||
2736 | int r; | ||
2737 | u32 irq; | ||
2738 | |||
2739 | is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | ||
2740 | irq = DISPC_IRQ_FRAMEDONEWB; | ||
2741 | |||
2742 | if (!enable && is_on) { | ||
2743 | init_completion(&frame_done_completion); | ||
2744 | |||
2745 | r = omap_dispc_register_isr(dispc_disable_isr, | ||
2746 | &frame_done_completion, irq); | ||
2747 | if (r) | ||
2748 | DSSERR("failed to register FRAMEDONEWB isr\n"); | ||
2749 | } | ||
2750 | |||
2751 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); | ||
2752 | |||
2753 | if (!enable && is_on) { | ||
2754 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
2755 | msecs_to_jiffies(100))) | ||
2756 | DSSERR("timeout waiting for FRAMEDONEWB\n"); | ||
2757 | |||
2758 | r = omap_dispc_unregister_isr(dispc_disable_isr, | ||
2759 | &frame_done_completion, irq); | ||
2760 | if (r) | ||
2761 | DSSERR("failed to unregister FRAMEDONEWB isr\n"); | ||
2762 | } | ||
2763 | } | ||
2764 | |||
2765 | bool dispc_wb_is_enabled(void) | ||
2766 | { | ||
2767 | enum omap_plane plane = OMAP_DSS_WB; | ||
2768 | |||
2769 | return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | ||
2770 | } | ||
2771 | |||
2454 | void dispc_lcd_enable_signal_polarity(bool act_high) | 2772 | void dispc_lcd_enable_signal_polarity(bool act_high) |
2455 | { | 2773 | { |
2456 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) | 2774 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) |
@@ -2605,24 +2923,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height) | |||
2605 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | 2923 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, |
2606 | int vsw, int vfp, int vbp) | 2924 | int vsw, int vfp, int vbp) |
2607 | { | 2925 | { |
2608 | if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { | 2926 | if (hsw < 1 || hsw > dispc.feat->sw_max || |
2609 | if (hsw < 1 || hsw > 64 || | 2927 | hfp < 1 || hfp > dispc.feat->hp_max || |
2610 | hfp < 1 || hfp > 256 || | 2928 | hbp < 1 || hbp > dispc.feat->hp_max || |
2611 | hbp < 1 || hbp > 256 || | 2929 | vsw < 1 || vsw > dispc.feat->sw_max || |
2612 | vsw < 1 || vsw > 64 || | 2930 | vfp < 0 || vfp > dispc.feat->vp_max || |
2613 | vfp < 0 || vfp > 255 || | 2931 | vbp < 0 || vbp > dispc.feat->vp_max) |
2614 | vbp < 0 || vbp > 255) | 2932 | return false; |
2615 | return false; | ||
2616 | } else { | ||
2617 | if (hsw < 1 || hsw > 256 || | ||
2618 | hfp < 1 || hfp > 4096 || | ||
2619 | hbp < 1 || hbp > 4096 || | ||
2620 | vsw < 1 || vsw > 256 || | ||
2621 | vfp < 0 || vfp > 4095 || | ||
2622 | vbp < 0 || vbp > 4095) | ||
2623 | return false; | ||
2624 | } | ||
2625 | |||
2626 | return true; | 2933 | return true; |
2627 | } | 2934 | } |
2628 | 2935 | ||
@@ -2654,19 +2961,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | |||
2654 | u32 timing_h, timing_v, l; | 2961 | u32 timing_h, timing_v, l; |
2655 | bool onoff, rf, ipc; | 2962 | bool onoff, rf, ipc; |
2656 | 2963 | ||
2657 | if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { | 2964 | timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | |
2658 | timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | | 2965 | FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | |
2659 | FLD_VAL(hbp-1, 27, 20); | 2966 | FLD_VAL(hbp-1, dispc.feat->bp_start, 20); |
2660 | 2967 | timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) | | |
2661 | timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | | 2968 | FLD_VAL(vfp, dispc.feat->fp_start, 8) | |
2662 | FLD_VAL(vbp, 27, 20); | 2969 | FLD_VAL(vbp, dispc.feat->bp_start, 20); |
2663 | } else { | ||
2664 | timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | | ||
2665 | FLD_VAL(hbp-1, 31, 20); | ||
2666 | |||
2667 | timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | | ||
2668 | FLD_VAL(vbp, 31, 20); | ||
2669 | } | ||
2670 | 2970 | ||
2671 | dispc_write_reg(DISPC_TIMING_H(channel), timing_h); | 2971 | dispc_write_reg(DISPC_TIMING_H(channel), timing_h); |
2672 | dispc_write_reg(DISPC_TIMING_V(channel), timing_v); | 2972 | dispc_write_reg(DISPC_TIMING_V(channel), timing_v); |
@@ -2872,6 +3172,23 @@ unsigned long dispc_core_clk_rate(void) | |||
2872 | return fclk / lcd; | 3172 | return fclk / lcd; |
2873 | } | 3173 | } |
2874 | 3174 | ||
3175 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) | ||
3176 | { | ||
3177 | enum omap_channel channel = dispc_ovl_get_channel_out(plane); | ||
3178 | |||
3179 | return dispc_mgr_pclk_rate(channel); | ||
3180 | } | ||
3181 | |||
3182 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) | ||
3183 | { | ||
3184 | enum omap_channel channel = dispc_ovl_get_channel_out(plane); | ||
3185 | |||
3186 | if (dss_mgr_is_lcd(channel)) | ||
3187 | return dispc_mgr_lclk_rate(channel); | ||
3188 | else | ||
3189 | return dispc_fclk_rate(); | ||
3190 | |||
3191 | } | ||
2875 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) | 3192 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) |
2876 | { | 3193 | { |
2877 | int lcd, pcd; | 3194 | int lcd, pcd; |
@@ -3492,7 +3809,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
3492 | ovl->name); | 3809 | ovl->name); |
3493 | dispc_ovl_enable(ovl->id, false); | 3810 | dispc_ovl_enable(ovl->id, false); |
3494 | dispc_mgr_go(ovl->manager->id); | 3811 | dispc_mgr_go(ovl->manager->id); |
3495 | mdelay(50); | 3812 | msleep(50); |
3496 | } | 3813 | } |
3497 | } | 3814 | } |
3498 | 3815 | ||
@@ -3504,7 +3821,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
3504 | bit = mgr_desc[i].sync_lost_irq; | 3821 | bit = mgr_desc[i].sync_lost_irq; |
3505 | 3822 | ||
3506 | if (bit & errors) { | 3823 | if (bit & errors) { |
3507 | struct omap_dss_device *dssdev = mgr->device; | 3824 | struct omap_dss_device *dssdev = mgr->get_device(mgr); |
3508 | bool enable; | 3825 | bool enable; |
3509 | 3826 | ||
3510 | DSSERR("SYNC_LOST on channel %s, restarting the output " | 3827 | DSSERR("SYNC_LOST on channel %s, restarting the output " |
@@ -3524,7 +3841,7 @@ static void dispc_error_worker(struct work_struct *work) | |||
3524 | } | 3841 | } |
3525 | 3842 | ||
3526 | dispc_mgr_go(mgr->id); | 3843 | dispc_mgr_go(mgr->id); |
3527 | mdelay(50); | 3844 | msleep(50); |
3528 | 3845 | ||
3529 | if (enable) | 3846 | if (enable) |
3530 | dssdev->driver->enable(dssdev); | 3847 | dssdev->driver->enable(dssdev); |
@@ -3535,9 +3852,13 @@ static void dispc_error_worker(struct work_struct *work) | |||
3535 | DSSERR("OCP_ERR\n"); | 3852 | DSSERR("OCP_ERR\n"); |
3536 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | 3853 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
3537 | struct omap_overlay_manager *mgr; | 3854 | struct omap_overlay_manager *mgr; |
3855 | struct omap_dss_device *dssdev; | ||
3856 | |||
3538 | mgr = omap_dss_get_overlay_manager(i); | 3857 | mgr = omap_dss_get_overlay_manager(i); |
3539 | if (mgr->device && mgr->device->driver) | 3858 | dssdev = mgr->get_device(mgr); |
3540 | mgr->device->driver->disable(mgr->device); | 3859 | |
3860 | if (dssdev && dssdev->driver) | ||
3861 | dssdev->driver->disable(dssdev); | ||
3541 | } | 3862 | } |
3542 | } | 3863 | } |
3543 | 3864 | ||
@@ -3661,17 +3982,98 @@ static void _omap_dispc_initial_config(void) | |||
3661 | if (dss_has_feature(FEAT_FUNCGATED)) | 3982 | if (dss_has_feature(FEAT_FUNCGATED)) |
3662 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); | 3983 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); |
3663 | 3984 | ||
3664 | _dispc_setup_color_conv_coef(); | 3985 | dispc_setup_color_conv_coef(); |
3665 | 3986 | ||
3666 | dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); | 3987 | dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); |
3667 | 3988 | ||
3668 | dispc_read_plane_fifo_sizes(); | 3989 | dispc_init_fifos(); |
3669 | 3990 | ||
3670 | dispc_configure_burst_sizes(); | 3991 | dispc_configure_burst_sizes(); |
3671 | 3992 | ||
3672 | dispc_ovl_enable_zorder_planes(); | 3993 | dispc_ovl_enable_zorder_planes(); |
3673 | } | 3994 | } |
3674 | 3995 | ||
3996 | static const struct dispc_features omap24xx_dispc_feats __initconst = { | ||
3997 | .sw_start = 5, | ||
3998 | .fp_start = 15, | ||
3999 | .bp_start = 27, | ||
4000 | .sw_max = 64, | ||
4001 | .vp_max = 255, | ||
4002 | .hp_max = 256, | ||
4003 | .calc_scaling = dispc_ovl_calc_scaling_24xx, | ||
4004 | .calc_core_clk = calc_core_clk_24xx, | ||
4005 | .num_fifos = 3, | ||
4006 | }; | ||
4007 | |||
4008 | static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { | ||
4009 | .sw_start = 5, | ||
4010 | .fp_start = 15, | ||
4011 | .bp_start = 27, | ||
4012 | .sw_max = 64, | ||
4013 | .vp_max = 255, | ||
4014 | .hp_max = 256, | ||
4015 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | ||
4016 | .calc_core_clk = calc_core_clk_34xx, | ||
4017 | .num_fifos = 3, | ||
4018 | }; | ||
4019 | |||
4020 | static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { | ||
4021 | .sw_start = 7, | ||
4022 | .fp_start = 19, | ||
4023 | .bp_start = 31, | ||
4024 | .sw_max = 256, | ||
4025 | .vp_max = 4095, | ||
4026 | .hp_max = 4096, | ||
4027 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | ||
4028 | .calc_core_clk = calc_core_clk_34xx, | ||
4029 | .num_fifos = 3, | ||
4030 | }; | ||
4031 | |||
4032 | static const struct dispc_features omap44xx_dispc_feats __initconst = { | ||
4033 | .sw_start = 7, | ||
4034 | .fp_start = 19, | ||
4035 | .bp_start = 31, | ||
4036 | .sw_max = 256, | ||
4037 | .vp_max = 4095, | ||
4038 | .hp_max = 4096, | ||
4039 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | ||
4040 | .calc_core_clk = calc_core_clk_44xx, | ||
4041 | .num_fifos = 5, | ||
4042 | .gfx_fifo_workaround = true, | ||
4043 | }; | ||
4044 | |||
4045 | static int __init dispc_init_features(struct device *dev) | ||
4046 | { | ||
4047 | const struct dispc_features *src; | ||
4048 | struct dispc_features *dst; | ||
4049 | |||
4050 | dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); | ||
4051 | if (!dst) { | ||
4052 | dev_err(dev, "Failed to allocate DISPC Features\n"); | ||
4053 | return -ENOMEM; | ||
4054 | } | ||
4055 | |||
4056 | if (cpu_is_omap24xx()) { | ||
4057 | src = &omap24xx_dispc_feats; | ||
4058 | } else if (cpu_is_omap34xx()) { | ||
4059 | if (omap_rev() < OMAP3430_REV_ES3_0) | ||
4060 | src = &omap34xx_rev1_0_dispc_feats; | ||
4061 | else | ||
4062 | src = &omap34xx_rev3_0_dispc_feats; | ||
4063 | } else if (cpu_is_omap44xx()) { | ||
4064 | src = &omap44xx_dispc_feats; | ||
4065 | } else if (soc_is_omap54xx()) { | ||
4066 | src = &omap44xx_dispc_feats; | ||
4067 | } else { | ||
4068 | return -ENODEV; | ||
4069 | } | ||
4070 | |||
4071 | memcpy(dst, src, sizeof(*dst)); | ||
4072 | dispc.feat = dst; | ||
4073 | |||
4074 | return 0; | ||
4075 | } | ||
4076 | |||
3675 | /* DISPC HW IP initialisation */ | 4077 | /* DISPC HW IP initialisation */ |
3676 | static int __init omap_dispchw_probe(struct platform_device *pdev) | 4078 | static int __init omap_dispchw_probe(struct platform_device *pdev) |
3677 | { | 4079 | { |
@@ -3682,6 +4084,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
3682 | 4084 | ||
3683 | dispc.pdev = pdev; | 4085 | dispc.pdev = pdev; |
3684 | 4086 | ||
4087 | r = dispc_init_features(&dispc.pdev->dev); | ||
4088 | if (r) | ||
4089 | return r; | ||
4090 | |||
3685 | spin_lock_init(&dispc.irq_lock); | 4091 | spin_lock_init(&dispc.irq_lock); |
3686 | 4092 | ||
3687 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 4093 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |