aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/dispc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss/dispc.c')
-rw-r--r--drivers/video/omap2/dss/dispc.c1018
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
84struct 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
85static struct { 108static 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
241struct color_conv_coef {
242 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
243 int full_range;
244};
245
214static void _omap_dispc_set_irqs(void); 246static void _omap_dispc_set_irqs(void);
247static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
248static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
215 249
216static inline void dispc_write_reg(const u16 idx, u32 val) 250static 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
546u32 dispc_wb_get_framedone_irq(void)
547{
548 return DISPC_IRQ_FRAMEDONEWB;
549}
550
512bool dispc_mgr_go_busy(enum omap_channel channel) 551bool 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
578bool dispc_wb_go_busy(void)
579{
580 return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
581}
582
583void 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
539static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) 602static 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
621static 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
685static 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
701static 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
657static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) 720static 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
677static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) 740static 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
684static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) 753static 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
694static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) 764static 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
705static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) 779static 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
726static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) 799static 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
736static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) 808static 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
1022void 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
950static void dispc_ovl_set_burst_size(enum omap_plane plane, 1029static 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
1030static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) 1109static 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
1048static void dispc_read_plane_fifo_sizes(void) 1131static 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
1066static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) 1178static 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
1071void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) 1191void 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 */
1851static int check_horiz_timing_omap3(enum omap_channel channel, 1994static 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
1903static unsigned long calc_core_clk_five_taps(enum omap_channel channel, 2043static 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
1943static unsigned long calc_core_clk(enum omap_channel channel, u16 width, 2084static 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
2095static 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 2122static 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
2144static 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
1983static int dispc_ovl_calc_scaling(enum omap_plane plane, 2185static 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
2251static 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
2293static 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
2150int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, 2358static 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
2503int 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
2528int 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
2302int dispc_ovl_enable(enum omap_plane plane, bool enable) 2579int 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
2731void 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
2765bool 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
2454void dispc_lcd_enable_signal_polarity(bool act_high) 2772void 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)
2605static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, 2923static 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
3175static 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
3182static 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}
2875static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) 3192static 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
3996static 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
4008static 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
4020static 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
4032static 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
4045static 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 */
3676static int __init omap_dispchw_probe(struct platform_device *pdev) 4078static 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