Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[pandora-kernel.git] / drivers / video / omap2 / dss / dispc.c
index 829be3b..6892cfd 100644 (file)
@@ -179,7 +179,8 @@ static void dispc_save_context(void)
        SR(CONTROL);
        SR(CONFIG);
        SR(LINE_NUMBER);
-       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+                       dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                SR(GLOBAL_ALPHA);
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                SR(CONTROL2);
@@ -293,7 +294,8 @@ static void dispc_restore_context(void)
        /*RR(CONTROL);*/
        RR(CONFIG);
        RR(LINE_NUMBER);
-       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+                       dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                RR(GLOBAL_ALPHA);
        if (dss_has_feature(FEAT_MGR_LCD2))
                RR(CONFIG2);
@@ -737,6 +739,27 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
        dispc_write_reg(DISPC_OVL_SIZE(plane), val);
 }
 
+static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder)
+{
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+               return;
+
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
+}
+
+static void dispc_ovl_enable_zorder_planes(void)
+{
+       int i;
+
+       if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
+               return;
+
+       for (i = 0; i < dss_feat_get_num_ovls(); i++)
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
+}
+
 static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
 {
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
@@ -749,7 +772,7 @@ static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
 
 static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
 {
-       static const unsigned shifts[] = { 0, 8, 16, };
+       static const unsigned shifts[] = { 0, 8, 16, 24, };
        int shift;
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
 
@@ -864,6 +887,7 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane,
                break;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
+       case OMAP_DSS_VIDEO3:
                shift = 16;
                break;
        default:
@@ -901,7 +925,7 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane,
 static void dispc_ovl_set_burst_size(enum omap_plane plane,
                enum omap_burst_size burst_size)
 {
-       static const unsigned shifts[] = { 6, 14, 14, };
+       static const unsigned shifts[] = { 6, 14, 14, 14, };
        int shift;
 
        shift = shifts[plane];
@@ -986,7 +1010,7 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
 
 static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable)
 {
-       static const unsigned shifts[] = { 5, 10, 10 };
+       static const unsigned shifts[] = { 5, 10, 10, 10 };
        int shift;
 
        shift = shifts[plane];
@@ -1686,14 +1710,74 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
        return dispc_mgr_pclk_rate(channel) * vf * hf;
 }
 
+static int dispc_ovl_calc_scaling(enum omap_plane plane,
+               enum omap_channel channel, u16 width, u16 height,
+               u16 out_width, u16 out_height,
+               enum omap_color_mode color_mode, bool *five_taps)
+{
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+       const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+       unsigned long fclk = 0;
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
+               if (width != out_width || height != out_height)
+                       return -EINVAL;
+               else
+                       return 0;
+       }
+
+       if (out_width < width / maxdownscale ||
+                       out_width > width * 8)
+               return -EINVAL;
+
+       if (out_height < height / maxdownscale ||
+                       out_height > height * 8)
+               return -EINVAL;
+
+       /* 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;
+       }
+
+       return 0;
+}
+
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
                bool ilace, enum omap_channel channel, bool replication,
                u32 fifo_low, u32 fifo_high)
 {
-       const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
-       bool five_taps = 0;
+       struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+       bool five_taps = false;
        bool fieldmode = 0;
-       int cconv = 0;
+       int r, cconv = 0;
        unsigned offset0, offset1;
        s32 row_inc;
        s32 pix_inc;
@@ -1727,61 +1811,16 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        if (!dss_feat_color_mode_supported(plane, oi->color_mode))
                return -EINVAL;
 
-       if (plane == OMAP_DSS_GFX) {
-               if (oi->width != oi->out_width || oi->height != oi->out_height)
-                       return -EINVAL;
-       } else {
-               /* video plane */
-
-               unsigned long fclk = 0;
-
-               if (oi->out_width < oi->width / maxdownscale ||
-                  oi->out_width > oi->width * 8)
-                       return -EINVAL;
-
-               if (oi->out_height < oi->height / maxdownscale ||
-                  oi->out_height > oi->height * 8)
-                       return -EINVAL;
-
-               if (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
-                               oi->color_mode == OMAP_DSS_COLOR_UYVY ||
-                               oi->color_mode == OMAP_DSS_COLOR_NV12)
-                       cconv = 1;
-
-               /* Must use 5-tap filter? */
-               five_taps = oi->height > oi->out_height * 2;
-
-               if (!five_taps) {
-                       fclk = calc_fclk(channel, oi->width, oi->height,
-                                       oi->out_width, oi->out_height);
-
-                       /* Try 5-tap filter if 3-tap fclk is too high */
-                       if (cpu_is_omap34xx() && oi->height > oi->out_height &&
-                                       fclk > dispc_fclk_rate())
-                               five_taps = true;
-               }
-
-               if (oi->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, oi->width,
-                                       oi->height, oi->out_width,
-                                       oi->out_height, oi->color_mode);
-
-               DSSDBG("required fclk rate = %lu Hz\n", fclk);
-               DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
+       r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height,
+                       oi->out_width, oi->out_height, oi->color_mode,
+                       &five_taps);
+       if (r)
+               return r;
 
-               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 (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       oi->color_mode == OMAP_DSS_COLOR_UYVY ||
+                       oi->color_mode == OMAP_DSS_COLOR_NV12)
+               cconv = 1;
 
        if (ilace && !fieldmode) {
                /*
@@ -1836,7 +1875,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
 
        dispc_ovl_set_pic_size(plane, oi->width, oi->height);
 
-       if (plane != OMAP_DSS_GFX) {
+       if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
                dispc_ovl_set_scaling(plane, oi->width, oi->height,
                                   oi->out_width, oi->out_height,
                                   ilace, five_taps, fieldmode,
@@ -1848,6 +1887,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror,
                        oi->color_mode);
 
+       dispc_ovl_set_zorder(plane, oi->zorder);
        dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
        dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
 
@@ -2144,38 +2184,35 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
        else /* OMAP_DSS_CHANNEL_LCD2 */
                REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
 }
-void dispc_mgr_enable_alpha_blending(enum omap_channel ch, bool enable)
+
+void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable)
 {
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
                return;
 
        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_mgr_alpha_blending_enabled(enum omap_channel ch)
+
+bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch)
 {
        bool enabled;
 
-       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
                return false;
 
        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, 19, 19);
