"%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
                "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
                "out_height=%d rotation_type=%d screen_width=%d\n",
-               __func__, info.enabled, info.paddr, info.width, info.height,
+               __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
                info.color_mode, info.rotation, info.mirror, info.pos_x,
                info.pos_y, info.out_width, info.out_height, info.rotation_type,
                info.screen_width);
        /* Disable all the overlay managers connected with this interface */
        for (i = 0; i < ovid->num_overlays; i++) {
                struct omap_overlay *ovl = ovid->overlays[i];
-               if (ovl->manager && ovl->manager->device) {
-                       struct omap_overlay_info info;
-                       ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 0;
-                       ovl->set_overlay_info(ovl, &info);
-               }
+               if (ovl->manager && ovl->manager->device)
+                       ovl->disable(ovl);
        }
        /* Turn off the pipeline */
        ret = omapvid_apply_changes(vout);
                if (ovl->manager && ovl->manager->device) {
                        struct omap_overlay_info info;
                        ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 1;
                        info.paddr = addr;
                        if (ovl->set_overlay_info(ovl, &info)) {
                                ret = -EINVAL;
        if (ret)
                v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
 
+       for (j = 0; j < ovid->num_overlays; j++) {
+               struct omap_overlay *ovl = ovid->overlays[j];
+
+               if (ovl->manager && ovl->manager->device) {
+                       ret = ovl->enable(ovl);
+                       if (ret)
+                               goto streamon_err1;
+               }
+       }
+
        ret = 0;
 
 streamon_err1:
        for (j = 0; j < ovid->num_overlays; j++) {
                struct omap_overlay *ovl = ovid->overlays[j];
 
-               if (ovl->manager && ovl->manager->device) {
-                       struct omap_overlay_info info;
-
-                       ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 0;
-                       ret = ovl->set_overlay_info(ovl, &info);
-                       if (ret)
-                               v4l2_err(&vout->vid_dev->v4l2_dev,
-                               "failed to update overlay info in streamoff\n");
-               }
+               if (ovl->manager && ovl->manager->device)
+                       ovl->disable(ovl);
        }
 
        /* Turn of the pipeline */
 
         * VSYNC/EVSYNC */
        bool shadow_dirty;
 
-       bool enabled;
-
        struct omap_overlay_info info;
 
        enum omap_channel channel;
 
        u32 fifo_low;
        u32 fifo_high;
+
+       bool extra_info_dirty;
+       bool shadow_extra_info_dirty;
+
+       bool enabled;
+
 };
 
 struct mgr_priv_data {
        return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
 }
 
-static int overlay_enabled(struct omap_overlay *ovl)
-{
-       return ovl->info.enabled && ovl->manager && ovl->manager->device;
-}
-
 int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
 {
        unsigned long timeout = msecs_to_jiffies(500);
        op = get_ovl_priv(ovl);
        oi = &op->info;
 
-       if (!op->enabled) {
-               dispc_ovl_enable(ovl->id, 0);
+       if (!op->enabled)
                return 0;
-       }
 
        replication = dss_use_replication(ovl->manager->device, oi->color_mode);
 
 
        dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
 
-       dispc_ovl_enable(ovl->id, 1);
-
        return 0;
 }
 
+static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+
+       DSSDBGF("%d", ovl->id);
+
+       /* note: write also when op->enabled == false, so that the ovl gets
+        * disabled */
+
+       dispc_ovl_enable(ovl->id, op->enabled);
+}
+
 static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
 {
        struct mgr_priv_data *mp;
                mgr_go[op->channel] = true;
        }
 
