aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/plat-omap/include/plat/dsscomp.h23
-rw-r--r--drivers/gpu/pvr/omaplfb/omaplfb_linux.c20
-rw-r--r--drivers/video/omap2/Kconfig1
-rw-r--r--drivers/video/omap2/Makefile1
-rw-r--r--drivers/video/omap2/dss/dispc.c932
-rw-r--r--drivers/video/omap2/dss/dispc.h57
-rw-r--r--drivers/video/omap2/dss/dss.h19
-rw-r--r--drivers/video/omap2/dss/dss_features.c24
-rw-r--r--drivers/video/omap2/dss/dss_features.h5
-rw-r--r--drivers/video/omap2/dss/manager.c259
-rw-r--r--drivers/video/omap2/dss/overlay.c157
-rw-r--r--drivers/video/omap2/dsscomp/Kconfig9
-rw-r--r--drivers/video/omap2/dsscomp/Makefile2
-rw-r--r--drivers/video/omap2/dsscomp/base.c442
-rw-r--r--drivers/video/omap2/dsscomp/device.c369
-rw-r--r--drivers/video/omap2/dsscomp/dsscomp.h83
-rw-r--r--drivers/video/omap2/dsscomp/queue.c887
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c2
-rw-r--r--include/video/dsscomp.h557
-rw-r--r--include/video/omapdss.h37
20 files changed, 3461 insertions, 425 deletions
diff --git a/arch/arm/plat-omap/include/plat/dsscomp.h b/arch/arm/plat-omap/include/plat/dsscomp.h
new file mode 100644
index 0000000..acafe0f
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/dsscomp.h
@@ -0,0 +1,23 @@
+#ifndef _ARCH_ARM_PLAT_OMAP_DSSCOMP_H
+#define _ARCH_ARM_PLAT_OMAP_DSSCOMP_H
+
+#include <video/omapdss.h>
+
+/* queuing operations */
+typedef struct dsscomp_data *dsscomp_t; /* handle */
+
+dsscomp_t dsscomp_new_sync_id(struct omap_overlay_manager *mgr, u32 sync_id);
+u32 dsscomp_first_sync_id(struct omap_overlay_manager *mgr);
+dsscomp_t dsscomp_find(struct omap_overlay_manager *mgr, u32 sync_id);
+u32 dsscomp_get_ovls(dsscomp_t comp);
+int dsscomp_set_ovl(dsscomp_t comp, struct dss2_ovl_info *ovl);
+int dsscomp_get_ovl(dsscomp_t comp, u32 ix, struct dss2_ovl_info *ovl);
+int dsscomp_set_mgr(dsscomp_t comp, struct dss2_mgr_info *mgr);
+int dsscomp_get_mgr(dsscomp_t comp, struct dss2_mgr_info *mgr);
+int dsscomp_setup(dsscomp_t comp, enum dsscomp_setup_mode mode,
+ struct dss2_rect_t win);
+int dsscomp_apply(dsscomp_t comp);
+int dsscomp_wait(dsscomp_t comp, enum dsscomp_wait_phase phase, int timeout);
+void dsscomp_drop(dsscomp_t c);
+
+#endif
diff --git a/drivers/gpu/pvr/omaplfb/omaplfb_linux.c b/drivers/gpu/pvr/omaplfb/omaplfb_linux.c
index 8aae8f5..07576c8 100644
--- a/drivers/gpu/pvr/omaplfb/omaplfb_linux.c
+++ b/drivers/gpu/pvr/omaplfb/omaplfb_linux.c
@@ -277,6 +277,26 @@ void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer)
}
}
#endif
+
+ {
+ #include <video/dsscomp.h>
+ #include <plat/dsscomp.h>
+
+ struct omapfb_info *ofbi = FB2OFB(psDevInfo->psLINFBInfo);
+ struct omap_overlay_manager *manager;
+ struct omap_overlay *overlay;
+
+ dsscomp_t comp;
+ u32 sync_id;
+
+ overlay = ofbi->overlays[OMAP_DSS_GFX];
+ manager = overlay->manager;
+
+ sync_id = dsscomp_first_sync_id(manager);
+ comp = dsscomp_find(manager, sync_id);
+ dsscomp_apply(comp);
+ }
+
console_unlock();
}
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
index d877c36..97a5bc4 100644
--- a/drivers/video/omap2/Kconfig
+++ b/drivers/video/omap2/Kconfig
@@ -7,3 +7,4 @@ config OMAP2_VRFB
source "drivers/video/omap2/dss/Kconfig"
source "drivers/video/omap2/omapfb/Kconfig"
source "drivers/video/omap2/displays/Kconfig"
+source "drivers/video/omap2/dsscomp/Kconfig"
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
index 5ddef12..2d5a205 100644
--- a/drivers/video/omap2/Makefile
+++ b/drivers/video/omap2/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
obj-$(CONFIG_OMAP2_DSS) += dss/
obj-$(CONFIG_FB_OMAP2) += omapfb/
obj-y += displays/
+obj-y += dsscomp/
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 62aa77c..988d440 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -38,6 +38,7 @@
#include <plat/sram.h>
#include <plat/clock.h>
+#include <mach/tiler.h>
#include <video/omapdss.h>
@@ -102,7 +103,7 @@ static struct {
int irq;
struct clk *dss_clk;
- u32 fifo_size[3];
+ u32 fifo_size[MAX_DSS_OVERLAYS];
u32 channel_irq[3]; /* Max channels hardcoded to 3*/
@@ -169,7 +170,7 @@ static int dispc_get_ctx_loss_count(void)
static void dispc_save_context(void)
{
- int i;
+ int i, o;
DSSDBG("dispc_save_context\n");
@@ -236,105 +237,60 @@ static void dispc_save_context(void)
if (dss_has_feature(FEAT_PRELOAD))
SR(OVL_PRELOAD(OMAP_DSS_GFX));
- /* VID1 */
- SR(OVL_BA0(OMAP_DSS_VIDEO1));
- SR(OVL_BA1(OMAP_DSS_VIDEO1));
- SR(OVL_POSITION(OMAP_DSS_VIDEO1));
- SR(OVL_SIZE(OMAP_DSS_VIDEO1));
- SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
- SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
- SR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
- SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
- SR(OVL_FIR(OMAP_DSS_VIDEO1));
- SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
- SR(OVL_ACCU0(OMAP_DSS_VIDEO1));
- SR(OVL_ACCU1(OMAP_DSS_VIDEO1));
-
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
-
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
-
- for (i = 0; i < 5; i++)
- SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
-
- if (dss_has_feature(FEAT_FIR_COEF_V)) {
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
- }
+ /* VID1-3 */
+ for (o = OMAP_DSS_VIDEO1; o <= OMAP_DSS_VIDEO3; o++) {
+ if (o == OMAP_DSS_VIDEO3 && !dss_has_feature(FEAT_OVL_VID3))
+ continue;
- if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
- SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
- SR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
- SR(OVL_FIR2(OMAP_DSS_VIDEO1));
- SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
- SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+ SR(OVL_BA0(o));
+ SR(OVL_BA1(o));
+ SR(OVL_POSITION(o));
+ SR(OVL_SIZE(o));
+ SR(OVL_ATTRIBUTES(o));
+ SR(OVL_FIFO_THRESHOLD(o));
+ SR(OVL_ROW_INC(o));
+ SR(OVL_PIXEL_INC(o));
+ SR(OVL_FIR(o));
+ SR(OVL_PICTURE_SIZE(o));
+ SR(OVL_ACCU0(o));
+ SR(OVL_ACCU1(o));
for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
+ SR(OVL_FIR_COEF_H(o, i));
for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
+ SR(OVL_FIR_COEF_HV(o, i));
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
- }
- if (dss_has_feature(FEAT_ATTR2))
- SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+ for (i = 0; i < 5; i++)
+ SR(OVL_CONV_COEF(o, i));
- if (dss_has_feature(FEAT_PRELOAD))
- SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
-
- /* VID2 */
- SR(OVL_BA0(OMAP_DSS_VIDEO2));
- SR(OVL_BA1(OMAP_DSS_VIDEO2));
- SR(OVL_POSITION(OMAP_DSS_VIDEO2));
- SR(OVL_SIZE(OMAP_DSS_VIDEO2));
- SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
- SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
- SR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
- SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
- SR(OVL_FIR(OMAP_DSS_VIDEO2));
- SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
- SR(OVL_ACCU0(OMAP_DSS_VIDEO2));
- SR(OVL_ACCU1(OMAP_DSS_VIDEO2));
-
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
-
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
-
- for (i = 0; i < 5; i++)
- SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
-
- if (dss_has_feature(FEAT_FIR_COEF_V)) {
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
- }
+ if (dss_has_feature(FEAT_FIR_COEF_V)) {
+ for (i = 0; i < 8; i++)
+ SR(OVL_FIR_COEF_V(o, i));
+ }
- if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
- SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
- SR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
- SR(OVL_FIR2(OMAP_DSS_VIDEO2));
- SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
- SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ SR(OVL_BA0_UV(o));
+ SR(OVL_BA1_UV(o));
+ SR(OVL_FIR2(o));
+ SR(OVL_ACCU2_0(o));
+ SR(OVL_ACCU2_1(o));
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+ for (i = 0; i < 8; i++)
+ SR(OVL_FIR_COEF_H2(o, i));
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+ for (i = 0; i < 8; i++)
+ SR(OVL_FIR_COEF_HV2(o, i));
- for (i = 0; i < 8; i++)
- SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
- }
- if (dss_has_feature(FEAT_ATTR2))
- SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+ for (i = 0; i < 8; i++)
+ SR(OVL_FIR_COEF_V2(o, i));
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ SR(OVL_ATTRIBUTES2(o));
- if (dss_has_feature(FEAT_PRELOAD))
- SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
+ if (dss_has_feature(FEAT_PRELOAD))
+ SR(OVL_PRELOAD(o));
+ }
if (dss_has_feature(FEAT_CORE_CLK_DIV))
SR(DIVISOR);
@@ -347,7 +303,7 @@ static void dispc_save_context(void)
static void dispc_restore_context(void)
{
- int i, ctx;
+ int i, o, ctx;
DSSDBG("dispc_restore_context\n");
@@ -425,105 +381,61 @@ static void dispc_restore_context(void)
if (dss_has_feature(FEAT_PRELOAD))
RR(OVL_PRELOAD(OMAP_DSS_GFX));
- /* VID1 */
- RR(OVL_BA0(OMAP_DSS_VIDEO1));
- RR(OVL_BA1(OMAP_DSS_VIDEO1));
- RR(OVL_POSITION(OMAP_DSS_VIDEO1));
- RR(OVL_SIZE(OMAP_DSS_VIDEO1));
- RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
- RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
- RR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
- RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
- RR(OVL_FIR(OMAP_DSS_VIDEO1));
- RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
- RR(OVL_ACCU0(OMAP_DSS_VIDEO1));
- RR(OVL_ACCU1(OMAP_DSS_VIDEO1));
-
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
-
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
-
- for (i = 0; i < 5; i++)
- RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
-
- if (dss_has_feature(FEAT_FIR_COEF_V)) {
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
- }
- if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
- RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
- RR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
- RR(OVL_FIR2(OMAP_DSS_VIDEO1));
- RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
- RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+ /* VID1-3 */
+ for (o = OMAP_DSS_VIDEO1; o <= OMAP_DSS_VIDEO3; o++) {
+ if (o == OMAP_DSS_VIDEO3 && !dss_has_feature(FEAT_OVL_VID3))
+ continue;
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
+ RR(OVL_BA0(o));
+ RR(OVL_BA1(o));
+ RR(OVL_POSITION(o));
+ RR(OVL_SIZE(o));
+ RR(OVL_ATTRIBUTES(o));
+ RR(OVL_FIFO_THRESHOLD(o));
+ RR(OVL_ROW_INC(o));
+ RR(OVL_PIXEL_INC(o));
+ RR(OVL_FIR(o));
+ RR(OVL_PICTURE_SIZE(o));
+ RR(OVL_ACCU0(o));
+ RR(OVL_ACCU1(o));
for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
+ RR(OVL_FIR_COEF_H(o, i));
for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
- }
- if (dss_has_feature(FEAT_ATTR2))
- RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+ RR(OVL_FIR_COEF_HV(o, i));
- if (dss_has_feature(FEAT_PRELOAD))
- RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
-
- /* VID2 */
- RR(OVL_BA0(OMAP_DSS_VIDEO2));
- RR(OVL_BA1(OMAP_DSS_VIDEO2));
- RR(OVL_POSITION(OMAP_DSS_VIDEO2));
- RR(OVL_SIZE(OMAP_DSS_VIDEO2));
- RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
- RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
- RR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
- RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
- RR(OVL_FIR(OMAP_DSS_VIDEO2));
- RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
- RR(OVL_ACCU0(OMAP_DSS_VIDEO2));
- RR(OVL_ACCU1(OMAP_DSS_VIDEO2));
-
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
-
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
-
- for (i = 0; i < 5; i++)
- RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
-
- if (dss_has_feature(FEAT_FIR_COEF_V)) {
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
- }
+ for (i = 0; i < 5; i++)
+ RR(OVL_CONV_COEF(o, i));
- if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
- RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
- RR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
- RR(OVL_FIR2(OMAP_DSS_VIDEO2));
- RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
- RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+ if (dss_has_feature(FEAT_FIR_COEF_V)) {
+ for (i = 0; i < 8; i++)
+ RR(OVL_FIR_COEF_V(o, i));
+ }
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ RR(OVL_BA0_UV(o));
+ RR(OVL_BA1_UV(o));
+ RR(OVL_FIR2(o));
+ RR(OVL_ACCU2_0(o));
+ RR(OVL_ACCU2_1(o));
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+ for (i = 0; i < 8; i++)
+ RR(OVL_FIR_COEF_H2(o, i));
- for (i = 0; i < 8; i++)
- RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
- }
- if (dss_has_feature(FEAT_ATTR2))
- RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+ for (i = 0; i < 8; i++)
+ RR(OVL_FIR_COEF_HV2(o, i));
- if (dss_has_feature(FEAT_PRELOAD))
- RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
+ for (i = 0; i < 8; i++)
+ RR(OVL_FIR_COEF_V2(o, i));
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ RR(OVL_ATTRIBUTES2(o));
+
+ if (dss_has_feature(FEAT_PRELOAD))
+ RR(OVL_PRELOAD(o));
+ }
if (dss_has_feature(FEAT_CORE_CLK_DIV))
RR(DIVISOR);
@@ -864,12 +776,25 @@ static void _dispc_setup_color_conv_coef(void)
dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4),
CVAL(0, ct->bcb));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO3, 0),
+ CVAL(ct->rcr, ct->ry));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO3, 1),
+ CVAL(ct->gy, ct->rcb));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO3, 2),
+ CVAL(ct->gcb, ct->gcr));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO3, 3),
+ CVAL(ct->bcr, ct->by));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO3, 4),
+ CVAL(0, ct->bcb));
+
#undef CVAL
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1),
ct->full_range, 11, 11);
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2),
ct->full_range, 11, 11);
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO3),
+ ct->full_range, 11, 11);
}
@@ -944,8 +869,12 @@ static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
if (plane == OMAP_DSS_GFX)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
+ else if (plane == OMAP_DSS_VIDEO1)
+ REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 15, 8);
else if (plane == OMAP_DSS_VIDEO2)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
+ else if (plane == OMAP_DSS_VIDEO3)
+ REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 31, 24);
}
static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
@@ -966,11 +895,11 @@ static void _dispc_set_color_mode(enum omap_plane plane,
switch (color_mode) {
case OMAP_DSS_COLOR_NV12:
m = 0x0; break;
- case OMAP_DSS_COLOR_RGB12U:
+ case OMAP_DSS_COLOR_RGBX16:
m = 0x1; break;
case OMAP_DSS_COLOR_RGBA16:
m = 0x2; break;
- case OMAP_DSS_COLOR_RGBX16:
+ case OMAP_DSS_COLOR_RGB12U:
m = 0x4; break;
case OMAP_DSS_COLOR_ARGB16:
m = 0x5; break;
@@ -1020,8 +949,10 @@ static void _dispc_set_color_mode(enum omap_plane plane,
case OMAP_DSS_COLOR_RGB24P:
m = 0x9; break;
case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_RGBX16:
m = 0xa; break;
case OMAP_DSS_COLOR_UYVY:
+ case OMAP_DSS_COLOR_RGBA16:
m = 0xb; break;
case OMAP_DSS_COLOR_ARGB32:
m = 0xc; break;
@@ -1052,6 +983,7 @@ void dispc_set_channel_out(enum omap_plane plane,
break;
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
shift = 16;
break;
default:
@@ -1098,6 +1030,7 @@ void dispc_set_burst_size(enum omap_plane plane,
break;
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
shift = 14;
break;
default:
@@ -1124,6 +1057,29 @@ void dispc_enable_gamma_table(bool enable)
REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
}
+void dispc_set_zorder(enum omap_plane plane,
+ enum omap_overlay_zorder zorder)
+{
+ u32 val;
+
+ if (!dss_has_feature(FEAT_OVL_ZORDER))
+ return;
+ val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ val = FLD_MOD(val, zorder, 27, 26);
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
+}
+
+void dispc_enable_zorder(enum omap_plane plane, bool enable)
+{
+ u32 val;
+
+ if (!dss_has_feature(FEAT_OVL_ZORDER))
+ return;
+ val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ val = FLD_MOD(val, enable, 25, 25);
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
+}
+
static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
{
u32 val;
@@ -1438,7 +1394,8 @@ static void _dispc_set_scaling(enum omap_plane plane,
}
static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
- bool mirroring, enum omap_color_mode color_mode)
+ bool mirroring, enum omap_color_mode color_mode,
+ enum omap_dss_rotation_type type)
{
bool row_repeat = false;
int vidrot = 0;
@@ -1488,6 +1445,16 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
if (dss_has_feature(FEAT_ROWREPEATENABLE))
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
row_repeat ? 1 : 0, 18, 18);
+
+ if (color_mode == OMAP_DSS_COLOR_NV12) {
+ /* this will never happen for GFX */
+ /* 1D NV12 buffer is always non-rotated or vert. mirrored */
+ bool doublestride = (rotation == OMAP_DSS_ROT_0 ||
+ rotation == OMAP_DSS_ROT_180) &&
+ type == OMAP_DSS_ROT_TILER;
+ /* DOUBLESTRIDE */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
+ }
}
static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -1536,6 +1503,28 @@ static s32 pixinc(int pixels, u8 ps)
BUG();
}
+static void calc_tiler_row_rotation(struct tiler_view_t *view,
+ u16 width, int bpp, int y_decim,
+ s32 *row_inc, unsigned *offset1, bool ilace)
+{
+ /* assume TB. We worry about swapping top/bottom outside of this call */
+
+ if (ilace) {
+ /* even and odd frames are interleaved */
+
+ /* offset1 is always at an odd line */
+ *offset1 = view->v_inc * (y_decim | 1);
+ y_decim *= 2;
+ }
+ *row_inc = view->v_inc * y_decim + 1 - width * bpp;
+
+ DSSDBG(" ps: %d/%d, width: %d/%d, offset1: %d,"
+ " height: %d, row_inc:%d\n", view->bpp, bpp,
+ view->width, width, *offset1, view->height, *row_inc);
+
+ return;
+}
+
static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
u16 screen_width,
u16 width, u16 height,
@@ -1626,7 +1615,7 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
enum omap_color_mode color_mode, bool fieldmode,
unsigned int field_offset,
unsigned *offset0, unsigned *offset1,
- s32 *row_inc, s32 *pix_inc)
+ s32 *row_inc, s32 *pix_inc, int x_decim, int y_decim)
{
u8 ps;
u16 fbw, fbh;
@@ -1639,6 +1628,15 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
case OMAP_DSS_COLOR_CLUT8:
BUG();
return;
+ case OMAP_DSS_COLOR_YUV2:
+ case OMAP_DSS_COLOR_UYVY:
+ if (cpu_is_omap44xx()) {
+ /* on OMAP4 YUYV is handled as 32-bit data */
+ ps = 4;
+ screen_width /= 2;
+ break;
+ }
+ /* fall through */
default:
ps = color_mode_to_bpp(color_mode) / 8;
break;
@@ -1668,10 +1666,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 + field_offset * screen_width * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(1 + (screen_width - fbw) +
+ *row_inc = pixinc(1 + (y_decim * screen_width - fbw * x_decim) +
(fieldmode ? screen_width : 0),
ps);
- *pix_inc = pixinc(1, ps);
+ *pix_inc = pixinc(x_decim, ps);
break;
case OMAP_DSS_ROT_90:
*offset1 = screen_width * (fbh - 1) * ps;
@@ -1768,6 +1766,11 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
/* FIXME venc pclk? */
u64 tmp, pclk = dispc_pclk_rate(channel);
+ /* do conservative guess on OMAP4 until better formula is available */
+ if (cpu_is_omap44xx())
+ return pclk * DIV_ROUND_UP(width, out_width) *
+ DIV_ROUND_UP(height, out_height);
+
if (height > out_height) {
/* FIXME get real display PPL */
unsigned int ppl = 800;
@@ -1826,6 +1829,174 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
return dispc_pclk_rate(channel) * vf * hf;
}
+int dispc_scaling_decision(u16 width, u16 height,
+ u16 out_width, u16 out_height,
+ enum omap_plane plane,
+ enum omap_color_mode color_mode,
+ enum omap_channel channel, u8 rotation,
+ u16 min_x_decim, u16 max_x_decim,
+ u16 min_y_decim, u16 max_y_decim,
+ u16 *x_decim, u16 *y_decim, bool *five_taps)
+{
+ int maxdownscale = cpu_is_omap24xx() ? 2 : 4;
+ int bpp = color_mode_to_bpp(color_mode);
+
+ /*
+ * For now only whole byte formats on OMAP4 can be predecimated.
+ * Later SDMA decimation support may be added
+ */
+ bool can_decimate_x = cpu_is_omap44xx() && !(bpp & 7);
+ bool can_decimate_y = can_decimate_x;
+
+ bool can_scale = plane != OMAP_DSS_GFX;
+
+ u16 in_width, in_height;
+ unsigned long fclk = 0, fclk5 = 0;
+ int min_factor, max_factor; /* decimation search limits */
+ int x, y; /* decimation search variables */
+ unsigned long fclk_max = dispc_fclk_rate();
+
+ /* No decimation for bitmap formats */
+ if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
+ color_mode == OMAP_DSS_COLOR_CLUT2 ||
+ color_mode == OMAP_DSS_COLOR_CLUT4 ||
+ color_mode == OMAP_DSS_COLOR_CLUT8) {
+ *x_decim = 1;
+ *y_decim = 1;
+ *five_taps = false;
+ return 0;
+ }
+
+ /* restrict search region based on whether we can decimate */
+ if (!can_decimate_x) {
+ if (min_x_decim > 1)
+ return -EINVAL;
+ min_x_decim = max_x_decim = 1;
+ } else {
+ if (max_x_decim > 16)
+ max_x_decim = 16;
+ }
+
+ if (!can_decimate_y) {
+ if (min_y_decim > 1)
+ return -EINVAL;
+ min_y_decim = max_y_decim = 1;
+ }
+
+ /*
+ * Find best supported quality. In the search algorithm, we make use
+ * of the fact, that increased decimation in either direction will have
+ * lower quality. However, we do not differentiate horizontal and
+ * vertical decimation even though they may affect quality differently
+ * given the exact geometry involved.
+ *
+ * Also, since the clock calculations are abstracted, we cannot make
+ * assumptions on how decimation affects the clock rates in our search.
+ *
+ * We search the whole search region in increasing layers from
+ * min_factor to max_factor. In each layer we search in increasing
+ * factors alternating between x and y axis:
+ *
+ * x: 1 2 3
+ * y:
+ * 1 1st | 3rd | 6th |
+ * ----+ | |
+ * 2 2nd 4th | 8th |
+ * ------------+ |
+ * 3 5th 7th 9th |
+ * --------------------+
+ */
+ min_factor = min(min_x_decim, min_y_decim);
+ max_factor = max(max_x_decim, max_y_decim);
+ x = min_x_decim;
+ y = min_y_decim;
+ while (1) {
+ if (x < min_x_decim || x > max_x_decim ||
+ y < min_y_decim || y > max_y_decim)
+ goto loop;
+
+ in_width = DIV_ROUND_UP(width, x);
+ in_height = DIV_ROUND_UP(height, y);
+
+ if (in_width == out_width && in_height == out_height)
+ break;
+
+ if (!can_scale)
+ goto loop;
+
+ if (out_width < in_width / maxdownscale ||
+ out_height < in_height / maxdownscale)
+ goto loop;
+
+ /* Use 5-tap filter unless must use 3-tap */
+ if (!cpu_is_omap44xx())
+ *five_taps = in_width <= 1024;
+ else if (omap_rev() == OMAP4430_REV_ES1_0)
+ *five_taps = in_width <= 1280;
+ else
+ *five_taps = true;
+
+ /* Also use 3-tap if downscaling by 2 or less */
+ *five_taps &= out_height * 2 < in_height;
+
+ /*
+ * Predecimation on OMAP4 still fetches the whole lines
+ * :TODO: How does it affect the required clock speed?
+ */
+ fclk = calc_fclk(channel, in_width, in_height,
+ out_width, out_height);
+ fclk5 = *five_taps ?
+ calc_fclk_five_taps(channel, in_width, in_height,
+ out_width, out_height, color_mode) : 0;
+
+ DSSDBG("%d*%d,%d*%d->%d,%d requires %lu(3T), %lu(5T) Hz\n",
+ in_width, x, in_height, y, out_width, out_height,
+ fclk, fclk5);
+
+ /* Use 3-tap if 5-tap clock requirement is too high */
+ *five_taps &= fclk5 <= fclk_max;
+
+ /* for now we always use 5-tap unless 3-tap is required */
+ if (*five_taps)
+ fclk = fclk5;
+
+ /* OMAP2/3 has a scaler size limitation */
+ if (!cpu_is_omap44xx() && in_width > (1024 << !*five_taps))
+ goto loop;
+
+ DSSDBG("required fclk rate = %lu Hz\n", fclk);
+ DSSDBG("current fclk rate = %lu Hz\n", fclk_max);
+
+ if (fclk > fclk_max)
+ goto loop;
+ break;
+
+loop:
+ /* err if exhausted search region */
+ if (x == max_x_decim && y == max_y_decim) {
+ DSSERR("failed to set up scaling, "
+ "required fclk rate = %lu Hz, "
+ "current fclk rate = %lu Hz\n",
+ fclk, fclk_max);
+ return -EINVAL;
+ }
+
+ /* get to next factor */
+ if (x == y) {
+ x = min_factor;
+ y++;
+ } else {
+ swap(x, y);
+ if (x < y)
+ x++;
+ }
+ }
+
+ *x_decim = x;
+ *y_decim = y;
+ return 0;
+}
+
int dispc_setup_plane(enum omap_plane plane,
u32 paddr, u16 screen_width,
u16 pos_x, u16 pos_y,
@@ -1833,13 +2004,13 @@ int dispc_setup_plane(enum omap_plane plane,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode,
bool ilace,
+ int x_decim, int y_decim, bool five_taps,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror,
u8 global_alpha, u8 pre_mult_alpha,
enum omap_channel channel, u32 puv_addr)
{
- const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
- bool five_taps = 0;
+ const int maxdownscale = cpu_is_omap24xx() ? 2 : 4;
bool fieldmode = 0;
int cconv = 0;
unsigned offset0, offset1;
@@ -1847,14 +2018,17 @@ int dispc_setup_plane(enum omap_plane plane,
s32 pix_inc;
u16 frame_height = height;
unsigned int field_offset = 0;
+ int pixpg = (color_mode &
+ (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) ? 2 : 1;
+ unsigned long tiler_width, tiler_height;
- DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
- "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
+ DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %d/%dx%d/%d -> "
+ "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d %dtap\n",
plane, paddr, screen_width, pos_x, pos_y,
- width, height,
+ width, x_decim, height, y_decim,
out_width, out_height,
ilace, color_mode,
- rotation, mirror, channel);
+ rotation, mirror, channel, five_taps ? 5 : 3);
if (paddr == 0)
return -EINVAL;
@@ -1876,59 +2050,41 @@ int dispc_setup_plane(enum omap_plane plane,
if (!dss_feat_color_mode_supported(plane, color_mode))
return -EINVAL;
+ /* predecimate */
+
+ /* adjust for group-of-pixels*/
+ if (rotation & 1)
+ height /= pixpg;
+ else
+ width /= pixpg;
+
+ /* remember tiler block's size as we are reconstructing it */
+ tiler_width = width;
+ tiler_height = height;
+
+ width = DIV_ROUND_UP(width, x_decim);
+ height = DIV_ROUND_UP(height, y_decim);
+
+ /* NV12 width has to be even (height apparently does not) */
+ if (color_mode == OMAP_DSS_COLOR_NV12)
+ width &= ~1;
+
if (plane == OMAP_DSS_GFX) {
if (width != out_width || height != out_height)
return -EINVAL;
} else {
/* video plane */
- unsigned long fclk = 0;
-
- if (out_width < width / maxdownscale ||
- out_width > width * 8)
+ if (out_width < width / maxdownscale)
return -EINVAL;
- if (out_height < height / maxdownscale ||
- out_height > height * 8)
+ if (out_height < height / maxdownscale)
return -EINVAL;
if (color_mode == OMAP_DSS_COLOR_YUV2 ||
color_mode == OMAP_DSS_COLOR_UYVY ||
color_mode == OMAP_DSS_COLOR_NV12)
cconv = 1;
-
- /* Must use 5-tap filter? */
- five_taps = height > out_height * 2;
-
- if (!five_taps) {
- fclk = calc_fclk(channel, width, height, out_width,
- out_height);
-
- /* Try 5-tap filter if 3-tap fclk is too high */
- if (cpu_is_omap34xx() && height > out_height &&
- fclk > dispc_fclk_rate())
- five_taps = true;
- }
-
- if (width > (2048 >> five_taps)) {
- DSSERR("failed to set up scaling, fclk too low\n");
- return -EINVAL;
- }
-
- if (five_taps)
- fclk = calc_fclk_five_taps(channel, width, height,
- out_width, out_height, color_mode);
-
- DSSDBG("required fclk rate = %lu Hz\n", fclk);
- DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
-
- if (!fclk || fclk > dispc_fclk_rate()) {
- DSSERR("failed to set up scaling, "
- "required fclk rate = %lu Hz, "
- "current fclk rate = %lu Hz\n",
- fclk, dispc_fclk_rate());
- return -EINVAL;
- }
}
if (ilace && !fieldmode) {
@@ -1949,17 +2105,69 @@ int dispc_setup_plane(enum omap_plane plane,
if (fieldmode)
field_offset = 1;
- if (rotation_type == OMAP_DSS_ROT_DMA)
+ /* default values */
+ row_inc = pix_inc = 0x1;
+ offset0 = offset1 = 0x0;
+
+ /*
+ * :HACK: we piggy back on UV separate feature for TILER to avoid
+ * having to keep rebase our FEAT_ enum until they add TILER.
+ */
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ /* set BURSTTYPE */
+ bool use_tiler = rotation_type == OMAP_DSS_ROT_TILER;
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), use_tiler, 29, 29);
+ }
+
+ if (rotation_type == OMAP_DSS_ROT_TILER) {
+ struct tiler_view_t view = {0};
+ int bpp = color_mode_to_bpp(color_mode) / 8;
+ /* tiler needs 0-degree width & height */
+ if (rotation & 1)
+ swap(tiler_width, tiler_height);
+
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY)
+ tiler_width /= 2;
+
+ tilview_create(&view, paddr, tiler_width, tiler_height);
+ tilview_rotate(&view, rotation * 90);
+ tilview_flip(&view, mirror, false);
+ paddr = view.tsptr;
+
+ /* we cannot do TB field interlaced in rotated view */
+ pix_inc = 1 + (x_decim - 1) * bpp * pixpg;
+ calc_tiler_row_rotation(&view, width * x_decim, bpp * pixpg,
+ y_decim, &row_inc, &offset1, ilace);
+
+ DSSDBG("w, h = %ld %ld\n", tiler_width, tiler_height);
+
+ if (puv_addr) {
+ tilview_create(&view, puv_addr, tiler_width / 2,
+ tiler_height / 2);
+ tilview_rotate(&view, rotation * 90);
+ tilview_flip(&view, mirror, false);
+ puv_addr = view.tsptr;
+ }
+
+ } else if (rotation_type == OMAP_DSS_ROT_DMA) {
calc_dma_rotation_offset(rotation, mirror,
screen_width, width, frame_height, color_mode,
fieldmode, field_offset,
- &offset0, &offset1, &row_inc, &pix_inc);
- else
+ &offset0, &offset1, &row_inc, &pix_inc,
+ x_decim, y_decim);
+ } else {
calc_vrfb_rotation_offset(rotation, mirror,
screen_width, width, frame_height, color_mode,
fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc);
+ }
+ /* adjust back to pixels */
+ if (rotation & 1)
+ height *= pixpg;
+ else
+ width *= pixpg;
DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
offset0, offset1, row_inc, pix_inc);
@@ -1977,8 +2185,8 @@ int dispc_setup_plane(enum omap_plane plane,
_dispc_set_row_inc(plane, row_inc);
_dispc_set_pix_inc(plane, pix_inc);
- DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
- out_width, out_height);
+ DSSDBG("%d,%d %d*%dx%d*%d -> %dx%d\n", pos_x, pos_y, width, x_decim,
+ height, y_decim, out_width, out_height);
_dispc_set_plane_pos(plane, pos_x, pos_y);
@@ -1993,7 +2201,8 @@ int dispc_setup_plane(enum omap_plane plane,
_dispc_set_vid_color_conv(plane, cconv);
}
- _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
+ _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode,
+ rotation_type);
_dispc_set_pre_mult_alpha(plane, pre_mult_alpha);
_dispc_setup_global_alpha(plane, global_alpha);
@@ -2135,6 +2344,8 @@ static void dispc_enable_digit_out(bool enable)
dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
if (dss_has_feature(FEAT_MGR_LCD2))
dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
+ if (dss_has_feature(FEAT_OVL_VID3))
+ dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc.irq_lock, flags);
@@ -2293,12 +2504,11 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return;
+ /* :NOTE: compatibility mode is not supported on LCD2 */
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
- else /* OMAP_DSS_CHANNEL_LCD2 */
- REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
}
bool dispc_alpha_blending_enabled(enum omap_channel ch)
{
@@ -2312,7 +2522,7 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
enabled = REG_GET(DISPC_CONFIG, 19, 19);
else if (ch == OMAP_DSS_CHANNEL_LCD2)
- enabled = REG_GET(DISPC_CONFIG2, 18, 18);
+ enabled = false;
else
BUG();
@@ -2678,6 +2888,10 @@ void dispc_dump_irqs(struct seq_file *s)
PIS(VID1_END_WIN);
PIS(VID2_FIFO_UNDERFLOW);
PIS(VID2_END_WIN);
+ if (dss_has_feature(FEAT_OVL_VID3)) {
+ PIS(VID3_FIFO_UNDERFLOW);
+ PIS(VID3_END_WIN);
+ }
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
PIS(WAKEUP);
@@ -2693,6 +2907,7 @@ void dispc_dump_irqs(struct seq_file *s)
void dispc_dump_regs(struct seq_file *s)
{
+ int i, o;
#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
if (dispc_runtime_get())
@@ -2768,177 +2983,59 @@ void dispc_dump_regs(struct seq_file *s)
if (dss_has_feature(FEAT_PRELOAD))
DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
- DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1));
-
- DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2));
-
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
- if (dss_has_feature(FEAT_FIR_COEF_V)) {
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
- }
+ for (o = OMAP_DSS_VIDEO1; o <= OMAP_DSS_VIDEO3; o++) {
+ if (o == OMAP_DSS_VIDEO3 && !dss_has_feature(FEAT_OVL_VID3))
+ continue;
- if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
- DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1));
-
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7));
-
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7));
-
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7));
- }
- if (dss_has_feature(FEAT_ATTR2))
- DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
-
-
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
-
- if (dss_has_feature(FEAT_FIR_COEF_V)) {
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
- }
+ DUMPREG(DISPC_OVL_BA0(o));
+ DUMPREG(DISPC_OVL_BA1(o));
+ DUMPREG(DISPC_OVL_POSITION(o));
+ DUMPREG(DISPC_OVL_SIZE(o));
+ DUMPREG(DISPC_OVL_ATTRIBUTES(o));
+ DUMPREG(DISPC_OVL_FIFO_THRESHOLD(o));
+ DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(o));
+ DUMPREG(DISPC_OVL_ROW_INC(o));
+ DUMPREG(DISPC_OVL_PIXEL_INC(o));
+ DUMPREG(DISPC_OVL_FIR(o));
+ DUMPREG(DISPC_OVL_PICTURE_SIZE(o));
+ DUMPREG(DISPC_OVL_ACCU0(o));
+ DUMPREG(DISPC_OVL_ACCU1(o));
- if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
- DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2));
- DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2));
-
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7));
-
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7));
-
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6));
- DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7));
- }
- if (dss_has_feature(FEAT_ATTR2))
- DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
-
- if (dss_has_feature(FEAT_PRELOAD)) {
- DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
- DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
+ for (i = 0; i < 8; i++)
+ DUMPREG(DISPC_OVL_FIR_COEF_H(o, i));
+
+ for (i = 0; i < 8; i++)
+ DUMPREG(DISPC_OVL_FIR_COEF_HV(o, i));
+
+ for (i = 0; i < 5; i++)
+ DUMPREG(DISPC_OVL_CONV_COEF(o, i));
+
+ if (dss_has_feature(FEAT_FIR_COEF_V)) {
+ for (i = 0; i < 8; i++)
+ DUMPREG(DISPC_OVL_FIR_COEF_V(o, i));
+ }
+
+ if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+ DUMPREG(DISPC_OVL_BA0_UV(o));
+ DUMPREG(DISPC_OVL_BA1_UV(o));
+ DUMPREG(DISPC_OVL_FIR2(o));
+ DUMPREG(DISPC_OVL_ACCU2_0(o));
+ DUMPREG(DISPC_OVL_ACCU2_1(o));
+
+ for (i = 0; i < 8; i++)
+ DUMPREG(DISPC_OVL_FIR_COEF_H2(o, i));
+
+ for (i = 0; i < 8; i++)
+ DUMPREG(DISPC_OVL_FIR_COEF_HV2(o, i));
+
+ for (i = 0; i < 8; i++)
+ DUMPREG(DISPC_OVL_FIR_COEF_V2(o, i));
+ }
+ if (dss_has_feature(FEAT_ATTR2))
+ DUMPREG(DISPC_OVL_ATTRIBUTES2(o));
+
+ if (dss_has_feature(FEAT_PRELOAD))
+ DUMPREG(DISPC_OVL_PRELOAD(o));
}
dispc_runtime_put();
@@ -3193,6 +3290,8 @@ static void print_irq_status(u32 status)
PIS(OCP_ERR);
PIS(VID1_FIFO_UNDERFLOW);
PIS(VID2_FIFO_UNDERFLOW);
+ if (dss_has_feature(FEAT_OVL_VID3))
+ PIS(VID3_FIFO_UNDERFLOW);
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
if (dss_has_feature(FEAT_MGR_LCD2))
@@ -3346,6 +3445,24 @@ static void dispc_error_worker(struct work_struct *work)
}
}
+ if (errors & DISPC_IRQ_VID3_FIFO_UNDERFLOW) {
+ DSSERR("VID3_FIFO_UNDERFLOW, disabling VID3\n");
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl;
+ ovl = omap_dss_get_overlay(i);
+
+ if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
+ continue;
+
+ if (ovl->id == 3) {
+ dispc_enable_plane(ovl->id, 0);
+ dispc_go(ovl->manager->id);
+ mdelay(50);
+ break;
+ }
+ }
+ }
+
if (errors & DISPC_IRQ_SYNC_LOST) {
struct omap_overlay_manager *manager = NULL;
bool enable = false;
@@ -3572,7 +3689,8 @@ static void _omap_dispc_initialize_irq(void)
dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
if (dss_has_feature(FEAT_MGR_LCD2))
dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
-
+ if (dss_has_feature(FEAT_OVL_VID3))
+ dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
/* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
* so clear it */
dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
index 6c9ee0a..c06efc3 100644
--- a/drivers/video/omap2/dss/dispc.h
+++ b/drivers/video/omap2/dss/dispc.h
@@ -291,6 +291,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
return 0x00BC;
case OMAP_DSS_VIDEO2:
return 0x014C;
+ case OMAP_DSS_VIDEO3:
+ return 0x0300;
default:
BUG();
}
@@ -304,6 +306,8 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0000;
+ case OMAP_DSS_VIDEO3:
+ return 0x0008;
default:
BUG();
}
@@ -316,6 +320,8 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0004;
+ case OMAP_DSS_VIDEO3:
+ return 0x000C;
default:
BUG();
}
@@ -330,6 +336,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
return 0x0544;
case OMAP_DSS_VIDEO2:
return 0x04BC;
+ case OMAP_DSS_VIDEO3:
+ return 0x0310;
default:
BUG();
}
@@ -344,6 +352,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
return 0x0548;
case OMAP_DSS_VIDEO2:
return 0x04C0;
+ case OMAP_DSS_VIDEO3:
+ return 0x0314;
default:
BUG();
}
@@ -356,6 +366,8 @@ static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0008;
+ case OMAP_DSS_VIDEO3:
+ return 0x009C;
default:
BUG();
}
@@ -368,6 +380,8 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x000C;
+ case OMAP_DSS_VIDEO3:
+ return 0x00A8;
default:
BUG();
}
@@ -381,6 +395,8 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0010;
+ case OMAP_DSS_VIDEO3:
+ return 0x0070;
default:
BUG();
}
@@ -395,6 +411,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
return 0x0568;
case OMAP_DSS_VIDEO2:
return 0x04DC;
+ case OMAP_DSS_VIDEO3:
+ return 0x032C;
default:
BUG();
}
@@ -408,6 +426,8 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0014;
+ case OMAP_DSS_VIDEO3:
+ return 0x008C;
default:
BUG();
}
@@ -421,6 +441,8 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0018;
+ case OMAP_DSS_VIDEO3:
+ return 0x0088;
default:
BUG();
}
@@ -434,6 +456,8 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x001C;
+ case OMAP_DSS_VIDEO3:
+ return 0x00A4;
default:
BUG();
}
@@ -447,6 +471,8 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0020;
+ case OMAP_DSS_VIDEO3:
+ return 0x0098;
default:
BUG();
}
@@ -459,6 +485,7 @@ static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
return 0x0034;
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
BUG();
default:
BUG();
@@ -472,6 +499,7 @@ static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
return 0x0038;
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
BUG();
default:
BUG();
@@ -486,6 +514,8 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0024;
+ case OMAP_DSS_VIDEO3:
+ return 0x0090;
default:
BUG();
}
@@ -500,6 +530,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
return 0x0580;
case OMAP_DSS_VIDEO2:
return 0x055C;
+ case OMAP_DSS_VIDEO3:
+ return 0x0424;
default:
BUG();
}
@@ -513,6 +545,8 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0028;
+ case OMAP_DSS_VIDEO3:
+ return 0x0094;
default:
BUG();
}
@@ -527,6 +561,8 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x002C;
+ case OMAP_DSS_VIDEO3:
+ return 0x0000;
default:
BUG();
}
@@ -541,6 +577,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
return 0x0584;
case OMAP_DSS_VIDEO2:
return 0x0560;
+ case OMAP_DSS_VIDEO3:
+ return 0x0428;
default:
BUG();
}
@@ -554,6 +592,8 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0030;
+ case OMAP_DSS_VIDEO3:
+ return 0x0004;
default:
BUG();
}
@@ -568,6 +608,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
return 0x0588;
case OMAP_DSS_VIDEO2:
return 0x0564;
+ case OMAP_DSS_VIDEO3:
+ return 0x042C;
default:
BUG();
}
@@ -582,6 +624,8 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0034 + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ return 0x0010 + i * 0x8;
default:
BUG();
}
@@ -597,6 +641,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
return 0x058C + i * 0x8;
case OMAP_DSS_VIDEO2:
return 0x0568 + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ return 0x0430 + i * 0x8;
default:
BUG();
}
@@ -611,6 +657,8 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
return 0x0038 + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ return 0x0014 + i * 0x8;
default:
BUG();
}
@@ -626,6 +674,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
return 0x0590 + i * 8;
case OMAP_DSS_VIDEO2:
return 0x056C + i * 0x8;
+ case OMAP_DSS_VIDEO3:
+ return 0x0434 + i * 0x8;
default:
BUG();
}
@@ -639,6 +689,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
BUG();
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
+ case OMAP_DSS_VIDEO3:
return 0x0074 + i * 0x4;
default:
BUG();
@@ -655,6 +706,8 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
return 0x0124 + i * 0x4;
case OMAP_DSS_VIDEO2:
return 0x00B4 + i * 0x4;
+ case OMAP_DSS_VIDEO3:
+ return 0x0050 + i * 0x4;
default:
BUG();
}
@@ -670,6 +723,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
return 0x05CC + i * 0x4;
case OMAP_DSS_VIDEO2:
return 0x05A8 + i * 0x4;
+ case OMAP_DSS_VIDEO3:
+ return 0x0470 + i * 0x4;
default:
BUG();
}
@@ -684,6 +739,8 @@ static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
return 0x0174;
case OMAP_DSS_VIDEO2:
return 0x00E8;
+ case OMAP_DSS_VIDEO3:
+ return 0x00A0;
default:
BUG();
}
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index ce17a61..6d59b26 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -398,6 +398,9 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
void dispc_enable_fifomerge(bool enable);
void dispc_set_burst_size(enum omap_plane plane,
enum omap_burst_size burst_size);
+void dispc_set_zorder(enum omap_plane plane,
+ enum omap_overlay_zorder zorder);
+void dispc_enable_zorder(enum omap_plane plane, bool enable);
void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
@@ -414,11 +417,20 @@ int dispc_setup_plane(enum omap_plane plane,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode,
bool ilace,
+ int x_decim, int y_decim, bool five_taps,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror,
u8 global_alpha, u8 pre_mult_alpha,
enum omap_channel channel,
u32 puv_addr);
+int dispc_scaling_decision(u16 width, u16 height,
+ u16 out_width, u16 out_height,
+ enum omap_plane plane,
+ enum omap_color_mode color_mode,
+ enum omap_channel channel, u8 rotation,
+ u16 min_x_decim, u16 max_x_decim,
+ u16 min_y_decim, u16 max_y_decim,
+ u16 *x_decim, u16 *y_decim, bool *three_tap);
bool dispc_go_busy(enum omap_channel channel);
void dispc_go(enum omap_channel channel);
@@ -535,4 +547,11 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
}
#endif
+/* callback is optional */
+static inline void dss_ovl_cb(struct omapdss_ovl_cb *cb, int id, int status)
+{
+ if (cb->fn)
+ cb->fn(cb->data, id, status);
+}
+
#endif
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index bd420f9..aba2250 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -197,7 +197,17 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
OMAP_DSS_COLOR_RGBX32,
- /* OMAP_DSS_VIDEO2 */
+ /* OMAP_DSS_VIDEO2 */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_VIDEO3 */
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
@@ -331,10 +341,12 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
- FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V,
+ FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V |
+ FEAT_ALPHA_OMAP3_COMPAT | FEAT_OVL_VID3 |
+ FEAT_OVL_ZORDER,
.num_mgrs = 3,
- .num_ovls = 3,
+ .num_ovls = 4,
.supported_displays = omap4_dss_supported_displays,
.supported_color_modes = omap4_dss_supported_color_modes,
.clksrc_names = omap4_dss_clk_source_names,
@@ -353,10 +365,12 @@ static const struct omap_dss_features omap4_dss_features = {
FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
- FEAT_PRELOAD | FEAT_FIR_COEF_V,
+ FEAT_PRELOAD | FEAT_FIR_COEF_V |
+ FEAT_ALPHA_OMAP3_COMPAT | FEAT_OVL_VID3 |
+ FEAT_OVL_ZORDER,
.num_mgrs = 3,
- .num_ovls = 3,
+ .num_ovls = 4,
.supported_displays = omap4_dss_supported_displays,
.supported_color_modes = omap4_dss_supported_color_modes,
.clksrc_names = omap4_dss_clk_source_names,
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 5be8103..28f44ed 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -21,7 +21,7 @@
#define __OMAP2_DSS_FEATURES_H
#define MAX_DSS_MANAGERS 3
-#define MAX_DSS_OVERLAYS 3
+#define MAX_DSS_OVERLAYS 4
#define MAX_DSS_LCD_MANAGERS 2
#define MAX_NUM_DSI 2
@@ -55,6 +55,9 @@ enum dss_feat_id {
FEAT_CPR = 1 << 23,
FEAT_PRELOAD = 1 << 24,
FEAT_FIR_COEF_V = 1 << 25,
+ FEAT_ALPHA_OMAP3_COMPAT = 1 << 26,
+ FEAT_OVL_VID3 = 1 << 27,
+ FEAT_OVL_ZORDER = 1 << 28,
};
/* DSS register field id */
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index b1126b6..106767d 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -260,6 +260,10 @@ static ssize_t manager_alpha_blending_enabled_store(
if (sscanf(buf, "%d", &enable) != 1)
return -EINVAL;
+ /* if we have OMAP3 alpha compatibility, alpha blending is always on */
+ if (dss_has_feature(FEAT_ALPHA_OMAP3_COMPAT) && !enable)
+ return -EINVAL;
+
mgr->get_manager_info(mgr, &info);
info.alpha_enabled = enable ? true : false;
@@ -353,6 +357,20 @@ static struct kobj_type manager_ktype = {
.default_attrs = manager_sysfs_attrs,
};
+struct callback_states {
+ /*
+ * Keep track of callbacks at the last 3 levels of pipeline:
+ * cache, shadow registers and in DISPC registers.
+ *
+ * Note: We zero the function pointer when moving from one level to
+ * another to avoid checking for dirty and shadow_dirty fields that
+ * are not common between overlay and manager cache structures.
+ */
+ struct omapdss_ovl_cb cache, shadow, dispc;
+ bool dispc_displayed;
+ bool shadow_enabled;
+};
+
/*
* We have 4 levels of cache for the dispc settings. First two are in SW and
* the latter two in HW.
@@ -409,15 +427,20 @@ struct overlay_cache_data {
u8 global_alpha;
u8 pre_mult_alpha;
+ struct callback_states cb; /* callback data for the last 3 states */
+ int dispc_channel; /* overlay's channel in DISPC */
+
enum omap_channel channel;
bool replication;
bool ilace;
+ u16 min_x_decim, max_x_decim, min_y_decim, max_y_decim;
enum omap_burst_size burst_size;
u32 fifo_low;
u32 fifo_high;
bool manual_update;
+ enum omap_overlay_zorder zorder;
};
struct manager_cache_data {
@@ -447,6 +470,8 @@ struct manager_cache_data {
/* enlarge the update area if the update area contains scaled
* overlays */
bool enlarge_update_area;
+
+ struct callback_states cb; /* callback data for the last 3 states */
};
static struct {
@@ -455,9 +480,43 @@ static struct {
struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
bool irq_enabled;
+ bool comp_irq_enabled;
} dss_cache;
+/* propagating callback info between states */
+static inline void
+dss_ovl_configure_cb(struct callback_states *st, int i, bool enabled)
+{
+ /* complete info in shadow */
+ dss_ovl_cb(&st->shadow, i, DSS_COMPLETION_ECLIPSED_SHADOW);
+ /* propagate cache to shadow */
+ st->shadow = st->cache;
+ st->shadow_enabled = enabled;
+ st->cache.fn = NULL; /* info traveled to shadow */
+}
+
+static inline void
+dss_ovl_program_cb(struct callback_states *st, int i)
+{
+ /* mark previous programming as completed */
+ dss_ovl_cb(&st->dispc, i, st->dispc_displayed ?
+ DSS_COMPLETION_RELEASED : DSS_COMPLETION_TORN);
+
+ /* mark shadow info as programmed, not yet displayed */
+ dss_ovl_cb(&st->shadow, i, DSS_COMPLETION_PROGRAMMED);
+
+ /* if overlay/manager is not enabled, we are done now */
+ if (!st->shadow_enabled) {
+ dss_ovl_cb(&st->shadow, i, DSS_COMPLETION_RELEASED);
+ st->shadow.fn = NULL;
+ }
+
+ /* propagate shadow to dispc */
+ st->dispc = st->shadow;
+ st->shadow.fn = NULL;
+ st->dispc_displayed = false;
+}
static int omap_dss_set_device(struct omap_overlay_manager *mgr,
struct omap_dss_device *dssdev)
@@ -743,6 +802,8 @@ static int configure_overlay(enum omap_plane plane)
u16 x, y, w, h;
u32 paddr;
int r;
+ u16 x_decim, y_decim;
+ bool five_taps;
u16 orig_w, orig_h, orig_outw, orig_outh;
DSSDBGF("%d", plane);
@@ -785,11 +846,17 @@ static int configure_overlay(enum omap_plane plane)
case OMAP_DSS_COLOR_NV12:
bpp = 8;
break;
+
+ case OMAP_DSS_COLOR_CLUT1:
+ case OMAP_DSS_COLOR_CLUT2:
+ case OMAP_DSS_COLOR_CLUT4:
+ case OMAP_DSS_COLOR_CLUT8:
case OMAP_DSS_COLOR_RGB16:
case OMAP_DSS_COLOR_ARGB16:
case OMAP_DSS_COLOR_YUV2:
case OMAP_DSS_COLOR_UYVY:
case OMAP_DSS_COLOR_RGBA16:
+ case OMAP_DSS_COLOR_RGB12U:
case OMAP_DSS_COLOR_RGBX16:
case OMAP_DSS_COLOR_ARGB16_1555:
case OMAP_DSS_COLOR_XRGB16_1555:
@@ -855,14 +922,19 @@ static int configure_overlay(enum omap_plane plane)
}
}
- r = dispc_setup_plane(plane,
+ r = dispc_scaling_decision(w, h, outw, outh,
+ plane, c->color_mode, c->channel,
+ c->rotation, c->min_x_decim, c->max_x_decim,
+ c->min_y_decim, c->max_y_decim,
+ &x_decim, &y_decim, &five_taps);
+ r = r ? : dispc_setup_plane(plane,
paddr,
c->screen_width,
x, y,
w, h,
outw, outh,
c->color_mode,
- c->ilace,
+ c->ilace, x_decim, y_decim, five_taps,
c->rotation_type,
c->rotation,
c->mirror,
@@ -881,6 +953,8 @@ static int configure_overlay(enum omap_plane plane)
dispc_enable_replication(plane, c->replication);
dispc_set_burst_size(plane, c->burst_size);
+ dispc_set_zorder(plane, c->zorder);
+ dispc_enable_zorder(plane, 1);
dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
dispc_enable_plane(plane, 1);
@@ -899,7 +973,15 @@ static void configure_manager(enum omap_channel channel)
dispc_set_default_color(channel, c->default_color);
dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
dispc_enable_trans_key(channel, c->trans_enabled);
- dispc_enable_alpha_blending(channel, c->alpha_enabled);
+
+ /* if we have OMAP3 alpha compatibility, alpha blending is always on */
+ if (dss_has_feature(FEAT_ALPHA_OMAP3_COMPAT)) {
+ /* and alpha_blending bit enables OMAP3 compatibility mode */
+ dispc_enable_alpha_blending(channel, false);
+ c->alpha_enabled = true;
+ } else {
+ dispc_enable_alpha_blending(channel, c->alpha_enabled);
+ }
}
/* configure_dispc() tries to write values from cache to shadow registers.
@@ -914,6 +996,7 @@ static int configure_dispc(void)
const int num_mgrs = dss_feat_get_num_mgrs();
int i;
int r;
+ int used_ovls, j;
bool mgr_busy[MAX_DSS_MANAGERS];
bool mgr_go[MAX_DSS_MANAGERS];
bool busy;
@@ -946,6 +1029,8 @@ static int configure_dispc(void)
if (r)
DSSERR("configure_overlay %d failed\n", i);
+ dss_ovl_configure_cb(&oc->cb, i, oc->enabled);
+
oc->dirty = false;
oc->shadow_dirty = true;
mgr_go[oc->channel] = true;
@@ -966,7 +1051,16 @@ static int configure_dispc(void)
continue;
}
+ for (j = used_ovls = 0; j < num_ovls; j++) {
+ oc = &dss_cache.overlay_cache[j];
+ if (oc->channel == i && oc->enabled)
+ used_ovls++;
+ }
+
configure_manager(i);
+
+ dss_ovl_configure_cb(&mc->cb, i, used_ovls);
+
mc->dirty = false;
mc->shadow_dirty = true;
mgr_go[i] = true;
@@ -1145,6 +1239,57 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
*hi = h;
}
+static void dss_completion_irq_handler(void *data, u32 mask)
+{
+ struct manager_cache_data *mc;
+ struct overlay_cache_data *oc;
+ const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
+ const int num_mgrs = MAX_DSS_MANAGERS;
+ const u32 masks[] = {
+ DISPC_IRQ_FRAMEDONE | DISPC_IRQ_VSYNC,
+ DISPC_IRQ_FRAMEDONE2 | DISPC_IRQ_VSYNC2,
+ /*DISPC_IRQ_FRAMEDONE_DIG |*/ DISPC_IRQ_EVSYNC_EVEN |
+ DISPC_IRQ_EVSYNC_ODD
+ };
+ int i;
+ bool notify = false;
+
+ spin_lock(&dss_cache.lock);
+
+ for (i = 0; i < num_mgrs; i++) {
+ mc = &dss_cache.manager_cache[i];
+ if (!(mask & masks[i]))
+ continue;
+
+ dss_ovl_cb(&mc->cb.dispc, i, DSS_COMPLETION_DISPLAYED);
+ mc->cb.dispc_displayed = true;
+ }
+
+ /* notify all overlays on that manager */
+ for (i = 0; i < num_ovls; i++) {
+ oc = &dss_cache.overlay_cache[i];
+ if (oc->enabled)
+ notify = true;
+
+ if (!(mask & masks[oc->channel]))
+ continue;
+
+ dss_ovl_cb(&oc->cb.dispc, i, DSS_COMPLETION_DISPLAYED);
+ oc->cb.dispc_displayed = true;
+ }
+
+ if (!notify) {
+ omap_dispc_unregister_isr(dss_completion_irq_handler, NULL,
+ DISPC_IRQ_FRAMEDONE | DISPC_IRQ_VSYNC |
+ DISPC_IRQ_FRAMEDONE2 | DISPC_IRQ_VSYNC2 |
+ /*DISPC_IRQ_FRAMEDONE_DIG |*/ DISPC_IRQ_EVSYNC_EVEN |
+ DISPC_IRQ_EVSYNC_ODD);
+ dss_cache.comp_irq_enabled = false;
+ }
+
+ spin_unlock(&dss_cache.lock);
+}
+
void dss_start_update(struct omap_dss_device *dssdev)
{
struct manager_cache_data *mc;
@@ -1153,14 +1298,22 @@ void dss_start_update(struct omap_dss_device *dssdev)
const int num_mgrs = dss_feat_get_num_mgrs();
struct omap_overlay_manager *mgr;
int i;
+ bool notify = false;
+ unsigned long flags;
mgr = dssdev->manager;
for (i = 0; i < num_ovls; ++i) {
oc = &dss_cache.overlay_cache[i];
+ notify |= oc->enabled;
+
if (oc->channel != mgr->id)
continue;
+ if (oc->shadow_dirty) {
+ dss_ovl_program_cb(&oc->cb, i);
+ oc->dispc_channel = oc->channel;
+ }
oc->shadow_dirty = false;
}
@@ -1169,9 +1322,29 @@ void dss_start_update(struct omap_dss_device *dssdev)
if (mgr->id != i)
continue;
+ if (mc->shadow_dirty)
+ dss_ovl_program_cb(&mc->cb, i);
mc->shadow_dirty = false;
}
+ spin_lock_irqsave(&dss_cache.lock, flags);
+ if (!dss_cache.comp_irq_enabled && notify) {
+ omap_dispc_register_isr(dss_completion_irq_handler, NULL,
+ DISPC_IRQ_FRAMEDONE | DISPC_IRQ_VSYNC |
+ DISPC_IRQ_FRAMEDONE2 | DISPC_IRQ_VSYNC2 |
+ /*DISPC_IRQ_FRAMEDONE_DIG |*/ DISPC_IRQ_EVSYNC_EVEN |
+ DISPC_IRQ_EVSYNC_ODD);
+ dss_cache.comp_irq_enabled = true;
+ } else if (dss_cache.comp_irq_enabled && !notify) {
+ omap_dispc_unregister_isr(dss_completion_irq_handler, NULL,
+ DISPC_IRQ_FRAMEDONE | DISPC_IRQ_VSYNC |
+ DISPC_IRQ_FRAMEDONE2 | DISPC_IRQ_VSYNC2 |
+ /*DISPC_IRQ_FRAMEDONE_DIG |*/ DISPC_IRQ_EVSYNC_EVEN |
+ DISPC_IRQ_EVSYNC_ODD);
+ dss_cache.comp_irq_enabled = false;
+ }
+ spin_unlock_irqrestore(&dss_cache.lock, flags);
+
dssdev->manager->enable(dssdev->manager);
}
@@ -1183,6 +1356,7 @@ static void dss_apply_irq_handler(void *data, u32 mask)
const int num_mgrs = dss_feat_get_num_mgrs();
int i, r;
bool mgr_busy[MAX_DSS_MANAGERS];
+ bool notify = false;
u32 irq_mask;
for (i = 0; i < num_mgrs; i++)
@@ -1192,14 +1366,37 @@ static void dss_apply_irq_handler(void *data, u32 mask)
for (i = 0; i < num_ovls; ++i) {
oc = &dss_cache.overlay_cache[i];
- if (!mgr_busy[oc->channel])
+ notify |= oc->enabled;
+
+ if (!mgr_busy[oc->channel] && oc->shadow_dirty) {
+ dss_ovl_program_cb(&oc->cb, i);
+ oc->dispc_channel = oc->channel;
oc->shadow_dirty = false;
+ }
}
for (i = 0; i < num_mgrs; ++i) {
mc = &dss_cache.manager_cache[i];
- if (!mgr_busy[i])
+ if (!mgr_busy[i] && mc->shadow_dirty) {
+ dss_ovl_program_cb(&mc->cb, i);
mc->shadow_dirty = false;
+ }
+ }
+
+ if (!dss_cache.comp_irq_enabled && notify) {
+ r = omap_dispc_register_isr(dss_completion_irq_handler, NULL,
+ DISPC_IRQ_FRAMEDONE | DISPC_IRQ_VSYNC |
+ DISPC_IRQ_FRAMEDONE2 | DISPC_IRQ_VSYNC2 |
+ /*DISPC_IRQ_FRAMEDONE_DIG |*/ DISPC_IRQ_EVSYNC_EVEN |
+ DISPC_IRQ_EVSYNC_ODD);
+ dss_cache.comp_irq_enabled = true;
+ } else if (dss_cache.comp_irq_enabled && !notify) {
+ omap_dispc_unregister_isr(dss_completion_irq_handler, NULL,
+ DISPC_IRQ_FRAMEDONE | DISPC_IRQ_VSYNC |
+ DISPC_IRQ_FRAMEDONE2 | DISPC_IRQ_VSYNC2 |
+ /*DISPC_IRQ_FRAMEDONE_DIG |*/ DISPC_IRQ_EVSYNC_EVEN |
+ DISPC_IRQ_EVSYNC_ODD);
+ dss_cache.comp_irq_enabled = false;
}
r = configure_dispc();
@@ -1283,6 +1480,17 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
continue;
}
+ /* complete unconfigured info in cache */
+ dss_ovl_cb(&oc->cb.cache, i,
+#if 0
+ (oc->cb.cache.fn == ovl->info.cb.fn &&
+ oc->cb.cache.data == ovl->info.cb.data) ?
+ DSS_COMPLETION_CHANGED_CACHE :
+#endif
+ DSS_COMPLETION_ECLIPSED_CACHE);
+ oc->cb.cache = ovl->info.cb;
+ ovl->info.cb.fn = NULL;
+
ovl->info_dirty = false;
oc->dirty = true;
@@ -1302,6 +1510,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->out_height = ovl->info.out_height;
oc->global_alpha = ovl->info.global_alpha;
oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
+ oc->zorder = ovl->info.zorder;
+ oc->min_x_decim = ovl->info.min_x_decim;
+ oc->max_x_decim = ovl->info.max_x_decim;
+ oc->min_y_decim = ovl->info.min_y_decim;
+ oc->max_y_decim = ovl->info.max_y_decim;
oc->replication =
dss_use_replication(dssdev, ovl->info.color_mode);
@@ -1342,6 +1555,17 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
dssdev = mgr->device;
+ /* complete unconfigured info in cache */
+ dss_ovl_cb(&mc->cb.cache, mgr->id,
+#if 0
+ (mc->cb.cache.fn == mgr->info.cb.fn &&
+ mc->cb.cache.data == mgr->info.cb.data) ?
+ DSS_COMPLETION_CHANGED_CACHE :
+#endif
+ DSS_COMPLETION_ECLIPSED_CACHE);
+ mc->cb.cache = mgr->info.cb;
+ mgr->info.cb.fn = NULL;
+
mgr->info_dirty = false;
mc->dirty = true;
@@ -1441,12 +1665,20 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
static int dss_check_manager(struct omap_overlay_manager *mgr)
{
- /* OMAP supports only graphics source transparency color key and alpha
- * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
-
- if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
+ /* if we have OMAP3 alpha compatibility, alpha blending is always on */
+ if (dss_has_feature(FEAT_ALPHA_OMAP3_COMPAT)) {
+ if (!mgr->info.alpha_enabled)
+ return -EINVAL;
+ } else {
+ /*
+ * OMAP3- supports only graphics destination transparency
+ * color key and alpha blending simultaneously.
+ * See TRM 15.4.2.4.2.2 Alpha Mode.
+ */
+ if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
- return -EINVAL;
+ return -EINVAL;
+ }
return 0;
}
@@ -1466,6 +1698,9 @@ static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
return r;
}
+ if (mgr->info_dirty)
+ dss_ovl_cb(&old_info.cb, mgr->id, DSS_COMPLETION_ECLIPSED_SET);
+
mgr->info_dirty = true;
return 0;
@@ -1511,6 +1746,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
BUG_ON(mgr == NULL);
+ /* alpha blending always on with OMAP3 alpha compatibility */
+ if (dss_has_feature(FEAT_ALPHA_OMAP3_COMPAT))
+ mgr->info.alpha_enabled = true;
+
switch (i) {
case 0:
mgr->name = "lcd";
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index c84380c..2a5ce97 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -321,6 +321,118 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
return size;
}
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ovl->info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ struct omap_overlay_info info;
+
+ if (!dss_has_feature(FEAT_OVL_ZORDER))
+ return size;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.zorder = simple_strtoul(buf, NULL, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_decim_show(u16 min, u16 max, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d..%d\n", min, max);
+}
+
+static ssize_t overlay_x_decim_show(struct omap_overlay *ovl, char *buf)
+{
+ return overlay_decim_show(ovl->info.min_x_decim, ovl->info.max_x_decim,
+ buf);
+}
+
+static ssize_t overlay_y_decim_show(struct omap_overlay *ovl, char *buf)
+{
+ return overlay_decim_show(ovl->info.min_y_decim, ovl->info.max_y_decim,
+ buf);
+}
+
+static ssize_t overlay_decim_store(u16 *min, u16 *max,
+ const char *buf, size_t size)
+{
+ char *last;
+
+ *min = *max = simple_strtoul(buf, &last, 10);
+ if (last < buf + size && *last == '.') {
+ /* check for .. separator */
+ if (last + 2 >= buf + size || last[1] != '.')
+ return -EINVAL;
+
+ *max = simple_strtoul(last + 2, &last, 10);
+
+ /* fix order */
+ if (*max < *min)
+ swap(*min, *max);
+ }
+
+ /* decimation must be positive */
+ if (*min == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t overlay_x_decim_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ r = overlay_decim_store(&info.min_x_decim, &info.max_x_decim,
+ buf, size);
+
+ r = r ? : ovl->set_overlay_info(ovl, &info);
+
+ if (!r && ovl->manager)
+ r = ovl->manager->apply(ovl->manager);
+
+ return r ? : size;
+}
+
+static ssize_t overlay_y_decim_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ r = overlay_decim_store(&info.min_y_decim, &info.max_y_decim,
+ buf, size);
+
+ r = r ? : ovl->set_overlay_info(ovl, &info);
+
+ if (!r && ovl->manager)
+ r = ovl->manager->apply(ovl->manager);
+
+ return r ? : size;
+}
+
struct overlay_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay *, char *);
@@ -347,6 +459,12 @@ static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
overlay_pre_mult_alpha_show,
overlay_pre_mult_alpha_store);
+static OVERLAY_ATTR(x_decim, S_IRUGO|S_IWUSR,
+ overlay_x_decim_show, overlay_x_decim_store);
+static OVERLAY_ATTR(y_decim, S_IRUGO|S_IWUSR,
+ overlay_y_decim_show, overlay_y_decim_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+ overlay_zorder_show, overlay_zorder_store);
static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_name.attr,
@@ -358,6 +476,9 @@ static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_enabled.attr,
&overlay_attr_global_alpha.attr,
&overlay_attr_pre_mult_alpha.attr,
+ &overlay_attr_zorder.attr,
+ &overlay_attr_x_decim.attr,
+ &overlay_attr_y_decim.attr,
NULL
};
@@ -462,6 +583,12 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
return -EINVAL;
}
+ if ((info->zorder < OMAP_DSS_OVL_ZORDER_0) ||
+ (info->zorder > OMAP_DSS_OVL_ZORDER_3)) {
+ DSSERR("overlay doesn't support zorder %d\n", info->zorder);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -482,6 +609,14 @@ static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
}
}
+ /* complete previous settings */
+ if (ovl->info_dirty)
+ dss_ovl_cb(&old_info.cb, ovl->id,
+ (info->cb.fn == old_info.cb.fn &&
+ info->cb.data == old_info.cb.data) ?
+ DSS_COMPLETION_CHANGED_SET :
+ DSS_COMPLETION_ECLIPSED_SET);
+
ovl->info_dirty = true;
return 0;
@@ -620,6 +755,7 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->id = OMAP_DSS_GFX;
ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
+ ovl->info.zorder = OMAP_DSS_OVL_ZORDER_0;
break;
case 1:
ovl->name = "vid1";
@@ -627,6 +763,9 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
+ ovl->info.zorder = dss_has_feature(FEAT_OVL_ZORDER) ?
+ OMAP_DSS_OVL_ZORDER_3 :
+ OMAP_DSS_OVL_ZORDER_0;
break;
case 2:
ovl->name = "vid2";
@@ -634,9 +773,27 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
OMAP_DSS_OVL_CAP_DISPC;
ovl->info.global_alpha = 255;
+ ovl->info.zorder = dss_has_feature(FEAT_OVL_ZORDER) ?
+ OMAP_DSS_OVL_ZORDER_2 :
+ OMAP_DSS_OVL_ZORDER_0;
+ break;
+ case 3:
+ ovl->name = "vid3";
+ ovl->id = OMAP_DSS_VIDEO3;
+ ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
+ OMAP_DSS_OVL_CAP_DISPC;
+ ovl->info.global_alpha = 255;
+ ovl->info.zorder = dss_has_feature(FEAT_OVL_ZORDER) ?
+ OMAP_DSS_OVL_ZORDER_1 :
+ OMAP_DSS_OVL_ZORDER_0;
break;
+
}
+ ovl->info.min_x_decim = ovl->info.min_y_decim = 1;
+ ovl->info.max_x_decim = ovl->info.max_y_decim =
+ cpu_is_omap44xx() ? 16 : 1;
+
ovl->set_manager = &omap_dss_set_manager;
ovl->unset_manager = &omap_dss_unset_manager;
ovl->set_overlay_info = &dss_ovl_set_overlay_info;
diff --git a/drivers/video/omap2/dsscomp/Kconfig b/drivers/video/omap2/dsscomp/Kconfig
new file mode 100644
index 0000000..f3b6f64
--- /dev/null
+++ b/drivers/video/omap2/dsscomp/Kconfig
@@ -0,0 +1,9 @@
+menuconfig DSSCOMP
+ tristate "OMAP DSS Composition support (EXPERIMENTAL)"
+ depends on OMAP2_DSS
+ default y
+
+ help
+ Frame composition driver using OMAP DSS2. Allows using all
+ DSS2 resources in a unified configuration. Should not be used
+ together with other DSS2 devices, such as V4L2 or framebuffer.
diff --git a/drivers/video/omap2/dsscomp/Makefile b/drivers/video/omap2/dsscomp/Makefile
new file mode 100644
index 0000000..705e36e
--- /dev/null
+++ b/drivers/video/omap2/dsscomp/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_DSSCOMP) += dsscomp.o
+dsscomp-y := device.o base.o queue.o
diff --git a/drivers/video/omap2/dsscomp/base.c b/drivers/video/omap2/dsscomp/base.c
new file mode 100644
index 0000000..0d0e616
--- /dev/null
+++ b/drivers/video/omap2/dsscomp/base.c
@@ -0,0 +1,442 @@
+/*
+ * linux/drivers/video/omap2/dsscomp/base.c
+ *
+ * DSS Composition basic operation support
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+
+#include <linux/notifier.h>
+#include <mach/tiler.h>
+
+#include <video/omapdss.h>
+#include <video/dsscomp.h>
+#include <plat/dsscomp.h>
+
+#include "dsscomp.h"
+
+int debug;
+module_param(debug, int, 0644);
+
+/* color formats supported - bitfield info is used for truncation logic */
+static const struct color_info {
+ int a_ix, a_bt; /* bitfields */
+ int r_ix, r_bt;
+ int g_ix, g_bt;
+ int b_ix, b_bt;
+ int x_bt;
+ enum omap_color_mode mode;
+ const char *name;
+} fmts[2][16] = { {
+ { 0, 0, 0, 0, 0, 0, 0, 0, 1, OMAP_DSS_COLOR_CLUT1, "BITMAP1" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 2, OMAP_DSS_COLOR_CLUT2, "BITMAP2" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 4, OMAP_DSS_COLOR_CLUT4, "BITMAP4" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 8, OMAP_DSS_COLOR_CLUT8, "BITMAP8" },
+ { 0, 0, 8, 4, 4, 4, 0, 4, 4, OMAP_DSS_COLOR_RGB12U, "xRGB12-4444" },
+ { 12, 4, 8, 4, 4, 4, 0, 4, 0, OMAP_DSS_COLOR_ARGB16, "ARGB16-4444" },
+ { 0, 0, 11, 5, 5, 6, 0, 5, 0, OMAP_DSS_COLOR_RGB16, "RGB16-565" },
+ { 15, 1, 10, 5, 5, 5, 0, 5, 0, OMAP_DSS_COLOR_ARGB16_1555,
+ "ARGB16-1555" },
+ { 0, 0, 16, 8, 8, 8, 0, 8, 8, OMAP_DSS_COLOR_RGB24U, "xRGB24-8888" },
+ { 0, 0, 16, 8, 8, 8, 0, 8, 0, OMAP_DSS_COLOR_RGB24P, "RGB24-888" },
+ { 0, 0, 12, 4, 8, 4, 4, 4, 4, OMAP_DSS_COLOR_RGBX16, "RGBx12-4444" },
+ { 0, 4, 12, 4, 8, 4, 4, 4, 0, OMAP_DSS_COLOR_RGBA16, "RGBA16-4444" },
+ { 24, 8, 16, 8, 8, 8, 0, 8, 0, OMAP_DSS_COLOR_ARGB32, "ARGB32-8888" },
+ { 0, 8, 24, 8, 16, 8, 8, 8, 0, OMAP_DSS_COLOR_RGBA32, "RGBA32-8888" },
+ { 0, 0, 24, 8, 16, 8, 8, 8, 8, OMAP_DSS_COLOR_RGBX32, "RGBx24-8888" },
+ { 0, 0, 10, 5, 5, 5, 0, 5, 1, OMAP_DSS_COLOR_XRGB16_1555,
+ "xRGB15-1555" },
+}, {
+ { 0, 0, 0, 0, 0, 0, 0, 0, 12, OMAP_DSS_COLOR_NV12, "NV12" },
+ { 0, 0, 12, 4, 8, 4, 4, 4, 4, OMAP_DSS_COLOR_RGBX16, "RGBx12-4444" },
+ { 0, 4, 12, 4, 8, 4, 4, 4, 0, OMAP_DSS_COLOR_RGBA16, "RGBA16-4444" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "invalid" },
+ { 0, 0, 8, 4, 4, 4, 0, 4, 4, OMAP_DSS_COLOR_RGB12U, "xRGB12-4444" },
+ { 12, 4, 8, 4, 4, 4, 0, 4, 0, OMAP_DSS_COLOR_ARGB16, "ARGB16-4444" },
+ { 0, 0, 11, 5, 5, 6, 0, 5, 0, OMAP_DSS_COLOR_RGB16, "RGB16-565" },
+ { 15, 1, 10, 5, 5, 5, 0, 5, 0, OMAP_DSS_COLOR_ARGB16_1555,
+ "ARGB16-1555" },
+ { 0, 0, 16, 8, 8, 8, 0, 8, 8, OMAP_DSS_COLOR_RGB24U, "xRGB24-8888" },
+ { 0, 0, 16, 8, 8, 8, 0, 8, 0, OMAP_DSS_COLOR_RGB24P, "RGB24-888" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 16, OMAP_DSS_COLOR_YUV2, "YUYV" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 16, OMAP_DSS_COLOR_UYVY, "UYVY" },
+ { 24, 8, 16, 8, 8, 8, 0, 8, 0, OMAP_DSS_COLOR_ARGB32, "ARGB32-8888" },
+ { 0, 8, 24, 8, 16, 8, 8, 8, 0, OMAP_DSS_COLOR_RGBA32, "RGBA32-8888" },
+ { 0, 0, 24, 8, 16, 8, 8, 8, 8, OMAP_DSS_COLOR_RGBX32, "RGBx24-8888" },
+ { 0, 0, 10, 5, 5, 5, 0, 5, 1, OMAP_DSS_COLOR_XRGB16_1555,
+ "xRGB15-1555" },
+} };
+
+static const struct color_info *get_color_info(enum omap_color_mode mode)
+{
+ int i;
+ for (i = 0; i < sizeof(fmts) / sizeof(fmts[0][0]); i++)
+ if (fmts[0][i].mode == mode)
+ return fmts[0] + i;
+ return NULL;
+}
+
+static int color_mode_to_bpp(enum omap_color_mode color_mode)
+{
+ const struct color_info *ci = get_color_info(color_mode);
+ BUG_ON(!ci);
+
+ return ci->a_bt + ci->r_bt + ci->g_bt + ci->b_bt + ci->x_bt;
+}
+
+union rect {
+ struct {
+ s32 x;
+ s32 y;
+ s32 w;
+ s32 h;
+ };
+ struct {
+ s32 xy[2];
+ s32 wh[2];
+ };
+ struct dss2_rect_t r;
+};
+
+int crop_to_rect(union rect *crop, union rect *win, union rect *vis,
+ int rotation, int mirror)
+{
+ int c, swap = rotation & 1;
+
+ /* align crop window with display coordinates */
+ if (swap)
+ crop->y -= (crop->h = -crop->h);
+ if (rotation & 2)
+ crop->xy[!swap] -= (crop->wh[!swap] = -crop->wh[!swap]);
+ if ((!mirror) ^ !(rotation & 2))
+ crop->xy[swap] -= (crop->wh[swap] = -crop->wh[swap]);
+
+ for (c = 0; c < 2; c++) {
+ /* see if complete buffer is outside the vis or it is
+ fully cropped or scaled to 0 */
+ if (win->wh[c] <= 0 || vis->wh[c] <= 0 ||
+ win->xy[c] + win->wh[c] <= vis->xy[c] ||
+ win->xy[c] >= vis->xy[c] + vis->wh[c] ||
+ !crop->wh[c ^ swap])
+ return -ENOENT;
+
+ /* crop left/top */
+ if (win->xy[c] < vis->xy[c]) {
+ /* correction term */
+ int a = (vis->xy[c] - win->xy[c]) *
+ crop->wh[c ^ swap] / win->wh[c];
+ crop->xy[c ^ swap] += a;
+ crop->wh[c ^ swap] -= a;
+ win->wh[c] -= vis->xy[c] - win->xy[c];
+ win->xy[c] = vis->xy[c];
+ }
+ /* crop right/bottom */
+ if (win->xy[c] + win->wh[c] > vis->xy[c] + vis->wh[c]) {
+ crop->wh[c ^ swap] = crop->wh[c ^ swap] *
+ (vis->xy[c] + vis->wh[c] - win->xy[c]) /
+ win->wh[c];
+ win->wh[c] = vis->xy[c] + vis->wh[c] - win->xy[c];
+ }
+
+ if (!crop->wh[c ^ swap] || !win->wh[c])
+ return -ENOENT;
+ }
+
+ /* realign crop window to buffer coordinates */
+ if (rotation & 2)
+ crop->xy[!swap] -= (crop->wh[!swap] = -crop->wh[!swap]);
+ if ((!mirror) ^ !(rotation & 2))
+ crop->xy[swap] -= (crop->wh[swap] = -crop->wh[swap]);
+ if (swap)
+ crop->y -= (crop->h = -crop->h);
+ return 0;
+}
+
+int set_dss_ovl_info(struct dss2_ovl_info *oi)
+{
+ struct omap_overlay_info info;
+ struct omap_overlay *ovl;
+ struct dss2_ovl_cfg *cfg;
+ union rect crop, win, vis;
+ int c;
+
+ /* check overlay number */
+ if (!oi || oi->cfg.ix >= omap_dss_get_num_overlays())
+ return -EINVAL;
+ cfg = &oi->cfg;
+ ovl = omap_dss_get_overlay(cfg->ix);
+
+ /* just in case there are new fields, we get the current info */
+ ovl->get_overlay_info(ovl, &info);
+
+ info.enabled = cfg->enabled;
+ if (!cfg->enabled)
+ goto done;
+
+ /* copied params */
+ info.zorder = cfg->zorder;
+
+ if (cfg->zonly)
+ goto done;
+
+ info.global_alpha = cfg->global_alpha;
+ info.pre_mult_alpha = cfg->pre_mult_alpha;
+ info.rotation = cfg->rotation;
+ info.mirror = cfg->mirror;
+ info.color_mode = cfg->color_mode;
+
+ /* crop to screen */
+ crop.r = cfg->crop;
+ win.r = cfg->win;
+ vis.x = vis.y = 0;
+ vis.w = ovl->manager->device->panel.timings.x_res;
+ vis.h = ovl->manager->device->panel.timings.y_res;
+
+ if (crop_to_rect(&crop, &win, &vis, cfg->rotation, cfg->mirror) ||
+ vis.w < 2) {
+ info.enabled = false;
+ goto done;
+ }
+
+ /* adjust crop to UV pixel boundaries */
+ for (c = 0; c < (cfg->color_mode == OMAP_DSS_COLOR_NV12 ? 2 :
+ (cfg->color_mode &
+ (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) ? 1 : 0); c++) {
+ /* keep the output window to avoid trembling edges */
+ crop.wh[c] += crop.xy[c] & 1; /* round down start */
+ crop.xy[c] &= ~1;
+ crop.wh[c] += crop.wh[c] & 1; /* round up end */
+
+ /*
+ * Buffer is aligned on UV pixel boundaries, so no
+ * worries about extending crop region.
+ */
+ }
+
+ info.width = crop.w;
+ info.height = crop.h;
+ if (cfg->rotation & 1)
+ /* DISPC uses swapped height/width for 90/270 degrees */
+ swap(info.width, info.height);
+ info.pos_x = win.x;
+ info.pos_y = win.y;
+ info.out_width = win.w;
+ info.out_height = win.h;
+
+ /* calculate addresses and cropping */
+ info.paddr = oi->ba;
+ info.p_uv_addr = (info.color_mode == OMAP_DSS_COLOR_NV12) ? oi->uv : 0;
+ info.vaddr = NULL;
+
+ /* check for TILER 2D buffer */
+ if (info.paddr >= 0x60000000 && info.paddr < 0x78000000) {
+ int bpp = 1 << ((info.paddr >> 27) & 3);
+ struct tiler_view_t t;
+
+ /* crop to top-left */
+
+ /*
+ * DSS supports YUV422 on 32-bit mode, but its technically
+ * 2 bytes-per-pixel.
+ * Also RGB24-888 is 3 bytes-per-pixel even though no
+ * tiler pixel format matches this.
+ */
+ if (cfg->color_mode &
+ (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY))
+ bpp = 2;
+ else if (cfg->color_mode == OMAP_DSS_COLOR_RGB24P)
+ bpp = 3;
+
+ tilview_create(&t, info.paddr, info.width, info.height);
+ info.paddr -= t.tsptr;
+ tilview_crop(&t, 0, crop.y, info.width, crop.h);
+ info.paddr += t.tsptr + bpp * crop.x;
+
+ info.rotation_type = OMAP_DSS_ROT_TILER;
+ info.screen_width = 0;
+
+ /* for NV12 format also crop NV12 */
+ if (info.color_mode == OMAP_DSS_COLOR_NV12) {
+ tilview_create(&t, info.p_uv_addr,
+ info.width >> 1, info.height >> 1);
+ info.p_uv_addr -= t.tsptr;
+ tilview_crop(&t, 0, crop.y >> 1, info.width,
+ crop.h >> 1);
+ info.p_uv_addr += t.tsptr + bpp * crop.x;
+ }
+ } else {
+ /* program tiler 1D as SDMA */
+
+ int bpp = color_mode_to_bpp(cfg->color_mode);
+ info.screen_width = cfg->stride * 8 / (bpp == 12 ? 8 : bpp);
+ info.paddr += crop.x * (bpp / 8) + crop.y * cfg->stride;
+
+ /* for NV12 format also crop NV12 */
+ if (info.color_mode == OMAP_DSS_COLOR_NV12)
+ info.p_uv_addr += crop.x * (bpp / 8) +
+ (crop.y >> 1) * cfg->stride;
+
+ /* no rotation on DMA buffer */
+ if (cfg->rotation & 3 || cfg->mirror)
+ return -EINVAL;
+
+ info.rotation_type = OMAP_DSS_ROT_DMA;
+ }
+
+ info.max_x_decim = cfg->decim.max_x ? : 255;
+ info.max_y_decim = cfg->decim.max_y ? : 255;
+ info.min_x_decim = cfg->decim.min_x ? : 1;
+ info.min_y_decim = cfg->decim.min_y ? : 1;
+#if 0
+ info.pic_height = cfg->height;
+
+ info.field = 0;
+ if (cfg->ilace & OMAP_DSS_ILACE_SEQ)
+ info.field |= OMAP_FLAG_IBUF;
+ if (cfg->ilace & OMAP_DSS_ILACE_SWAP)
+ info.field |= OMAP_FLAG_ISWAP;
+ /*
+ * Ignore OMAP_DSS_ILACE as there is no real support yet for
+ * interlaced interleaved vs progressive buffers
+ */
+ if (ovl->manager &&
+ ovl->manager->device &&
+ !strcmp(ovl->manager->device->name, "hdmi") &&
+ is_hdmi_interlaced())
+ info.field |= OMAP_FLAG_IDEV;
+
+ info.out_wb = 0;
+#endif
+
+ /* :TODO: copy color conversion - this needs ovl support */
+
+done:
+#if 0
+ pr_debug("ovl%d: en=%d %x/%x (%dx%d|%d) => (%dx%d) @ (%d,%d) rot=%d "
+ "mir=%d col=%x z=%d al=%02x prem=%d pich=%d ilace=%d\n",
+ ovl->id, info.enabled, info.paddr, info.p_uv_addr, info.width,
+ info.height, info.screen_width, info.out_width, info.out_height,
+ info.pos_x, info.pos_y, info.rotation, info.mirror,
+ info.color_mode, info.zorder, info.global_alpha,
+ info.pre_mult_alpha, info.pic_height, info.field);
+#else
+ pr_debug("ovl%d: en=%d %x/%x (%dx%d|%d) => (%dx%d) @ (%d,%d) rot=%d "
+ "mir=%d col=%x z=%d al=%02x prem=%d\n",
+ ovl->id, info.enabled, info.paddr, info.p_uv_addr, info.width,
+ info.height, info.screen_width, info.out_width, info.out_height,
+ info.pos_x, info.pos_y, info.rotation, info.mirror,
+ info.color_mode, info.zorder, info.global_alpha,
+ info.pre_mult_alpha);
+#endif
+ /* set overlay info */
+ return ovl->set_overlay_info(ovl, &info);
+}
+
+struct omap_overlay_manager *find_dss_mgr(int display_ix)
+{
+ struct omap_overlay_manager *mgr;
+ char name[32];
+ int i;
+
+ sprintf(name, "display%d", display_ix);
+
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
+ mgr = omap_dss_get_overlay_manager(i);
+ if (mgr->device && !strcmp(name, dev_name(&mgr->device->dev)))
+ return mgr;
+ }
+ return NULL;
+}
+
+int set_dss_mgr_info(struct dss2_mgr_info *mi)
+{
+ struct omap_overlay_manager_info info;
+ struct omap_overlay_manager *mgr;
+
+ if (!mi)
+ return -EINVAL;
+ mgr = find_dss_mgr(mi->ix);
+ if (!mgr)
+ return -EINVAL;
+
+ /* just in case there are new fields, we get the current info */
+ mgr->get_manager_info(mgr, &info);
+
+ info.alpha_enabled = mi->alpha_blending;
+ info.default_color = mi->default_color;
+ info.trans_enabled = mi->trans_enabled && !mi->alpha_blending;
+ info.trans_key = mi->trans_key;
+ info.trans_key_type = mi->trans_key_type;
+
+ return mgr->set_manager_info(mgr, &info);
+}
+
+/*
+ * ===========================================================================
+ * DEBUG METHODS
+ * ===========================================================================
+ */
+void dump_ovl_info(struct dsscomp_dev *cdev, struct dss2_ovl_info *oi)
+{
+ struct dss2_ovl_cfg *c = &oi->cfg;
+ const struct color_info *ci;
+
+ if (!(debug & DEBUG_OVERLAYS) ||
+ !(debug & DEBUG_COMPOSITIONS))
+ return;
+
+ ci = get_color_info(c->color_mode);
+ if (c->zonly) {
+ dev_info(DEV(cdev), "ovl%d(%s z%d)\n",
+ c->ix, c->enabled ? "ON" : "off", c->zorder);
+ return;
+ }
+ dev_info(DEV(cdev), "ovl%d(%s z%d %s%s *%d%% %d*%d:%d,%d+%d,%d rot%d%s"
+ " => %d,%d+%d,%d %p/%p|%d)\n",
+ c->ix, c->enabled ? "ON" : "off", c->zorder,
+ ci->name ? : "(none)",
+ c->pre_mult_alpha ? " premult" : "",
+ (c->global_alpha * 100 + 128) / 255,
+ c->width, c->height, c->crop.x, c->crop.y,
+ c->crop.w, c->crop.h,
+ c->rotation, c->mirror ? "+mir" : "",
+ c->win.x, c->win.y, c->win.w, c->win.h,
+ (void *) oi->ba, (void *) oi->uv, c->stride);
+}
+
+void dump_comp_info(struct dsscomp_dev *cdev, struct dsscomp_setup_mgr_data *d,
+ const char *phase)
+{
+ struct dss2_mgr_info *mi = &d->mgr;
+
+ if (!(debug & DEBUG_COMPOSITIONS))
+ return;
+
+ dev_info(DEV(cdev), "[%08x] %s: %c%c%c"
+ "(dis%d(%s) alpha=%d col=%08x ilace=%d n=%d)\n",
+ d->sync_id, phase,
+ (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-',
+ (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-',
+ (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-',
+ mi->ix,
+ (mi->ix < cdev->num_displays && cdev->displays[mi->ix]) ?
+ cdev->displays[mi->ix]->name : "NONE",
+ mi->alpha_blending, mi->default_color,
+ mi->interlaced,
+ d->num_ovls);
+}
diff --git a/drivers/video/omap2/dsscomp/device.c b/drivers/video/omap2/dsscomp/device.c
new file mode 100644
index 0000000..20235a8
--- /dev/null
+++ b/drivers/video/omap2/dsscomp/device.c
@@ -0,0 +1,369 @@
+/*
+ * linux/drivers/video/omap2/dsscomp/device.c
+ *
+ * DSS Composition file device and ioctl support
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DEBUG
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#define MODULE_NAME "dsscomp"
+
+#include <video/omapdss.h>
+#include <video/dsscomp.h>
+#include <plat/dsscomp.h>
+#include "dsscomp.h"
+
+static u32 hwc_virt_to_phys(u32 arg)
+{
+ pmd_t *pmd;
+ pte_t *ptep;
+
+ pgd_t *pgd = pgd_offset(current->mm, arg);
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ return 0;
+
+ pmd = pmd_offset(pgd, arg);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ return 0;
+
+ ptep = pte_offset_map(pmd, arg);
+ if (ptep && pte_present(*ptep))
+ return (PAGE_MASK & *ptep) | (~PAGE_MASK & arg);
+
+ return 0;
+}
+
+static long setup_mgr(struct dsscomp_dev *cdev,
+ struct dsscomp_setup_mgr_data *d)
+{
+ int i, r;
+ struct omap_dss_device *dev;
+ struct omap_overlay_manager *mgr;
+ dsscomp_t comp;
+
+ dump_comp_info(cdev, d, "queue");
+ for (i = 0; i < d->num_ovls; i++)
+ dump_ovl_info(cdev, d->ovls + i);
+
+ /* verify display is valid and connected */
+ if (d->mgr.ix >= cdev->num_displays)
+ return -EINVAL;
+ dev = cdev->displays[d->mgr.ix];
+ if (!dev)
+ return -EINVAL;
+ mgr = dev->manager;
+ if (!mgr)
+ return -ENODEV;
+
+ comp = dsscomp_new_sync_id(mgr, d->sync_id);
+ if (IS_ERR(comp))
+ return PTR_ERR(comp);
+
+ r = dsscomp_set_mgr(comp, &d->mgr);
+
+ for (i = 0; i < d->num_ovls; i++) {
+ struct dss2_ovl_info *oi = d->ovls + i;
+ u32 addr = (u32) oi->address;
+
+ /* convert addresses to user space */
+ if (oi->cfg.color_mode == OMAP_DSS_COLOR_NV12)
+ oi->uv = hwc_virt_to_phys(addr +
+ oi->cfg.height * oi->cfg.stride);
+ oi->ba = hwc_virt_to_phys(addr);
+
+ r = r ? : dsscomp_set_ovl(comp, oi);
+ }
+
+ r = r ? : dsscomp_setup(comp, d->mode, d->win);
+ if (r)
+ dsscomp_drop(comp);
+ else if (d->mode & DSSCOMP_SETUP_APPLY)
+ r = dsscomp_apply(comp);
+
+ return r;
+}
+
+static long query_display(struct dsscomp_dev *cdev,
+ struct dsscomp_display_info *dis)
+{
+ struct omap_dss_device *dev;
+ struct omap_overlay_manager *mgr;
+ int i;
+
+ /* get display */
+ if (dis->ix >= cdev->num_displays)
+ return -EINVAL;
+ dev = cdev->displays[dis->ix];
+ if (!dev)
+ return -EINVAL;
+ mgr = dev->manager;
+
+ /* fill out display information */
+ dis->channel = dev->channel;
+ dis->enabled = (dev->state == OMAP_DSS_DISPLAY_SUSPENDED) ?
+ dev->activate_after_resume :
+ (dev->state == OMAP_DSS_DISPLAY_ACTIVE);
+ dis->overlays_available = 0;
+ dis->overlays_owned = 0;
+#if 0
+ dis->s3d_info = dev->panel.s3d_info;
+#endif
+ dis->state = dev->state;
+ dis->timings = dev->panel.timings;
+
+ /* find all overlays available for/owned by this display */
+ for (i = 0; i < cdev->num_ovls && dis->enabled; i++) {
+ if (cdev->ovls[i]->manager == mgr)
+ dis->overlays_owned |= 1 << i;
+ else if (!cdev->ovls[i]->info.enabled)
+ dis->overlays_available |= 1 << i;
+ }
+ dis->overlays_available |= dis->overlays_owned;
+
+ /* fill out manager information */
+ if (mgr) {
+ dis->mgr.alpha_blending = mgr->info.alpha_enabled;
+ dis->mgr.default_color = mgr->info.default_color;
+#if 0
+ dis->mgr.interlaced = !strcmp(dev->name, "hdmi") &&
+ is_hdmi_interlaced()
+#else
+ dis->mgr.interlaced = 0;
+#endif
+ dis->mgr.trans_enabled = mgr->info.trans_enabled;
+ dis->mgr.trans_key = mgr->info.trans_key;
+ dis->mgr.trans_key_type = mgr->info.trans_key_type;
+ } else {
+ /* display is disabled if it has no manager */
+ memset(&dis->mgr, 0, sizeof(dis->mgr));
+ }
+ dis->mgr.ix = dis->ix;
+
+ return 0;
+}
+
+static long check_ovl(struct dsscomp_dev *cdev,
+ struct dsscomp_check_ovl_data *chk)
+{
+ /* for now return all overlays as possible */
+ return (1 << cdev->num_ovls) - 1;
+}
+
+static long wait(struct dsscomp_dev *cdev, struct dsscomp_wait_data *wd)
+{
+ struct omap_overlay_manager *mgr;
+ dsscomp_t comp;
+
+ /* get manager */
+ if (wd->ix >= cdev->num_displays || !cdev->displays[wd->ix])
+ return -EINVAL;
+ mgr = cdev->displays[wd->ix]->manager;
+ if (!mgr)
+ return -ENODEV;
+
+ /* get composition */
+ comp = dsscomp_find(mgr, wd->sync_id);
+ if (IS_ERR(comp))
+ return 0;
+
+ return dsscomp_wait(comp, wd->phase, usecs_to_jiffies(wd->timeout_us));
+}
+
+static void fill_cache(struct dsscomp_dev *cdev)
+{
+ unsigned long i;
+ struct omap_dss_device *dssdev = NULL;
+
+ cdev->num_ovls = min(omap_dss_get_num_overlays(), MAX_OVERLAYS);
+ for (i = 0; i < cdev->num_ovls; i++)
+ cdev->ovls[i] = omap_dss_get_overlay(i);
+
+ cdev->num_mgrs = min(omap_dss_get_num_overlay_managers(), MAX_MANAGERS);
+ for (i = 0; i < cdev->num_mgrs; i++)
+ cdev->mgrs[i] = omap_dss_get_overlay_manager(i);
+
+ for_each_dss_dev(dssdev) {
+ const char *name = dev_name(&dssdev->dev);
+ if (strncmp(name, "display", 7) ||
+ strict_strtoul(name + 7, 10, &i) ||
+ i >= MAX_DISPLAYS)
+ continue;
+
+ if (cdev->num_displays <= i)
+ cdev->num_displays = i + 1;
+
+ cdev->displays[i] = dssdev;
+ dev_dbg(DEV(cdev), "display%lu=%s\n", i, dssdev->driver_name);
+ }
+ dev_info(DEV(cdev), "found %d displays and %d overlays\n",
+ cdev->num_displays, cdev->num_ovls);
+}
+
+static long comp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int r = 0;
+ struct miscdevice *dev = filp->private_data;
+ struct dsscomp_dev *cdev = container_of(dev, struct dsscomp_dev, dev);
+ void __user *ptr = (void __user *)arg;
+
+ switch (cmd) {
+ case DSSCOMP_SETUP_MGR:
+ {
+ struct {
+ struct dsscomp_setup_mgr_data set;
+ struct dss2_ovl_info ovl[MAX_OVERLAYS];
+ } p;
+
+ r = copy_from_user(&p.set, ptr, sizeof(p.set)) ? :
+ p.set.num_ovls >= ARRAY_SIZE(p.ovl) ? -EINVAL :
+ copy_from_user(&p.ovl, (void __user *)arg + sizeof(p.set),
+ sizeof(*p.ovl) * p.set.num_ovls) ? :
+ setup_mgr(cdev, &p.set);
+ break;
+ }
+ case DSSCOMP_QUERY_DISPLAY:
+ {
+ struct dsscomp_display_info dis;
+ r = copy_from_user(&dis, ptr, sizeof(dis)) ? :
+ query_display(cdev, &dis) ? :
+ copy_to_user(ptr, &dis, sizeof(dis));
+ break;
+ }
+ case DSSCOMP_CHECK_OVL:
+ {
+ struct dsscomp_check_ovl_data chk;
+ r = copy_from_user(&chk, ptr, sizeof(chk)) ? :
+ check_ovl(cdev, &chk);
+ break;
+ }
+ case DSSCOMP_WAIT:
+ {
+ struct dsscomp_wait_data wd;
+ r = copy_from_user(&wd, ptr, sizeof(wd)) ? :
+ wait(cdev, &wd);
+ break;
+ }
+ default:
+ r = -EINVAL;
+ }
+ return r;
+}
+
+/* must implement open for filp->private_data to be filled */
+static int comp_open(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static const struct file_operations comp_fops = {
+ .owner = THIS_MODULE,
+ .open = comp_open,
+ .unlocked_ioctl = comp_ioctl,
+};
+
+static int dsscomp_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct dsscomp_dev *cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ if (!cdev) {
+ pr_err("dsscomp: failed to allocate device.\n");
+ return -ENOMEM;
+ }
+ cdev->dev.minor = MISC_DYNAMIC_MINOR;
+ cdev->dev.name = "dsscomp";
+ cdev->dev.mode = 0666;
+ cdev->dev.fops = &comp_fops;
+
+ ret = misc_register(&cdev->dev);
+ if (ret) {
+ pr_err("dsscomp: failed to register misc device.\n");
+ return ret;
+ }
+ cdev->dbgfs = debugfs_create_dir("dsscomp", NULL);
+ if (IS_ERR_OR_NULL(cdev->dbgfs))
+ dev_warn(DEV(cdev), "failed to create debug files.\n");
+
+ platform_set_drvdata(pdev, cdev);
+
+ fill_cache(cdev);
+
+ /* initialize queues */
+ dsscomp_queue_init(cdev);
+
+ return 0;
+}
+
+static int dsscomp_remove(struct platform_device *pdev)
+{
+ struct dsscomp_dev *cdev = platform_get_drvdata(pdev);
+ misc_deregister(&cdev->dev);
+ debugfs_remove_recursive(cdev->dbgfs);
+
+ dsscomp_queue_exit();
+ kfree(cdev);
+
+ return 0;
+}
+
+static struct platform_driver dsscomp_pdriver = {
+ .probe = dsscomp_probe,
+ .remove = dsscomp_remove,
+ .driver = { .name = MODULE_NAME, .owner = THIS_MODULE }
+};
+
+static struct platform_device dsscomp_pdev = {
+ .name = MODULE_NAME,
+ .id = -1
+};
+
+static int __init dsscomp_init(void)
+{
+ int err = platform_driver_register(&dsscomp_pdriver);
+ if (err)
+ return err;
+
+ err = platform_device_register(&dsscomp_pdev);
+ if (err)
+ platform_driver_unregister(&dsscomp_pdriver);
+ return err;
+}
+
+static void __exit dsscomp_exit(void)
+{
+ platform_device_unregister(&dsscomp_pdev);
+ platform_driver_unregister(&dsscomp_pdriver);
+}
+
+MODULE_LICENSE("GPL v2");
+module_init(dsscomp_init);
+module_exit(dsscomp_exit);
diff --git a/drivers/video/omap2/dsscomp/dsscomp.h b/drivers/video/omap2/dsscomp/dsscomp.h
new file mode 100644
index 0000000..baf8034
--- /dev/null
+++ b/drivers/video/omap2/dsscomp/dsscomp.h
@@ -0,0 +1,83 @@
+/*
+ * linux/drivers/video/omap2/dsscomp/base.c
+ *
+ * DSS Composition basic operation support
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DSSCOMP_H
+#define _DSSCOMP_H
+
+#include <linux/miscdevice.h>
+#include <linux/debugfs.h>
+
+#define MAX_OVERLAYS 5
+#define MAX_MANAGERS 3
+#define MAX_DISPLAYS 4
+
+#define DEBUG_OVERLAYS (1 << 0)
+#define DEBUG_COMPOSITIONS (1 << 1)
+#define DEBUG_PHASES (1 << 2)
+#define DEBUG_WAITS (1 << 3)
+
+/*
+ * Utility macros
+ */
+#define ZERO(c) memset(&c, 0, sizeof(c))
+#define ZEROn(c, n) memset(c, 0, sizeof(*c) * n)
+#define DEV(c) (c->dev.this_device)
+
+/**
+ * DSS Composition Device Driver
+ *
+ * @dev: misc device base
+ * @dbgfs: debugfs hook
+ */
+struct dsscomp_dev {
+ struct miscdevice dev;
+ struct dentry *dbgfs;
+
+ /* cached DSS objects */
+ u32 num_ovls;
+ struct omap_overlay *ovls[MAX_OVERLAYS];
+ u32 num_mgrs;
+ struct omap_overlay_manager *mgrs[MAX_MANAGERS];
+ u32 num_displays;
+ struct omap_dss_device *displays[MAX_DISPLAYS];
+};
+
+extern int debug;
+
+/*
+ * Kernel interface
+ */
+int dsscomp_queue_init(struct dsscomp_dev *cdev);
+void dsscomp_queue_exit(void);
+
+/* basic operation - if not using queues */
+int set_dss_ovl_info(struct dss2_ovl_info *oi);
+int set_dss_mgr_info(struct dss2_mgr_info *mi);
+struct omap_overlay_manager *find_dss_mgr(int display_ix);
+
+/*
+ * Debug functions
+ */
+void dump_ovl_info(struct dsscomp_dev *cdev, struct dss2_ovl_info *oi);
+void dump_comp_info(struct dsscomp_dev *cdev, struct dsscomp_setup_mgr_data *d,
+ const char *phase);
+
+#endif
diff --git a/drivers/video/omap2/dsscomp/queue.c b/drivers/video/omap2/dsscomp/queue.c
new file mode 100644
index 0000000..ade17a0
--- /dev/null
+++ b/drivers/video/omap2/dsscomp/queue.c
@@ -0,0 +1,887 @@
+/*
+ * linux/drivers/video/omap2/dsscomp/queue.c
+ *
+ * DSS Composition queueing support
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+
+#include <video/omapdss.h>
+#include <video/dsscomp.h>
+#include <plat/dsscomp.h>
+
+#include "dsscomp.h"
+
+/* queue state */
+static DEFINE_MUTEX(mtx);
+
+/* free overlay structs */
+static LIST_HEAD(free_ois);
+
+#define QUEUE_SIZE 3
+
+#define MUTEXED(exp) ({ typeof(exp) __r;\
+ mutex_lock(&mtx); __r = (exp); mutex_unlock(&mtx); __r; })
+
+#undef STRICT_CHECK
+
+#define MAGIC_ACTIVE 0xAC54156E
+#define MAGIC_APPLIED 0xA50504C1
+#define MAGIC_PROGRAMMED 0x50520652
+#define MAGIC_DISPLAYED 0xD15504CA
+
+static struct dsscomp_data {
+ u32 magic;
+ struct dsscomp_setup_mgr_data frm;
+ /*
+ * :TRICKY: before applying, overlays used in a composition are stored
+ * in ovl_mask and the other masks are empty. Once composition is
+ * applied, blank is set to see if all overlays are to be disabled on
+ * this composition, any disabled overlays in the composition are set in
+ * ovl_dmask, and ovl_mask is updated to include ALL overlays that are
+ * actually on the display - even if they are not part of the
+ * composition. The reason: we use ovl_mask to see if an overlay is used
+ * or planned to be used on a manager. We update ovl_mask when
+ * composition is programmed (removing the disabled overlays).
+ */
+ bool blank; /* true if all overlays are to be disabled */
+ u32 ovl_mask; /* overlays used on this frame */
+ u32 ovl_dmask; /* overlays disabled on this frame */
+ u32 ix; /* manager index that this frame is on */
+ struct list_head q;
+ struct list_head ois;
+ struct omapdss_ovl_cb cb;
+} *cis;
+
+static struct dss2_overlay {
+ struct dss2_ovl_info ovl;
+ struct list_head q;
+} *ois;
+
+static struct {
+ struct list_head q_ci; /* compositions */
+ struct list_head free_cis; /* free composition structs */
+
+ wait_queue_head_t wq;
+
+ u32 ovl_mask; /* overlays used on this display */
+ u32 ovl_qmask; /* overlays queued to this display */
+} mgrq[MAX_MANAGERS];
+
+static struct dsscomp_dev *cdev;
+
+/*
+ * ===========================================================================
+ * EXIT
+ * ===========================================================================
+ */
+
+/* Initialize queue structures, and set up state of the displays */
+int dsscomp_queue_init(struct dsscomp_dev *cdev_)
+{
+ u32 i, j, ncis, nois;
+
+ cdev = cdev_;
+ ncis = QUEUE_SIZE * cdev->num_mgrs;
+ nois = QUEUE_SIZE * cdev->num_ovls;
+
+ INIT_LIST_HEAD(&free_ois);
+
+ cis = vmalloc(sizeof(*cis) * ncis);
+ ois = vmalloc(sizeof(*ois) * nois);
+
+ if (cis && ois && ARRAY_SIZE(mgrq) >= cdev->num_mgrs) {
+ ZERO(mgrq);
+ ZEROn(cis, ncis);
+ ZEROn(ois, nois);
+
+ for (i = 0; i < nois; i++)
+ list_add(&ois[i].q, &free_ois);
+ for (i = 0; i < cdev->num_mgrs; i++) {
+ struct omap_overlay_manager *mgr;
+ INIT_LIST_HEAD(&mgrq[i].q_ci);
+ INIT_LIST_HEAD(&mgrq[i].free_cis);
+ init_waitqueue_head(&mgrq[i].wq);
+
+ for (j = 0; j < QUEUE_SIZE; j++)
+ list_add(&cis[j + QUEUE_SIZE * i].q,
+ &mgrq[i].free_cis);
+
+ /* record overlays on this display */
+ mgr = cdev->mgrs[i];
+ for (j = 0; j < cdev->num_ovls; j++) {
+ if (cdev->ovls[j]->info.enabled &&
+ mgr &&
+ cdev->ovls[j]->manager == mgr)
+ mgrq[i].ovl_mask |= 1 << j;
+ }
+ }
+ return 0;
+ } else {
+ vfree(cis);
+ vfree(ois);
+ return -ENOMEM;
+ }
+}
+
+/* returns if composition is valid and active */
+static inline struct dsscomp_data *validate(struct dsscomp_data *comp)
+{
+#ifdef STRICT_CHECK
+ u32 ix, q_ix;
+ struct dsscomp_data *c;
+ struct omap_overlay_manager *mgr;
+
+ if (!comp)
+ return ERR_PTR(-EFAULT);
+
+ ix = comp->frm.mgr.ix;
+ if (ix >= cdev->num_displays || !cdev->displays[ix])
+ return ERR_PTR(-EINVAL);
+ mgr = cdev->displays[ix]->manager;
+ if (!mgr || mgr->id >= cdev->num_mgrs)
+ return ERR_PTR(-ENODEV);
+
+ /* check if composition is active */
+ list_for_each_entry(c, &mgrq[mgr->id].q_ci, q)
+ if (c == comp)
+ return c;
+ return ERR_PTR(-ESRCH);
+#else
+ if (!comp)
+ return ERR_PTR(-EFAULT);
+
+ return (comp->magic == MAGIC_PROGRAMMED ||
+ comp->magic == MAGIC_DISPLAYED ||
+ comp->magic == MAGIC_APPLIED ||
+ comp->magic == MAGIC_ACTIVE) ? comp : ERR_PTR(-ESRCH);
+#endif
+}
+
+
+/* get display index from manager */
+static u32 get_display_ix(struct omap_overlay_manager *mgr)
+{
+ u32 i;
+
+ /* handle if manager is not attached to a display */
+ if (!mgr || !mgr->device)
+ return cdev->num_displays;
+
+ /* find manager's display */
+ for (i = 0; i < cdev->num_displays; i++)
+ if (cdev->displays[i] == mgr->device)
+ break;
+
+ return i;
+}
+
+/*
+ * ===========================================================================
+ * QUEUING SETUP OPERATIONS
+ * ===========================================================================
+ */
+
+/* get composition by sync_id */
+static dsscomp_t dsscomp_get(struct omap_overlay_manager *mgr, u32 sync_id)
+{
+ struct dsscomp_data *comp;
+
+ /* get display index */
+ u32 ix = mgr ? mgr->id : cdev->num_mgrs;
+ if (ix >= cdev->num_mgrs)
+ return NULL;
+
+ /* find composition with sync id on manager */
+ list_for_each_entry(comp, &mgrq[ix].q_ci, q)
+ if (comp->frm.sync_id == sync_id)
+ return comp;
+
+ return NULL;
+}
+
+/* create a new composition for a display */
+dsscomp_t dsscomp_new_sync_id(struct omap_overlay_manager *mgr, u32 sync_id)
+{
+ struct dsscomp_data *comp = NULL;
+ int r;
+ u32 display_ix = get_display_ix(mgr);
+
+ /* check manager */
+ u32 ix = mgr ? mgr->id : cdev->num_mgrs;
+ if (ix >= cdev->num_mgrs || display_ix >= cdev->num_displays)
+ return ERR_PTR(-EINVAL);
+
+ /* see if sync_id exists */
+ mutex_lock(&mtx);
+ if (dsscomp_get(mgr, sync_id)) {
+ r = -EEXIST;
+ goto done;
+ }
+
+ /* check if there is space on the queue */
+ if (list_empty(&mgrq[ix].free_cis)) {
+ /* discard earliest unapplied frame */
+ list_for_each_entry(comp, &mgrq[ix].q_ci, q) {
+ if (comp->magic == MAGIC_ACTIVE)
+ break;
+ }
+ /* fail if we have not found one */
+ if (&comp->q == &mgrq[ix].q_ci) {
+ r = -EBUSY;
+ goto done;
+ }
+ dsscomp_drop(comp);
+ }
+
+ /* initialize new composition */
+ comp = list_first_entry(&mgrq[ix].free_cis, typeof(*comp), q);
+ list_move_tail(&comp->q, &mgrq[ix].q_ci);
+ comp->ix = ix; /* save where this composition came from */
+ ZERO(comp->frm);
+ INIT_LIST_HEAD(&comp->ois);
+ comp->ovl_mask = comp->ovl_dmask = 0;
+ comp->frm.sync_id = sync_id;
+ comp->frm.mgr.ix = display_ix;
+ ZERO(comp->cb);
+
+ /* :TODO: retrieve last manager configuration */
+
+ comp->magic = MAGIC_ACTIVE;
+ r = 0;
+ done:
+ mutex_unlock(&mtx);
+ return r ? ERR_PTR(r) : comp;
+}
+EXPORT_SYMBOL(dsscomp_new_sync_id);
+
+dsscomp_t dsscomp_find(struct omap_overlay_manager *mgr, u32 sync_id)
+{
+ struct dsscomp_data *comp;
+
+ /* check manager */
+ if (!mgr || mgr->id >= cdev->num_mgrs)
+ return ERR_PTR(-EINVAL);
+
+ /* see if sync_id exists */
+ mutex_lock(&mtx);
+ comp = dsscomp_get(mgr, sync_id);
+ if (IS_ERR(comp))
+ comp = NULL;
+ mutex_unlock(&mtx);
+ return comp;
+}
+EXPORT_SYMBOL(dsscomp_find);
+
+/* find first unapplied sync_id or 0 if none found */
+u32 dsscomp_first_sync_id(struct omap_overlay_manager *mgr)
+{
+ struct dsscomp_data *comp;
+ u32 sync_id = 0;
+
+ /* get display index */
+ u32 ix = mgr ? mgr->id : cdev->num_mgrs;
+ if (ix >= cdev->num_mgrs)
+ return 0;
+
+ /* find first unapplied composition */
+ mutex_lock(&mtx);
+ list_for_each_entry(comp, &mgrq[ix].q_ci, q) {
+ if (comp->magic == MAGIC_ACTIVE &&
+ (DSSCOMP_SETUP_MODE_APPLY & ~comp->frm.mode)) {
+ sync_id = comp->frm.sync_id;
+ break;
+ }
+ }
+ mutex_unlock(&mtx);
+
+ return sync_id;
+}
+EXPORT_SYMBOL(dsscomp_first_sync_id);
+
+/* returns overlays used in a composition */
+u32 dsscomp_get_ovls(dsscomp_t comp)
+{
+ BUG_ON(MUTEXED(IS_ERR(validate(comp))));
+
+ return comp->ovl_mask;
+}
+EXPORT_SYMBOL(dsscomp_get_ovls);
+
+/* set overlay info */
+int dsscomp_set_ovl(dsscomp_t comp, struct dss2_ovl_info *ovl)
+{
+ int r = -EFAULT;
+
+ if (comp && ovl) {
+ u32 i, mask = 1 << ovl->cfg.ix;
+ struct omap_overlay *o;
+ struct dss2_overlay *oi;
+ u32 ix = comp->frm.mgr.ix;
+ if (ix < cdev->num_displays &&
+ cdev->displays[ix] &&
+ cdev->displays[ix]->manager)
+ ix = cdev->displays[ix]->manager->id;
+ else
+ ix = cdev->num_mgrs;
+ if (ix >= cdev->num_mgrs)
+ return -ENODEV;
+
+ mutex_lock(&mtx);
+
+ /* check if composition is active */
+ comp = validate(comp);
+ if (IS_ERR(comp)) {
+ r = PTR_ERR(comp);
+ goto done;
+ }
+
+ if (comp->magic != MAGIC_ACTIVE) {
+ r = -EACCES;
+ goto done;
+ }
+
+ if (ovl->cfg.ix >= cdev->num_ovls) {
+ r = -EINVAL;
+ goto done;
+ }
+
+ /* if overlay is already part of the composition */
+ if (mask & comp->ovl_mask) {
+ /* look up overlay */
+ list_for_each_entry(oi, &comp->ois, q)
+ if (oi->ovl.cfg.ix == ovl->cfg.ix)
+ break;
+ BUG_ON(&oi->q == &comp->ois);
+ } else {
+ /* check if ovl is free to use */
+ r = -EBUSY;
+ if (list_empty(&free_ois))
+ goto done;
+
+ /* not in any other displays queue */
+ if (mask & ~mgrq[ix].ovl_qmask) {
+ for (i = 0; i < cdev->num_mgrs; i++) {
+
+ if (i == ix)
+ continue;
+ if (mgrq[i].ovl_qmask & mask)
+ goto done;
+ }
+ }
+
+ /* and disabled (unless forced) if on another manager */
+ o = cdev->ovls[ovl->cfg.ix];
+ if (o->info.enabled &&
+ (!o->manager || o->manager->id != ix))
+ goto done;
+
+ /* add overlay to composition & display */
+ comp->ovl_mask |= mask;
+ comp->frm.num_ovls++;
+ mgrq[ix].ovl_qmask |= mask;
+
+ oi = list_first_entry(&free_ois, typeof(*oi), q);
+ list_move(&oi->q, &comp->ois);
+ }
+
+ oi->ovl = *ovl;
+ r = 0;
+ done:
+ mutex_unlock(&mtx);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(dsscomp_set_ovl);
+
+/* get overlay info */
+int dsscomp_get_ovl(dsscomp_t comp, u32 ix, struct dss2_ovl_info *ovl)
+{
+ int r = -EFAULT;
+ struct dss2_overlay *oi;
+
+ if (comp && ovl) {
+ mutex_lock(&mtx);
+
+ /* check if composition is active */
+ comp = validate(comp);
+ if (IS_ERR(comp)) {
+ r = PTR_ERR(comp);
+ } else if (comp->magic != MAGIC_ACTIVE) {
+ r = -EACCES;
+ } else {
+ if (ix >= cdev->num_ovls) {
+ r = -EINVAL;
+ } else if (comp->ovl_mask & (1 << ix)) {
+ r = 0;
+ list_for_each_entry(oi, &comp->ois, q) {
+ if (oi->ovl.cfg.ix == ix) {
+ *ovl = oi->ovl;
+ break;
+ }
+ }
+ BUG_ON(&oi->q == &comp->ois);
+ } else {
+ /* :TODO: get past overlay info */
+ r = -ENOENT;
+ }
+ }
+
+ mutex_unlock(&mtx);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(dsscomp_get_ovl);
+
+/* set manager info */
+int dsscomp_set_mgr(dsscomp_t comp, struct dss2_mgr_info *mgr)
+{
+ int r = -EFAULT;
+
+ if (comp && mgr) {
+ mutex_lock(&mtx);
+
+ /* check if composition is active */
+ comp = validate(comp);
+ if (IS_ERR(comp)) {
+ r = PTR_ERR(comp);
+ goto done;
+ }
+
+ if (comp->magic != MAGIC_ACTIVE) {
+ r = -EACCES;
+ goto done;
+ }
+
+ /* set display index in manager info */
+ mgr->ix = comp->frm.mgr.ix;
+ comp->frm.mgr = *mgr;
+ r = 0;
+ done:
+ mutex_unlock(&mtx);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(dsscomp_set_mgr);
+
+/* get manager info */
+int dsscomp_get_mgr(dsscomp_t comp, struct dss2_mgr_info *mgr)
+{
+ int r = -EFAULT;
+
+ if (comp && mgr) {
+ mutex_lock(&mtx);
+
+ /* check if composition is active */
+ comp = validate(comp);
+ if (IS_ERR(comp)) {
+ r = PTR_ERR(comp);
+ } else if (comp->magic != MAGIC_ACTIVE) {
+ r = -EACCES;
+ } else {
+ r = 0;
+ *mgr = comp->frm.mgr;
+ }
+
+ mutex_unlock(&mtx);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(dsscomp_get_mgr);
+
+/* get manager info */
+int dsscomp_setup(dsscomp_t comp, enum dsscomp_setup_mode mode,
+ struct dss2_rect_t win)
+{
+ int r = -EFAULT;
+
+ if (comp) {
+ mutex_lock(&mtx);
+
+ /* check if composition is active */
+ comp = validate(comp);
+ if (IS_ERR(comp)) {
+ r = PTR_ERR(comp);
+ } else if (comp->magic != MAGIC_ACTIVE) {
+ r = -EACCES;
+ } else {
+ r = 0;
+ comp->frm.mode = mode;
+ comp->frm.win = win;
+ }
+
+ mutex_unlock(&mtx);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(dsscomp_setup);
+
+/*
+ * ===========================================================================
+ * QUEUING COMMITTING OPERATIONS
+ * ===========================================================================
+ */
+
+static void refresh_masks(u32 ix)
+{
+ struct dsscomp_data *c;
+
+ mgrq[ix].ovl_qmask = mgrq[ix].ovl_mask;
+ list_for_each_entry(c, &mgrq[ix].q_ci, q) {
+ if (c->magic != MAGIC_PROGRAMMED)
+ mgrq[ix].ovl_qmask |= c->ovl_mask;
+ }
+
+ wake_up_interruptible_sync(&mgrq[ix].wq);
+}
+
+void dsscomp_drop(dsscomp_t c)
+{
+ struct dss2_overlay *o, *o2;
+
+ if (debug & DEBUG_COMPOSITIONS)
+ dev_info(DEV(cdev), "[%08x] released\n", c->frm.sync_id);
+
+ list_for_each_entry_safe(o, o2, &c->ois, q)
+ list_move(&o->q, &free_ois);
+ list_move(&c->q, &mgrq[c->ix].free_cis);
+ c->magic = 0;
+}
+EXPORT_SYMBOL(dsscomp_drop);
+
+static void dsscomp_mgr_callback(void *data, int id, int status)
+{
+ struct dsscomp_data *comp = data;
+ u32 ix;
+
+ /* do any other callbacks */
+ if (comp->cb.fn)
+ comp->cb.fn(comp->cb.data, id, status);
+
+ /* verify validity */
+ comp = validate(comp);
+ if (IS_ERR(comp))
+ return;
+
+ ix = comp->frm.mgr.ix;
+ if (ix >= cdev->num_displays ||
+ !cdev->displays[ix] ||
+ !cdev->displays[ix]->manager)
+ return;
+ ix = cdev->displays[ix]->manager->id;
+ if (ix >= cdev->num_mgrs)
+ return;
+
+ /* handle programming & release */
+ if (status == DSS_COMPLETION_PROGRAMMED) {
+ comp->magic = MAGIC_PROGRAMMED;
+ if (debug & DEBUG_PHASES)
+ dev_info(DEV(cdev),
+ "[%08x] programmed\n", comp->frm.sync_id);
+
+ /* update used overlay mask */
+ mgrq[ix].ovl_mask = comp->ovl_mask & ~comp->ovl_dmask;
+
+ /* if all overlays were disabled, the composition is complete */
+ if (comp->blank)
+ dsscomp_drop(comp);
+ refresh_masks(ix);
+ } else if ((status & DSS_COMPLETION_DISPLAYED) &&
+ comp->magic == MAGIC_PROGRAMMED) {
+ /* composition is 1st displayed */
+ comp->magic = MAGIC_DISPLAYED;
+ if (debug & DEBUG_PHASES)
+ dev_info(DEV(cdev),
+ "[%08x] displayed\n", comp->frm.sync_id);
+ wake_up_interruptible_sync(&mgrq[ix].wq);
+ } else if (status & DSS_COMPLETION_RELEASED) {
+ /* composition is no longer displayed */
+ dsscomp_drop(comp);
+ refresh_masks(ix);
+ }
+}
+
+static inline bool dssdev_manually_updated(struct omap_dss_device *dev)
+{
+ return dev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
+ dev->driver->get_update_mode(dev) != OMAP_DSS_UPDATE_AUTO;
+}
+
+/* get manager info */
+int dsscomp_apply(dsscomp_t comp)
+{
+ int i, r = -EFAULT;
+ u32 dmask, display_ix;
+ struct omap_dss_device *dssdev;
+ struct omap_dss_driver *drv;
+ struct omap_overlay_manager *mgr;
+ struct omap_overlay *ovl;
+ struct dsscomp_setup_mgr_data *d;
+ struct dsscomp_data *c, *c2;
+ struct dss2_overlay *o, *o2;
+ bool change = false;
+
+ mutex_lock(&mtx);
+
+ /* check if composition is active */
+ comp = validate(comp);
+ if (IS_ERR(comp)) {
+ r = PTR_ERR(comp);
+ goto done;
+ }
+
+ if (comp->magic != MAGIC_ACTIVE) {
+ r = -EACCES;
+ goto done;
+ }
+
+ /* check if the display is valid and used */
+ r = -ENODEV;
+ d = &comp->frm;
+ display_ix = d->mgr.ix;
+ if (display_ix >= cdev->num_displays)
+ goto done;
+ dssdev = cdev->displays[display_ix];
+ if (!dssdev)
+ goto done;
+
+ drv = dssdev->driver;
+ mgr = dssdev->manager;
+ if (!mgr || !drv || mgr->id >= cdev->num_mgrs)
+ goto done;
+
+ /* skip all unapplied prior compositions */
+ list_for_each_entry_safe(c, c2, &mgrq[mgr->id].q_ci, q) {
+ if (c == comp)
+ break;
+
+ /* keep applied compositions, as callback has been scheduled */
+ if (c->magic == MAGIC_ACTIVE) {
+ dsscomp_drop(c);
+ change = true;
+ }
+ }
+
+ dump_comp_info(cdev, d, "apply");
+
+ r = 0;
+ dmask = 0;
+ list_for_each_entry_safe(o, o2, &comp->ois, q) {
+ struct dss2_ovl_info *oi = &o->ovl;
+
+ /* keep track of disabled overlays */
+ if (!oi->cfg.enabled)
+ dmask |= 1 << oi->cfg.ix;
+
+ if (r)
+ goto done_ovl;
+
+ dump_ovl_info(cdev, oi);
+
+ if (oi->cfg.ix >= cdev->num_ovls) {
+ r = -EINVAL;
+ goto done_ovl;
+ }
+ ovl = cdev->ovls[oi->cfg.ix];
+
+ /* set overlays' manager & info */
+ if (ovl->info.enabled && ovl->manager != mgr) {
+ r = -EBUSY;
+ goto done_ovl;
+ }
+ if (ovl->manager != mgr) {
+ /*
+ * Ideally, we should call ovl->unset_manager(ovl),
+ * but it may block on go even though the disabling
+ * of the overlay already went through. So instead,
+ * we are just clearing the manager.
+ */
+ ovl->manager = NULL;
+ r = ovl->set_manager(ovl, mgr);
+ if (r)
+ goto done_ovl;
+ }
+
+ r = set_dss_ovl_info(oi);
+done_ovl:
+ /* we no longer have use for the overlay info structs */
+ list_move(&o->q, &free_ois);
+ }
+
+ /*
+ * set manager's info - this also sets the completion callback,
+ * so if it succeeds, we will use the callback to complete the
+ * composition. Otherwise, we can skip the composition now.
+ */
+ r = r ? : set_dss_mgr_info(&d->mgr);
+ if (r) {
+ dev_err(DEV(cdev), "[%08x] set failed %d\n", d->sync_id, r);
+ dsscomp_drop(comp);
+ change = true;
+ goto done;
+ } else {
+ /* override manager's callback to avoid eclipsed cb */
+ comp->blank = dmask == comp->ovl_mask;
+ comp->ovl_dmask = dmask;
+ comp->cb = mgr->info.cb;
+ mgr->info.cb.fn = dsscomp_mgr_callback;
+ mgr->info.cb.data = comp;
+
+ /*
+ * Check other overlays that may also use this display.
+ * NOTE: This is only needed in case someone changes
+ * overlays via sysfs.
+ */
+ for (i = 0; i < cdev->num_ovls; i++) {
+ u32 mask = 1 << i;
+ if ((~comp->ovl_mask & mask) &&
+ cdev->ovls[i]->info.enabled &&
+ cdev->ovls[i]->manager == mgr)
+ comp->ovl_mask |= mask;
+ }
+ }
+
+ /* apply changes and call update on manual panels */
+ comp->magic = MAGIC_APPLIED;
+
+ if (dssdev_manually_updated(dssdev)) {
+ if (!d->win.w && !d->win.x)
+ d->win.w = dssdev->panel.timings.x_res - d->win.x;
+ if (!d->win.h && !d->win.y)
+ d->win.h = dssdev->panel.timings.y_res - d->win.y;
+
+ /* sync to prevent frame loss */
+ r = drv->sync(dssdev) ? : mgr->apply(mgr);
+
+ if (!r && (d->mode & DSSCOMP_SETUP_MODE_DISPLAY)) {
+#if 0
+ /* schedule update if supported */
+ if (drv->sched_update)
+ r = drv->sched_update(dssdev, d->win.x,
+ d->win.y, d->win.w, d->win.h);
+ else if (drv->update)
+#else
+ if (drv->update)
+#endif
+ r = drv->update(dssdev, d->win.x,
+ d->win.y, d->win.w, d->win.h);
+ }
+ } else {
+ /* wait for sync to avoid tear */
+ r = mgr->wait_for_vsync(mgr) ? : mgr->apply(mgr);
+ }
+done:
+ if (change)
+ refresh_masks(display_ix);
+
+ mutex_unlock(&mtx);
+
+ return r;
+}
+EXPORT_SYMBOL(dsscomp_apply);
+
+/*
+ * ===========================================================================
+ * WAIT OPERATIONS
+ * ===========================================================================
+ */
+
+/* return true iff composition phase has passed */
+static bool is_wait_over(dsscomp_t comp, enum dsscomp_wait_phase phase)
+{
+ comp = validate(comp);
+ return IS_ERR(comp) ||
+ (phase == DSSCOMP_WAIT_PROGRAMMED &&
+ (comp->magic == MAGIC_PROGRAMMED ||
+ comp->magic == MAGIC_DISPLAYED)) ||
+ (phase == DSSCOMP_WAIT_DISPLAYED &&
+ comp->magic == MAGIC_DISPLAYED);
+}
+
+/* wait for programming or release of a composition */
+int dsscomp_wait(dsscomp_t comp, enum dsscomp_wait_phase phase, int timeout)
+{
+ u32 id;
+
+ mutex_lock(&mtx);
+
+ comp = validate(comp);
+ id = IS_ERR(comp) ? 0 : comp->frm.sync_id;
+ if (debug & DEBUG_WAITS)
+ dev_info(DEV(cdev), "wait %s on [%08x]\n",
+ phase == DSSCOMP_WAIT_DISPLAYED ? "display" :
+ phase == DSSCOMP_WAIT_PROGRAMMED ? "program" :
+ "release", id);
+
+ if (!IS_ERR(comp) && !is_wait_over(comp, phase)) {
+ u32 ix = comp->frm.mgr.ix;
+
+ mutex_unlock(&mtx);
+
+ /*
+ * we can check being active without mutex because we will
+ * also check it while holding the mutex before returning
+ */
+ timeout = wait_event_interruptible_timeout(mgrq[ix].wq,
+ is_wait_over(comp, phase), timeout);
+ if (debug & DEBUG_WAITS)
+ dev_info(DEV(cdev), "wait over [%08x]: %s %d\n", id,
+ timeout < 0 ? "signal" :
+ timeout > 0 ? "ok" : "timeout",
+ timeout);
+ if (timeout <= 0)
+ return timeout ? : -ETIME;
+
+ mutex_lock(&mtx);
+ }
+
+ mutex_unlock(&mtx);
+
+ return 0;
+}
+EXPORT_SYMBOL(dsscomp_wait);
+
+/*
+ * ===========================================================================
+ * EXIT
+ * ===========================================================================
+ */
+void dsscomp_queue_exit(void)
+{
+ struct dsscomp_data *c, *c2;
+ if (cis && ois && cdev) {
+ int i;
+ for (i = 0; i < cdev->num_displays; i++) {
+ list_for_each_entry_safe(c, c2, &mgrq[i].q_ci, q)
+ dsscomp_drop(c);
+ }
+ vfree(cis);
+ vfree(ois);
+ cis = NULL;
+ ois = NULL;
+ cdev = NULL;
+ }
+}
+EXPORT_SYMBOL(dsscomp_queue_exit);
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 0a3e400..51da678 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -358,7 +358,7 @@ static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
dssmode = OMAP_DSS_COLOR_RGB24P;
break;
case 32:
- dssmode = OMAP_DSS_COLOR_RGB24U;
+ dssmode = OMAP_DSS_COLOR_ARGB32;
break;
default:
return -EINVAL;
diff --git a/include/video/dsscomp.h b/include/video/dsscomp.h
new file mode 100644
index 0000000..0900f7a
--- /dev/null
+++ b/include/video/dsscomp.h
@@ -0,0 +1,557 @@
+#ifndef _LINUX_DSSCOMP_H
+#define _LINUX_DSSCOMP_H
+
+#ifdef __KERNEL__
+#include <video/omapdss.h>
+#else
+
+/* exporting enumerations from arch/arm/plat-omap/include/plat/display.h */
+enum omap_plane {
+ OMAP_DSS_GFX = 0,
+ OMAP_DSS_VIDEO1 = 1,
+ OMAP_DSS_VIDEO2 = 2,
+ OMAP_DSS_VIDEO3 = 3,
+ OMAP_DSS_WB = 4,
+};
+
+enum omap_channel {
+ OMAP_DSS_CHANNEL_LCD = 0,
+ OMAP_DSS_CHANNEL_DIGIT = 1,
+ OMAP_DSS_CHANNEL_LCD2 = 2,
+};
+
+enum omap_color_mode {
+ OMAP_DSS_COLOR_CLUT1 = 1 << 0, /* BITMAP 1 */
+ OMAP_DSS_COLOR_CLUT2 = 1 << 1, /* BITMAP 2 */
+ OMAP_DSS_COLOR_CLUT4 = 1 << 2, /* BITMAP 4 */
+ OMAP_DSS_COLOR_CLUT8 = 1 << 3, /* BITMAP 8 */
+
+ /* also referred to as RGB 12-BPP, 16-bit container */
+ OMAP_DSS_COLOR_RGB12U = 1 << 4, /* xRGB12-4444 */
+ OMAP_DSS_COLOR_ARGB16 = 1 << 5, /* ARGB16-4444 */
+ OMAP_DSS_COLOR_RGB16 = 1 << 6, /* RGB16-565 */
+
+ /* also referred to as RGB 24-BPP, 32-bit container */
+ OMAP_DSS_COLOR_RGB24U = 1 << 7, /* xRGB24-8888 */
+ OMAP_DSS_COLOR_RGB24P = 1 << 8, /* RGB24-888 */
+ OMAP_DSS_COLOR_YUV2 = 1 << 9, /* YUV2 4:2:2 co-sited */
+ OMAP_DSS_COLOR_UYVY = 1 << 10, /* UYVY 4:2:2 co-sited */
+ OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32-8888 */
+ OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32-8888 */
+
+ /* also referred to as RGBx 32 in TRM */
+ OMAP_DSS_COLOR_RGBX24 = 1 << 13, /* RGBx32-8888 */
+ OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32-8888 */
+ OMAP_DSS_COLOR_NV12 = 1 << 14, /* NV12 format: YUV 4:2:0 */
+
+ /* also referred to as RGBA12-4444 in TRM */
+ OMAP_DSS_COLOR_RGBA16 = 1 << 15, /* RGBA16-4444 */
+
+ OMAP_DSS_COLOR_RGBX12 = 1 << 16, /* RGBx16-4444 */
+ OMAP_DSS_COLOR_RGBX16 = 1 << 16, /* RGBx16-4444 */
+ OMAP_DSS_COLOR_ARGB16_1555 = 1 << 17, /* ARGB16-1555 */
+
+ /* also referred to as xRGB16-555 in TRM */
+ OMAP_DSS_COLOR_XRGB15 = 1 << 18, /* xRGB16-1555 */
+ OMAP_DSS_COLOR_XRGB16_1555 = 1 << 18, /* xRGB16-1555 */
+};
+
+enum omap_dss_trans_key_type {
+ OMAP_DSS_COLOR_KEY_GFX_DST = 0,
+ OMAP_DSS_COLOR_KEY_VID_SRC = 1,
+};
+
+enum omap_dss_display_state {
+ OMAP_DSS_DISPLAY_DISABLED = 0,
+ OMAP_DSS_DISPLAY_ACTIVE,
+ OMAP_DSS_DISPLAY_SUSPENDED,
+ OMAP_DSS_DISPLAY_TRANSITION,
+};
+
+struct omap_video_timings {
+ /* Unit: pixels */
+ __u16 x_res;
+ /* Unit: pixels */
+ __u16 y_res;
+ /* Unit: KHz */
+ __u32 pixel_clock;
+ /* Unit: pixel clocks */
+ __u16 hsw; /* Horizontal synchronization pulse width */
+ /* Unit: pixel clocks */
+ __u16 hfp; /* Horizontal front porch */
+ /* Unit: pixel clocks */
+ __u16 hbp; /* Horizontal back porch */
+ /* Unit: line clocks */
+ __u16 vsw; /* Vertical synchronization pulse width */
+ /* Unit: line clocks */
+ __u16 vfp; /* Vertical front porch */
+ /* Unit: line clocks */
+ __u16 vbp; /* Vertical back porch */
+};
+
+#endif
+
+/*
+ * Stereoscopic Panel types
+ * row, column, overunder, sidebyside options
+ * are with respect to native scan order
+ */
+enum s3d_disp_type {
+ S3D_DISP_NONE = 0,
+ S3D_DISP_FRAME_SEQ,
+ S3D_DISP_ROW_IL,
+ S3D_DISP_COL_IL,
+ S3D_DISP_PIX_IL,
+ S3D_DISP_CHECKB,
+ S3D_DISP_OVERUNDER,
+ S3D_DISP_SIDEBYSIDE,
+};
+
+/* Subsampling direction is based on native panel scan order.*/
+enum s3d_disp_sub_sampling {
+ S3D_DISP_SUB_SAMPLE_NONE = 0,
+ S3D_DISP_SUB_SAMPLE_V,
+ S3D_DISP_SUB_SAMPLE_H,
+};
+
+/*
+ * Indicates if display expects left view first followed by right or viceversa
+ * For row interlaved displays, defines first row view
+ * For column interleaved displays, defines first column view
+ * For checkerboard, defines first pixel view
+ * For overunder, defines top view
+ * For sidebyside, defines west view
+ */
+enum s3d_disp_order {
+ S3D_DISP_ORDER_L = 0,
+ S3D_DISP_ORDER_R = 1,
+};
+
+/*
+ * Indicates current view
+ * Used mainly for displays that need to trigger a sync signal
+ */
+enum s3d_disp_view {
+ S3D_DISP_VIEW_L = 0,
+ S3D_DISP_VIEW_R,
+};
+
+struct s3d_disp_info {
+ enum s3d_disp_type type;
+ enum s3d_disp_sub_sampling sub_samp;
+ enum s3d_disp_order order;
+ /*
+ * Gap between left and right views
+ * For over/under units are lines
+ * For sidebyside units are pixels
+ * For other types ignored
+ */
+ unsigned int gap;
+};
+
+enum omap_dss_ilace_mode {
+ OMAP_DSS_ILACE = (1 << 0), /* interlaced vs. progressive */
+ OMAP_DSS_ILACE_SEQ = (1 << 1), /* sequential vs interleaved */
+ OMAP_DSS_ILACE_SWAP = (1 << 2), /* swap fields, e.g. TB=>BT */
+
+ OMAP_DSS_ILACE_NONE = 0,
+ OMAP_DSS_ILACE_IL_TB = OMAP_DSS_ILACE,
+ OMAP_DSS_ILACE_IL_BT = OMAP_DSS_ILACE | OMAP_DSS_ILACE_SWAP,
+ OMAP_DSS_ILACE_SEQ_TB = OMAP_DSS_ILACE_IL_TB | OMAP_DSS_ILACE_SEQ,
+ OMAP_DSS_ILACE_SEQ_BT = OMAP_DSS_ILACE_IL_BT | OMAP_DSS_ILACE_SEQ,
+};
+
+/* YUV to RGB color conversion info */
+struct dss2_color_conv_info {
+ __s16 r_y, r_cr, r_cb;
+ __s16 g_y, g_cr, g_cb;
+ __s16 b_y, b_cr, b_cb;
+
+ /* Y is 16..235, UV is 16..240 if not fullrange. Otherwise 0..255 */
+ __u16 fullrange; /* bool */
+} __attribute__ ((aligned(4)));
+
+/* YUV VC1 range mapping info */
+struct dss2_vc1_range_map_info {
+ __u8 enable; /* bool */
+
+ __u8 range_y; /* 0..7 */
+ __u8 range_uv; /* 0..7 */
+} __attribute__ ((aligned(4)));
+
+/* standard rectangle */
+struct dss2_rect_t {
+ __s32 x; /* left */
+ __s32 y; /* top */
+ __u32 w; /* width */
+ __u32 h; /* height */
+} __attribute__ ((aligned(4)));
+
+/* decimation constraints */
+struct dss2_decim {
+ __u8 min_x;
+ __u8 max_x; /* 0 is same as 255 */
+ __u8 min_y;
+ __u8 max_y; /* 0 is same as 255 */
+} __attribute__ ((aligned(4)));
+
+/*
+ * A somewhat more user friendly interface to the DSS2. This is a
+ * direct interface to the DSS2 overlay and overlay_manager modules.
+ * User-space APIs are provided for HW-specific control of DSS in
+ * contrast with V4L2/FB that are more generic, but in this process
+ * omit HW-specific features.
+ *
+ * For now managers are specified by display index as opposed to manager
+ * type, so that display0 is always the default display (e.g. HDMI on
+ * panda, and LCD blaze.) For now you would need to query the displays
+ * or use sysfs to find a specific display.
+ *
+ * Userspace operations are as follows:
+ *
+ * 1) check if DSS supports an overlay configuration, use DSSCOMP_CHECK_OVL
+ * ioctl with the manager, overlay, and setup-mode information filled out.
+ * All fields should be filled out as it may influence whether DSS can
+ * display/render the overlay.
+ *
+ * If proper address information is not available, it may be possible to
+ * use a type-of-address enumeration instead for luma/rgb and chroma (if
+ * applicable) frames.
+ *
+ * Do this for each overlay before attempting to configure DSS.
+ *
+ * 2) configure DSS pipelines for display/manager using DSSCOMP_SETUP_MANAGER
+ * ioctl. You can delay applying the settings until an dss2_manager_apply()
+ * with the same sync_id is called if the APPLY bit of setup mode is not
+ * set. However the CAPTURE/DISPLAY bits of the setup mode settings will
+ * determine if at this time a capture will take place (in case of capture
+ * only mode). You may also set up additional pipelines with
+ * dss2_overlay_setup() before this.
+ *
+ * 3) On OMAP4/5 you can use the DSS WB pipeline to copy (and convert) a buffer
+ * using DSS. Use the DSSCOMP_WB_COPY ioctl for this. This is a blocking
+ * call, and it may possibly fail if an ongoing WB capture mode has been
+ * schedule (which is outside of the current scope of the DSS2 interface.)
+ *
+ */
+
+/*
+ * DSS2 overlay information. This structure contains all information
+ * needed to set up the overlay for a particular buffer to be displayed
+ * at a particular orientation.
+ *
+ * The following information is deemed to be set globally, so it is not
+ * included:
+ * - whether to enable zorder (always enabled)
+ * - whether to replicate/truncate color fields (it is decided per the
+ * whole manager/overlay settings, and is enabled unless overlay is
+ * directed to WB.)
+ *
+ * There is also no support for CLUT formats
+ *
+ * Requirements:
+ *
+ * 1) 0 <= crop.x <= crop.x + crop.w <= width
+ * 2) 0 <= crop.y <= crop.y + crop.h <= height
+ * 3) win.x <= win.x + win.w and win.w >= 0
+ * 4) win.y <= win.y + win.h and win.h >= 0
+ *
+ * 5) color_mode is supported by overlay
+ * 6) requested scaling is supported by overlay and functional clocks
+ *
+ * Notes:
+ *
+ * 1) Any portions of X:[pos_x, pos_x + out_width] and
+ * Y:[pos_y, pos_y + out_height] outside of the screen
+ * X:[0, screen.width], Y:[0, screen.height] will be cropped
+ * automatically without changing the scaling ratio.
+ *
+ * 2) Crop region will be adjusted to the pixel granularity:
+ * (2-by-1) for YUV422, (2-by-2) for YUV420. This will
+ * not modify the output region. Crop region is for the
+ * original (unrotated) buffer, so it does not change with
+ * rotation.
+ *
+ * 3) Rotation will not modify the output region, specifically
+ * its height and width. Also the coordinate system of the
+ * display is always (0,0) = top left.
+ *
+ * 4) cconv and vc1 only needs to be filled for YUV color modes.
+ *
+ * 5) vc1.range_y and vc1.range_uv only needs to be filled if
+ * vc1.enable is true.
+ */
+struct dss2_ovl_cfg {
+ __u16 width; /* buffer width */
+ __u16 height; /* buffer height */
+ __u32 stride; /* buffer stride */
+
+ enum omap_color_mode color_mode;
+ __u8 pre_mult_alpha; /* bool */
+ __u8 global_alpha; /* 0..255 */
+ __u8 rotation; /* 0..3 (*90 degrees clockwise) */
+ __u8 mirror; /* left-to-right: mirroring is applied after rotation */
+
+ enum omap_dss_ilace_mode ilace; /* interlace mode */
+
+ struct dss2_rect_t win; /* output window - on display */
+ struct dss2_rect_t crop; /* crop window - in source buffer */
+
+ struct dss2_decim decim; /* predecimation limits */
+
+ struct dss2_color_conv_info cconv;
+ struct dss2_vc1_range_map_info vc1;
+
+ __u8 ix; /* ovl index same as sysfs/overlay# */
+ __u8 zorder; /* 0..3 */
+ __u8 enabled; /* bool */
+ __u8 zonly; /* only set zorder and enabled bit */
+} __attribute__ ((aligned(4)));
+
+enum omapdss_buffer_type {
+ OMAP_DSS_BUFTYPE_SDMA,
+ OMAP_DSS_BUFTYPE_TILER_8BIT,
+ OMAP_DSS_BUFTYPE_TILER_16BIT,
+ OMAP_DSS_BUFTYPE_TILER_32BIT,
+ OMAP_DSS_BUFTYPE_TILER_PAGE,
+};
+
+struct dss2_ovl_info {
+ struct dss2_ovl_cfg cfg;
+
+ union {
+ /* user-space interfaces */
+ struct {
+ void *address; /* main buffer address */
+
+ /*
+ * For DSSCOMP_CHECK_OVL we allow specifying just the
+ * type of each buffer. This is used if we need to
+ * check whether DSS will be able to display a buffer
+ * if using a particular memory type before spending
+ * time to map/copy the buffer into that type of
+ * memory. Default value of 0 uses the address to
+ * determine the type.
+ */
+ __u16 ba_type;
+ __u16 uv_type;
+ };
+
+ /* kernel-space interfaces */
+ struct {
+ __u32 ba; /* base address */
+ __u32 uv; /* uv address */
+ };
+ };
+};
+
+/*
+ * DSS2 manager information.
+ *
+ * The following information is deemed to be set globally, so it is not
+ * included:
+ * - gamma correction
+ * - color phase correction
+ *
+ * whether to enable zorder (always enabled)
+ * whether to replicate/truncate color fields (it is decided per the
+ * whole manager/overlay settings, and is enabled unless overlay is
+ * directed to WB.)
+ * Notes:
+ *
+ * 1) trans_key_type and trans_enabled only need to be filled if
+ * trans_enabled is true, and alpha_blending is false.
+ */
+struct dss2_mgr_info {
+ __u32 ix; /* display index same as sysfs/display# */
+
+ __u32 default_color;
+
+ enum omap_dss_trans_key_type trans_key_type;
+ __u32 trans_key;
+ __u8 trans_enabled; /* bool */
+
+ __u8 interlaced; /* bool */
+ __u8 alpha_blending; /* bool - overrides trans_enabled */
+} __attribute__ ((aligned(4)));
+
+/*
+ * ioctl: DSSCOMP_SETUP_MGR, struct dsscomp_setup_mgr_data
+ *
+ * 1. sets manager of each ovl in composition to the display
+ * 2. calls set_dss_ovl_info() for each ovl to set up the
+ * overlay staging structures (this is a wrapper around ovl->set_info())
+ * 3. calls set_dss_mgr_info() for mgr to set up the manager
+ * staging structures (this is a wrapper around mgr->set_info())
+ * 4. if update is true:
+ * calls manager->apply()
+ * calls driver->update() in a non-blocking fashion
+ * this will program the DSS synchronously
+ *
+ * Notes:
+ *
+ * 1) x, y, w, h only needs to be set if update is true.
+ *
+ * All non-specified pipelines that currently are on the same display
+ * will remain the same as on the previous frame. You may want to
+ * disable unused pipelines to avoid surprises.
+ *
+ * If get_sync_obj is false, it returns 0 on success, <0 error value
+ * on failure.
+ *
+ * If get_sync_obj is true, it returns fd on success, or a negative value
+ * on failure. You can use the fd to wait on (using poll()). It gets
+ * ready when frame has been eclipsed by another frame.
+ *
+ * Note: frames do not get eclipsed when the display turns off. Queue a
+ * blank frame to eclipse old frames. Blank frames get eclipsed when
+ * programmed into DSS.
+ *
+ * All overlays to be used on the frame must be listed. There is no way
+ * to add another overlay to a defined frame.
+ */
+enum dsscomp_setup_mode {
+ DSSCOMP_SETUP_MODE_APPLY = (1 << 0), /* applies changes to cache */
+ DSSCOMP_SETUP_MODE_DISPLAY = (1 << 1), /* calls display update */
+ DSSCOMP_SETUP_MODE_CAPTURE = (1 << 2), /* capture to WB */
+
+ /* just apply changes for next vsync/update */
+ DSSCOMP_SETUP_APPLY = DSSCOMP_SETUP_MODE_APPLY,
+ /* trigger an update (wait for vsync) */
+ DSSCOMP_SETUP_DISPLAY =
+ DSSCOMP_SETUP_MODE_APPLY | DSSCOMP_SETUP_MODE_DISPLAY,
+ /* capture to WB - WB must be configured */
+ DSSCOMP_SETUP_CAPTURE =
+ DSSCOMP_SETUP_MODE_APPLY | DSSCOMP_SETUP_MODE_CAPTURE,
+ /* display and capture to WB - WB must be configured */
+ DSSCOMP_SETUP_DISPLAY_CAPTURE =
+ DSSCOMP_SETUP_DISPLAY | DSSCOMP_SETUP_CAPTURE,
+};
+
+struct dsscomp_setup_mgr_data {
+ __u32 sync_id; /* synchronization ID */
+
+ struct dss2_rect_t win; /* update region, set w/h to 0 for fullscreen */
+ enum dsscomp_setup_mode mode;
+ __u16 num_ovls; /* # of overlays used in the composition */
+ __u16 get_sync_obj; /* ioctl should return a sync object */
+
+ struct dss2_mgr_info mgr;
+ struct dss2_ovl_info ovls[0]; /* up to 5 overlays to set up */
+};
+
+/*
+ * ioctl: DSSCOMP_CHECK_OVL, struct dsscomp_check_ovl_data
+ *
+ * DISPLAY and/or CAPTURE bits must be filled for the mode field
+ * correctly to be able to decide correctly if DSS can properly
+ * render the overlay.
+ *
+ * ovl.ix is ignored.
+ *
+ * Returns a positive bitmask regarding which overlay of DSS can
+ * render the overlay as it is configured for the display/display's
+ * manager. NOTE: that overlays that are assigned to other displays
+ * may be returned. If there is an invalid configuration (negative
+ * sizes, etc.), a negative error value is returned.
+ *
+ * ovl->decim's min values will be modified to the smallest decimation that
+ * DSS can use to support the overlay configuration.
+ *
+ * Assumptions:
+ * - zorder will be distinct from other pipelines on that manager
+ * - overlay will be enabled and routed to the display specified
+ */
+struct dsscomp_check_ovl_data {
+ enum dsscomp_setup_mode mode;
+ struct dss2_mgr_info mgr;
+ struct dss2_ovl_info ovl;
+};
+
+/*
+ * ioctl: DSSCOMP_WB_COPY, struct dsscomp_wb_copy_data
+ *
+ * Requirements:
+ * wb.ix must be OMAP_DSS_WB.
+ *
+ * Returns 0 on success (copy is completed), non-0 on failure.
+ */
+struct dsscomp_wb_copy_data {
+ struct dss2_ovl_info ovl, wb;
+};
+
+/*
+ * ioctl: DSSCOMP_QUERY_DISPLAY, struct dsscomp_display_info
+ *
+ * Gets informations about the display. Fill in ix before calling
+ * ioctl, and rest of the fields are filled in by ioctl.
+ *
+ * Returns: 0 on success, non-0 error value on failure.
+ */
+struct dsscomp_display_info {
+ __u32 ix; /* display index (sysfs/display#) */
+ __u32 overlays_available; /* bitmask of available overlays */
+ __u32 overlays_owned; /* bitmask of owned overlays */
+ enum omap_channel channel;
+ enum omap_dss_display_state state;
+ __u8 enabled; /* bool: resume-state if suspended */
+ struct omap_video_timings timings;
+ struct s3d_disp_info s3d_info; /* any S3D specific information */
+ struct dss2_mgr_info mgr; /* manager information */
+};
+
+/*
+ * ioctl: DSSCOMP_WAIT, struct dsscomp_wait_data
+ *
+ * Use this ioctl to wait for one of the following events:
+ *
+ * A) the moment a composition is programmed into DSS
+ * B) the moment a composition is first displayed (or captured)
+ * C) the moment when a composition is no longer queued or displayed on a
+ * display (it is released). (A composition is assumed to be superceded
+ * when another composition has been programmed into DSS, even if that
+ * subsequent composition does not update/specify all overlays used by
+ * the prior composition; moreover, even if it uses the same buffers.)
+ *
+ * Non-existing sync IDs are assumed to have been programmed, displayed and
+ * released. (They are assumed to be no-longer existing sync IDs.)
+ *
+ * Set timeout to desired timeout value in microseconds. Set timeout
+ * to 0 if you want to return a sync object (file descriptor) instead of
+ * waiting for the event. You can then poll on this sync object to
+ * wait for the specified event.
+ *
+ * Returns: >=0 on success, <0 error value on failure (e.g. -ETIME).
+ */
+enum dsscomp_wait_phase {
+ DSSCOMP_WAIT_RELEASED,
+ DSSCOMP_WAIT_PROGRAMMED,
+ DSSCOMP_WAIT_DISPLAYED,
+};
+
+struct dsscomp_wait_data {
+ __u32 ix; /* display index */
+ __u32 sync_id;
+ __u32 timeout_us; /* timeout in microseconds */
+ enum dsscomp_wait_phase phase; /* phase to wait for */
+};
+
+/*
+ * ioctl: DSSCOMP_LAST_RELEASED, struct dsscomp_wait_data
+ *
+ * Non-blocking sync.
+ *
+ * Fills in the sync_id of the last released frame on a
+ * display specified by ix.
+ *
+ * Returns 0 on success, non-0 error value on failure.
+ */
+
+/* IOCTLS */
+#define DSSCOMP_SETUP_MGR _IOW('O', 128, struct dsscomp_setup_mgr_data)
+#define DSSCOMP_CHECK_OVL _IOWR('O', 129, struct dsscomp_check_ovl_data)
+#define DSSCOMP_WB_COPY _IOW('O', 130, struct dsscomp_wb_copy_data)
+#define DSSCOMP_QUERY_DISPLAY _IOWR('O', 131, struct dsscomp_display_info)
+#define DSSCOMP_WAIT _IOW('O', 132, struct dsscomp_wait_data)
+
+#endif
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 25fc1f3..565a49b 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -41,6 +41,8 @@
#define DISPC_IRQ_WAKEUP (1 << 16)
#define DISPC_IRQ_SYNC_LOST2 (1 << 17)
#define DISPC_IRQ_VSYNC2 (1 << 18)
+#define DISPC_IRQ_VID3_END_WIN (1 << 19)
+#define DISPC_IRQ_VID3_FIFO_UNDERFLOW (1 << 20)
#define DISPC_IRQ_ACBIAS_COUNT_STAT2 (1 << 21)
#define DISPC_IRQ_FRAMEDONE2 (1 << 22)
@@ -60,7 +62,8 @@ enum omap_display_type {
enum omap_plane {
OMAP_DSS_GFX = 0,
OMAP_DSS_VIDEO1 = 1,
- OMAP_DSS_VIDEO2 = 2
+ OMAP_DSS_VIDEO2 = 2,
+ OMAP_DSS_VIDEO3 = 3,
};
enum omap_channel {
@@ -166,6 +169,7 @@ enum omap_dss_overlay_managers {
enum omap_dss_rotation_type {
OMAP_DSS_ROT_DMA = 0,
OMAP_DSS_ROT_VRFB = 1,
+ OMAP_DSS_ROT_TILER = 2,
};
/* clockwise rotation angle */
@@ -196,6 +200,13 @@ enum omap_dss_clk_source {
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */
};
+enum omap_overlay_zorder {
+ OMAP_DSS_OVL_ZORDER_0 = 0,
+ OMAP_DSS_OVL_ZORDER_1 = 1,
+ OMAP_DSS_OVL_ZORDER_2 = 2,
+ OMAP_DSS_OVL_ZORDER_3 = 3,
+};
+
/* RFBI */
struct rfbi_timings {
@@ -308,6 +319,24 @@ extern const struct omap_video_timings omap_dss_pal_timings;
extern const struct omap_video_timings omap_dss_ntsc_timings;
#endif
+enum omapdss_completion_status {
+ DSS_COMPLETION_PROGRAMMED = 0,
+ DSS_COMPLETION_DISPLAYED = 4,
+ DSS_COMPLETION_CHANGED_SET,
+ DSS_COMPLETION_CHANGED_CACHE,
+ DSS_COMPLETION_RELEASED = 8,
+ DSS_COMPLETION_ECLIPSED_SET,
+ DSS_COMPLETION_ECLIPSED_CACHE,
+ DSS_COMPLETION_ECLIPSED_SHADOW,
+ DSS_COMPLETION_TORN,
+};
+
+struct omapdss_ovl_cb {
+ /* optional callback method */
+ void (*fn)(void *data, int id, int status);
+ void *data;
+};
+
struct omap_overlay_info {
bool enabled;
@@ -328,6 +357,10 @@ struct omap_overlay_info {
u16 out_height; /* if 0, out_height == height */
u8 global_alpha;
u8 pre_mult_alpha;
+ enum omap_overlay_zorder zorder;
+ u16 min_x_decim, max_x_decim, min_y_decim, max_y_decim;
+
+ struct omapdss_ovl_cb cb;
};
struct omap_overlay {
@@ -367,6 +400,8 @@ struct omap_overlay_manager_info {
bool trans_enabled;
bool alpha_enabled;
+
+ struct omapdss_ovl_cb cb;
};
struct omap_overlay_manager {