diff options
author | Rebecca Schultz Zavin <rebecca@android.com> | 2011-07-11 16:59:22 -0700 |
---|---|---|
committer | Rebecca Schultz Zavin <rebecca@android.com> | 2011-07-11 16:59:33 -0700 |
commit | 6fa70b73010a837fc70f34a9fc747a8692f83a1a (patch) | |
tree | 3acc95649104c509a29d7b5580080dd3e9932795 | |
parent | b6ffdd2809ca0b0727f4c89340a83372eaf88fb6 (diff) | |
parent | 2de1312397d169b871473f3da1db38b5cdd3d784 (diff) | |
download | kernel_samsung_tuna-6fa70b73010a837fc70f34a9fc747a8692f83a1a.zip kernel_samsung_tuna-6fa70b73010a837fc70f34a9fc747a8692f83a1a.tar.gz kernel_samsung_tuna-6fa70b73010a837fc70f34a9fc747a8692f83a1a.tar.bz2 |
Merge remote branch 'omap/linux-omap-dss-3.0' into linux-omap-3.0
Change-Id: Ida1a3053c2e75c4bfa554319bade0e78011b5e4c
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 932 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc.h | 57 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 19 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 24 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.h | 5 | ||||
-rw-r--r-- | drivers/video/omap2/dss/manager.c | 259 | ||||
-rw-r--r-- | drivers/video/omap2/dss/overlay.c | 157 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 2 | ||||
-rw-r--r-- | include/video/omapdss.h | 37 |
9 files changed, 1067 insertions, 425 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 2458248..9681717 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)) @@ -3348,6 +3447,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; @@ -3576,7 +3693,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/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/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 { |