+       for (i = 0; i < num_ovls; ++i) {
+               ovl = omap_dss_get_overlay(i);
+               op = get_ovl_priv(ovl);
+
+               if (!op->extra_info_dirty)
+                       continue;
+
+               mp = get_mgr_priv(ovl->manager);
+
+               if (mp->manual_update && !mp->do_manual_update)
+                       continue;
+
+               if (mp->busy) {
+                       busy = true;
+                       continue;
+               }
+
+               dss_ovl_write_regs_extra(ovl);
+
+               op->extra_info_dirty = false;
+               op->shadow_extra_info_dirty = true;
+               mgr_go[op->channel] = true;
+       }
+
        /* Commit manager settings */
        for (i = 0; i < num_mgrs; ++i) {
                mgr = omap_dss_get_overlay_manager(i);
        list_for_each_entry(ovl, &mgr->overlays, list) {
                op = get_ovl_priv(ovl);
                op->shadow_dirty = false;
+               op->shadow_extra_info_dirty = false;
        }
 
        mp->shadow_dirty = false;
 
                mp = get_mgr_priv(ovl->manager);
 
-               if (!mp->busy)
+               if (!mp->busy) {
                        op->shadow_dirty = false;
+                       op->shadow_extra_info_dirty = false;
+               }
        }
 
        for (i = 0; i < num_mgrs; ++i) {
                ovl->info_dirty  = true;
        }
 
-       if (!overlay_enabled(ovl)) {
-               if (op->enabled) {
-                       op->enabled = false;
-                       op->dirty = true;
-               }
-               return;
-       }
-
        if (!ovl->info_dirty)
                return;
 
        op->info = ovl->info;
 
        op->channel = ovl->manager->id;
-
-       op->enabled = true;
 }
 
 static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
 
        op = get_ovl_priv(ovl);
 
-       if (!op->enabled)
-               return;
-
        dssdev = ovl->manager->device;
 
        size = dispc_ovl_get_fifo_size(ovl->id);
 int dss_ovl_set_manager(struct omap_overlay *ovl,
                struct omap_overlay_manager *mgr)
 {
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
        int r;
 
        if (!mgr)
                goto err;
        }
 
