DSS2: Swap field 0 and field 1 registers
[pandora-kernel.git] / drivers / video / omap2 / dss / dispc.c
index ae7be3d..9bab6cf 100644 (file)
@@ -994,7 +994,10 @@ static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
+       if (cpu_is_omap24xx())
+               val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
+       else
+               val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
        dispc_write_reg(fir_reg[plane-1], val);
 }
 
@@ -1026,12 +1029,12 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
 static void _dispc_set_scaling(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
-               bool ilace, bool five_taps)
+               bool ilace, bool five_taps,
+               bool fieldmode)
 {
        int fir_hinc;
        int fir_vinc;
        int hscaleup, vscaleup;
-       int fieldmode = 0;
        int accu0 = 0;
        int accu1 = 0;
        u32 l;
@@ -1069,17 +1072,16 @@ static void _dispc_set_scaling(enum omap_plane plane,
 
        dispc_write_reg(dispc_reg_att[plane], l);
 
-       if (ilace) {
-               if (fieldmode) {
-                       accu0 = fir_vinc / 2;
-                       accu1 = 0;
-               } else {
-                       accu0 = 0;
-                       accu1 = fir_vinc / 2;
-                       if (accu1 >= 1024/2) {
-                               accu0 = 1024/2;
-                               accu1 -= accu0;
-                       }
+       /*
+        * field 0 = even field = bottom field
+        * field 1 = odd field = top field
+        */
+       if (ilace && !fieldmode) {
+               accu1 = 0;
+               accu0 = fir_vinc / 2;
+               if (accu0 >= 1024/2) {
+                       accu1 = 1024/2;
+                       accu0 -= accu1;
                }
        }
 
@@ -1106,7 +1108,7 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                        case 0: vidrot = 0; break;
                        case 1: vidrot = 1; break;
                        case 2: vidrot = 2; break;
-                       case 3: vidrot = 1; break;
+                       case 3: vidrot = 3; break;
                        }
                }
 
@@ -1134,7 +1136,92 @@ static s32 pixinc(int pixels, u8 ps)
                BUG();
 }
 
-static void calc_rotation_offset(u8 rotation, bool mirror,
+static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
+               u16 screen_width,
+               u16 width, u16 height,
+               enum omap_color_mode color_mode, bool fieldmode,
+               unsigned *offset0, unsigned *offset1,
+               s32 *row_inc, s32 *pix_inc)
+{
+       u8 ps;
+
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_RGB16:
+       case OMAP_DSS_COLOR_ARGB16:
+               ps = 2;
+               break;
+
+       case OMAP_DSS_COLOR_RGB24P:
+               ps = 3;
+               break;
+
+       case OMAP_DSS_COLOR_RGB24U:
+       case OMAP_DSS_COLOR_ARGB32:
+       case OMAP_DSS_COLOR_RGBA32:
+       case OMAP_DSS_COLOR_RGBX32:
+       case OMAP_DSS_COLOR_YUV2:
+       case OMAP_DSS_COLOR_UYVY:
+               ps = 4;
+               break;
+
+       default:
+               BUG();
+               return;
+       }
+
+       DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
+                       width, height);
+       switch (rotation + mirror * 4) {
+       case 0:
+       case 2:
+               /*
+                * If the pixel format is YUV or UYVY divide the width
+                * of the image by 2 for 0 and 180 degree rotation.
+                */
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       width = width >> 1;
+       case 1:
+       case 3:
+               *offset0 = 0;
+               if (fieldmode)
+                       *offset1 = screen_width * ps;
+               else
+                       *offset1 = 0;
+
+               *row_inc = pixinc(1 + (screen_width - width) +
+                               (fieldmode ? screen_width : 0),
+                               ps);
+               *pix_inc = pixinc(1, ps);
+               break;
+
+       case 4:
+       case 6:
+               /* If the pixel format is YUV or UYVY divide the width
+                * of the image by 2  for 0 degree and 180 degree
+                */
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       width = width >> 1;
+       case 5:
+       case 7:
+               *offset0 = 0;
+               if (fieldmode)
+                       *offset1 = screen_width * ps;
+               else
+                       *offset1 = 0;
+               *row_inc = pixinc(1 - (screen_width + width) -
+                               (fieldmode ? screen_width : 0),
+                               ps);
+               *pix_inc = pixinc(1, ps);
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                u16 screen_width,
                u16 width, u16 height,
                enum omap_color_mode color_mode, bool fieldmode,
@@ -1183,34 +1270,38 @@ static void calc_rotation_offset(u8 rotation, bool mirror,
                fbh = width;
        }
 
+       /*
+        * field 0 = even field = bottom field
+        * field 1 = odd field = top field
+        */
        switch (rotation + mirror * 4) {
        case 0:
-               *offset0 = 0;
+               *offset1 = 0;
                if (fieldmode)
-                       *offset1 = screen_width * ps;
+                       *offset0 = screen_width * ps;
                else
-                       *offset1 = 0;
+                       *offset0 = 0;
                *row_inc = pixinc(1 + (screen_width - fbw) +
                                (fieldmode ? screen_width : 0),
                                ps);
                *pix_inc = pixinc(1, ps);
                break;
        case 1:
-               *offset0 = screen_width * (fbh - 1) * ps;
+               *offset1 = screen_width * (fbh - 1) * ps;
                if (fieldmode)
-                       *offset1 = *offset0 + ps;
+                       *offset0 = *offset1 + ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
                                (fieldmode ? 1 : 0), ps);
                *pix_inc = pixinc(-screen_width, ps);
                break;
        case 2:
-               *offset0 = (screen_width * (fbh - 1) + fbw - 1) * ps;
+               *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
                if (fieldmode)
-                       *offset1 = *offset0 - screen_width * ps;
+                       *offset0 = *offset1 - screen_width * ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(-1 -
                                (screen_width - fbw) -
                                (fieldmode ? screen_width : 0),
@@ -1218,11 +1309,11 @@ static void calc_rotation_offset(u8 rotation, bool mirror,
                *pix_inc = pixinc(-1, ps);
                break;
        case 3:
-               *offset0 = (fbw - 1) * ps;
+               *offset1 = (fbw - 1) * ps;
                if (fieldmode)
-                       *offset1 = *offset0 - ps;
+                       *offset0 = *offset1 - ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
                                (fieldmode ? 1 : 0), ps);
                *pix_inc = pixinc(screen_width, ps);
@@ -1230,11 +1321,11 @@ static void calc_rotation_offset(u8 rotation, bool mirror,
 
        /* mirroring */
        case 0 + 4:
-               *offset0 = (fbw - 1) * ps;
+               *offset1 = (fbw - 1) * ps;
                if (fieldmode)
-                       *offset1 = *offset0 + screen_width * ps;
+                       *offset0 = *offset1 + screen_width * ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(screen_width * 2 - 1 +
                                (fieldmode ? screen_width : 0),
                                ps);
@@ -1242,11 +1333,11 @@ static void calc_rotation_offset(u8 rotation, bool mirror,
                break;
 
        case 1 + 4:
-               *offset0 = 0;
+               *offset1 = 0;
                if (fieldmode)
-                       *offset1 = *offset0 + screen_width * ps;
+                       *offset0 = *offset1 + screen_width * ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
                                (fieldmode ? 1 : 0),
                                ps);
@@ -1254,11 +1345,11 @@ static void calc_rotation_offset(u8 rotation, bool mirror,
                break;
 
        case 2 + 4:
-               *offset0 = screen_width * (fbh - 1) * ps;
+               *offset1 = screen_width * (fbh - 1) * ps;
                if (fieldmode)
-                       *offset1 = *offset0 + screen_width * ps;
+                       *offset0 = *offset1 + screen_width * ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(1 - screen_width * 2 -
                                (fieldmode ? screen_width : 0),
                                ps);
@@ -1266,11 +1357,11 @@ static void calc_rotation_offset(u8 rotation, bool mirror,
                break;
 
        case 3 + 4:
-               *offset0 = (screen_width * (fbh - 1) + fbw - 1) * ps;
+               *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
                if (fieldmode)
-                       *offset1 = *offset0 + screen_width * ps;
+                       *offset0 = *offset1 + screen_width * ps;
                else
-                       *offset1 = *offset0;
+                       *offset0 = *offset1;
                *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
                                (fieldmode ? 1 : 0),
                                ps);
@@ -1317,15 +1408,10 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height,
 }
 
 static unsigned long calc_fclk(u16 width, u16 height,
-               u16 out_width, u16 out_height,
-               enum omap_color_mode color_mode, bool five_taps)
+               u16 out_width, u16 out_height)
 {
        unsigned int hf, vf;
 
-       if (five_taps)
-               return calc_fclk_five_taps(width, height,
-                               out_width, out_height, color_mode);
-
        /*
         * FIXME how to determine the 'A' factor
         * for the no downscaling case ?
@@ -1357,6 +1443,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
                u16 out_width, u16 out_height,
                enum omap_color_mode color_mode,
                bool ilace,
+               enum omap_dss_rotation_type rotation_type,
                u8 rotation, int mirror)
 {
        const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
@@ -1371,7 +1458,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
        if (paddr == 0)
                return -EINVAL;
 
-       if (ilace && height >= out_height)
+       if (ilace && height == out_height)
                fieldmode = 1;
 
        if (ilace) {
@@ -1405,7 +1492,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
        } else {
                /* video plane */
 
-               unsigned long fclk;
+               unsigned long fclk = 0;
 
                if (out_width < width / maxdownscale ||
                   out_width > width * 8)
@@ -1441,20 +1528,22 @@ static int _dispc_setup_plane(enum omap_plane plane,
                /* Must use 5-tap filter? */
                five_taps = height > out_height * 2;
 
-               /* Try to use 5-tap filter whenever possible. */
-               if (cpu_is_omap34xx() && !five_taps &&
-                   height > out_height && width <= 1024) {
-                       fclk = calc_fclk_five_taps(width, height,
-                                       out_width, out_height, color_mode);
-                       if (fclk <= dispc_fclk_rate())
+               if (!five_taps) {
+                       fclk = calc_fclk(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))
                        return -EINVAL;
 
-               fclk = calc_fclk(width, height, out_width, out_height,
-                               color_mode, five_taps);
+               if (five_taps)
+                       fclk = calc_fclk_five_taps(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());
@@ -1463,10 +1552,16 @@ static int _dispc_setup_plane(enum omap_plane plane,
                        return -EINVAL;
        }
 
-       calc_rotation_offset(rotation, mirror,
-                       screen_width, width, frame_height, color_mode,
-                       fieldmode,
-                       &offset0, &offset1, &row_inc, &pix_inc);
+       if (rotation_type == OMAP_DSS_ROT_DMA)
+               calc_dma_rotation_offset(rotation, mirror,
+                               screen_width, width, frame_height, color_mode,
+                               fieldmode,
+                               &offset0, &offset1, &row_inc, &pix_inc);
+       else
+               calc_vrfb_rotation_offset(rotation, mirror,
+                               screen_width, width, frame_height, color_mode,
+                               fieldmode,
+                               &offset0, &offset1, &row_inc, &pix_inc);
 
        DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
                        offset0, offset1, row_inc, pix_inc);
@@ -1490,7 +1585,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
        if (plane != OMAP_DSS_GFX) {
                _dispc_set_scaling(plane, width, height,
                                   out_width, out_height,
-                                  ilace, five_taps);
+                                  ilace, five_taps, fieldmode);
                _dispc_set_vid_size(plane, out_width, out_height);
                _dispc_set_vid_color_conv(plane, cconv);
        }
@@ -1734,9 +1829,9 @@ void dispc_get_trans_key(enum omap_channel ch,
        enable_clocks(1);
        if (type) {
                if (ch == OMAP_DSS_CHANNEL_LCD)
-                       *type = REG_GET(DISPC_CONFIG, 11, 11) >> 11;
+                       *type = REG_GET(DISPC_CONFIG, 11, 11);
                else if (ch == OMAP_DSS_CHANNEL_DIGIT)
-                       *type = REG_GET(DISPC_CONFIG, 13, 13) >> 13;
+                       *type = REG_GET(DISPC_CONFIG, 13, 13);
                else
                        BUG();
        }
@@ -1755,6 +1850,32 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
                REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
        enable_clocks(0);
 }
+void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
+{
+       enable_clocks(1);
+       if (ch == OMAP_DSS_CHANNEL_LCD)
+               REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
+       else /* OMAP_DSS_CHANNEL_DIGIT */
+               REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
+       enable_clocks(0);
+}
+bool dispc_alpha_blending_enabled(enum omap_channel ch)
+{
+       bool enabled;
+
+       enable_clocks(1);
+       if (ch == OMAP_DSS_CHANNEL_LCD)
+               enabled = REG_GET(DISPC_CONFIG, 18, 18);
+       else if (ch == OMAP_DSS_CHANNEL_DIGIT)
+               enabled = REG_GET(DISPC_CONFIG, 18, 18);
+       else
+               BUG();
+       enable_clocks(0);
+
+       return enabled;
+
+}
+
 
 bool dispc_trans_key_enabled(enum omap_channel ch)
 {
@@ -2791,6 +2912,16 @@ static void _omap_dispc_initialize_irq(void)
        omap_dispc_set_irqs();
 }
 
+void dispc_enable_sidle(void)
+{
+       REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3);  /* SIDLEMODE: smart idle */
+}
+
+void dispc_disable_sidle(void)
+{
+       REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3);  /* SIDLEMODE: no idle */
+}
+
 static void _omap_dispc_initial_config(void)
 {
        u32 l;
@@ -2879,6 +3010,7 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out,
                       u16 out_width, u16 out_height,
                       enum omap_color_mode color_mode,
                       bool ilace,
+                      enum omap_dss_rotation_type rotation_type,
                       u8 rotation, bool mirror)
 {
        int r = 0;
@@ -2899,6 +3031,7 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out,
                           width, height,
                           out_width, out_height,
                           color_mode, ilace,
+                          rotation_type,
                           rotation, mirror);
 
        enable_clocks(0);
@@ -3112,7 +3245,8 @@ void dispc_setup_partial_planes(struct omap_display *display,
                                pw, ph,
                                pow, poh,
                                pi->color_mode, 0,
-                               pi->rotation, // XXX rotation probably wrong
+                               pi->rotation_type,
+                               pi->rotation,
                                pi->mirror);
 
                dispc_enable_plane(ovl->id, 1);