-       else if (ch == OMAP_DSS_CHANNEL_LCD2)
-               enabled = REG_GET(DISPC_CONFIG2, 18, 18);
        else
                BUG();
 
        return enabled;
 }
 
-
 bool dispc_mgr_trans_key_enabled(enum omap_channel ch)
 {
        bool enabled;
@@ -2544,6 +2581,10 @@ void dispc_dump_irqs(struct seq_file *s)
        PIS(VID1_END_WIN);
        PIS(VID2_FIFO_UNDERFLOW);
        PIS(VID2_END_WIN);
+       if (dss_feat_get_num_ovls() > 3) {
+               PIS(VID3_FIFO_UNDERFLOW);
+               PIS(VID3_END_WIN);
+       }
        PIS(SYNC_LOST);
        PIS(SYNC_LOST_DIGIT);
        PIS(WAKEUP);
@@ -2569,6 +2610,7 @@ void dispc_dump_regs(struct seq_file *s)
                [OMAP_DSS_GFX]          = "GFX",
                [OMAP_DSS_VIDEO1]       = "VID1",
                [OMAP_DSS_VIDEO2]       = "VID2",
+               [OMAP_DSS_VIDEO3]       = "VID3",
        };
        const char **p_names;
 
@@ -2588,7 +2630,8 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_CAPABLE);
        DUMPREG(DISPC_LINE_STATUS);
        DUMPREG(DISPC_LINE_NUMBER);
-       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+       if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
+                       dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
                DUMPREG(DISPC_GLOBAL_ALPHA);
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                DUMPREG(DISPC_CONTROL2);
@@ -2970,6 +3013,8 @@ static void print_irq_status(u32 status)
        PIS(OCP_ERR);
        PIS(VID1_FIFO_UNDERFLOW);
        PIS(VID2_FIFO_UNDERFLOW);
+       if (dss_feat_get_num_ovls() > 3)
+               PIS(VID3_FIFO_UNDERFLOW);
        PIS(SYNC_LOST);
        PIS(SYNC_LOST_DIGIT);
        if (dss_has_feature(FEAT_MGR_LCD2))
@@ -3067,6 +3112,7 @@ static void dispc_error_worker(struct work_struct *work)
                DISPC_IRQ_GFX_FIFO_UNDERFLOW,
                DISPC_IRQ_VID1_FIFO_UNDERFLOW,
                DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+               DISPC_IRQ_VID3_FIFO_UNDERFLOW,
        };
 
        static const unsigned sync_lost_bits[] = {
@@ -3242,6 +3288,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_feat_get_num_ovls() > 3)
+               dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
 
        /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
         * so clear it */
@@ -3291,6 +3339,8 @@ static void _omap_dispc_initial_config(void)
        dispc_read_plane_fifo_sizes();
 
        dispc_configure_burst_sizes();
+
+       dispc_ovl_enable_zorder_planes();
 }
 
 /* DISPC HW IP initialisation */