-       if (ovl->info.enabled) {
+       spin_lock_irqsave(&data_lock, flags);
+
+       if (op->enabled) {
+               spin_unlock_irqrestore(&data_lock, flags);
                DSSERR("overlay has to be disabled to change the manager\n");
                r = -EINVAL;
                goto err;
        list_add_tail(&ovl->list, &mgr->overlays);
        ovl->manager_changed = true;
 
+       spin_unlock_irqrestore(&data_lock, flags);
+
        /* XXX: When there is an overlay on a DSI manual update display, and
         * the overlay is first disabled, then moved to tv, and enabled, we
         * seem to get SYNC_LOST_DIGIT error.
 
 int dss_ovl_unset_manager(struct omap_overlay *ovl)
 {
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
        int r;
 
        mutex_lock(&apply_lock);
                goto err;
        }
 
-       if (ovl->info.enabled) {
+       spin_lock_irqsave(&data_lock, flags);
+
+       if (op->enabled) {
+               spin_unlock_irqrestore(&data_lock, flags);
                DSSERR("overlay has to be disabled to unset the manager\n");
                r = -EINVAL;
                goto err;
        list_del(&ovl->list);
        ovl->manager_changed = true;
 
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+bool dss_ovl_is_enabled(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       bool e;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       e = op->enabled;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       return e;
+}
+
+int dss_ovl_enable(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (ovl->manager == NULL || ovl->manager->device == NULL) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       op->enabled = true;
+       op->extra_info_dirty = true;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+int dss_ovl_disable(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (ovl->manager == NULL || ovl->manager->device == NULL) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       op->enabled = false;
+       op->extra_info_dirty = true;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
        mutex_unlock(&apply_lock);
 
        return 0;
+
 err:
        mutex_unlock(&apply_lock);
        return r;
 
                struct omap_dss_device *dssdev);
 int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
 
+bool dss_ovl_is_enabled(struct omap_overlay *ovl);
+int dss_ovl_enable(struct omap_overlay *ovl);
+int dss_ovl_disable(struct omap_overlay *ovl);
 int dss_ovl_set_info(struct omap_overlay *ovl,
                struct omap_overlay_info *info);
 void dss_ovl_get_info(struct omap_overlay *ovl,
 
 
 static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
+       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
 }
 
 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
 {
        int r;
        bool enable;
-       struct omap_overlay_info info;
-
-       ovl->get_overlay_info(ovl, &info);
 
        r = strtobool(buf, &enable);
        if (r)
                return r;
 
-       info.enabled = enable;
+       if (enable)
+               r = ovl->enable(ovl);
+       else
+               r = ovl->disable(ovl);
 
-       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;
 }
 
                        break;
                }
 
+               ovl->is_enabled = &dss_ovl_is_enabled;
+               ovl->enable = &dss_ovl_enable;
+               ovl->disable = &dss_ovl_disable;
                ovl->set_manager = &dss_ovl_set_manager;
                ovl->unset_manager = &dss_ovl_unset_manager;
                ovl->set_overlay_info = &dss_ovl_set_info;
 
                set_fb_fix(fbi);
        }
 
-       if (pi->enabled) {
-               struct omap_overlay_info info;
+       if (!pi->enabled) {
+               r = ovl->disable(ovl);
+               if (r)
+                       goto undo;
+       }
 
+       if (pi->enabled) {
                r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
                        pi->out_width, pi->out_height);
                if (r)
                        goto undo;
-
-               ovl->get_overlay_info(ovl, &info);
-
-               if (!info.enabled) {
-                       info.enabled = pi->enabled;
-                       r = ovl->set_overlay_info(ovl, &info);
-                       if (r)
-                               goto undo;
-               }
        } else {
                struct omap_overlay_info info;
 
                ovl->get_overlay_info(ovl, &info);
 
-               info.enabled = pi->enabled;
                info.pos_x = pi->pos_x;
                info.pos_y = pi->pos_y;
                info.out_width = pi->out_width;
        if (ovl->manager)
                ovl->manager->apply(ovl->manager);
 
+       if (pi->enabled) {
+               r = ovl->enable(ovl);
+               if (r)
+                       goto undo;
+       }
+
        /* Release the locks in a specific order to keep lockdep happy */
        if (old_rg->id > new_rg->id) {
                omapfb_put_mem_region(old_rg);
 
                pi->pos_x = ovli->pos_x;
                pi->pos_y = ovli->pos_y;
-               pi->enabled = ovli->enabled;
+               pi->enabled = ovl->is_enabled(ovl);
                pi->channel_out = 0; /* xxx */
                pi->mirror = 0;
                pi->mem_idx = get_mem_idx(ofbi);
                        continue;
 
                for (j = 0; j < ofbi2->num_overlays; j++) {
-                       if (ofbi2->overlays[j]->info.enabled) {
+                       struct omap_overlay *ovl;
+                       ovl = ofbi2->overlays[j];
+                       if (ovl->is_enabled(ovl)) {
                                r = -EBUSY;
                                goto out;
                        }
 
                if (ofbi->num_overlays > 0) {
                        struct omap_overlay *ovl = ofbi->overlays[0];
 
+                       ovl->manager->apply(ovl->manager);
+
                        r = omapfb_overlay_enable(ovl, 1);
 
                        if (r) {
 
                        continue;
 
                for (j = 0; j < ofbi2->num_overlays; j++) {
-                       if (ofbi2->overlays[j]->info.enabled) {
+                       struct omap_overlay *ovl;
+                       ovl = ofbi2->overlays[j];
+                       if (ovl->is_enabled(ovl)) {
                                r = -EBUSY;
                                goto out;
                        }
 
 static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
                int enable)
 {
-       struct omap_overlay_info info;
-
-       ovl->get_overlay_info(ovl, &info);
-       if (info.enabled == enable)
-               return 0;
-       info.enabled = enable;
-       return ovl->set_overlay_info(ovl, &info);
+       if (enable)
+               return ovl->enable(ovl);
+       else
+               return ovl->disable(ovl);
 }
 
 static inline struct omapfb2_mem_region *
 
 };
 
 struct omap_overlay_info {
-       bool enabled;
-
        u32 paddr;
        u32 p_uv_addr;  /* for NV12 format */
        u16 screen_width;
        /* if true, info has been changed, but not applied() yet */
        bool info_dirty;
 
+       int (*enable)(struct omap_overlay *ovl);
+       int (*disable)(struct omap_overlay *ovl);
+       bool (*is_enabled)(struct omap_overlay *ovl);
+
        int (*set_manager)(struct omap_overlay *ovl,
                struct omap_overlay_manager *mgr);
        int (*unset_manager)(struct omap_overlay *ovl);