diff options
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r-- | drivers/video/omap2/dss/apply.c | 163 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/overlay.c | 20 |
3 files changed, 146 insertions, 40 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 107a4ae6e5ac..eb28a7f178dd 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -63,14 +63,18 @@ struct ovl_priv_data { * 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 { @@ -132,11 +136,6 @@ static bool mgr_manual_update(struct omap_overlay_manager *mgr) 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); @@ -270,10 +269,8 @@ static int dss_ovl_write_regs(struct omap_overlay *ovl) 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); @@ -291,11 +288,21 @@ static int dss_ovl_write_regs(struct omap_overlay *ovl) 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; @@ -356,6 +363,30 @@ static int dss_write_regs(void) 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); @@ -419,6 +450,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) 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; @@ -490,8 +522,10 @@ static void dss_apply_irq_handler(void *data, u32 mask) 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) { @@ -541,14 +575,6 @@ static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) ovl->info_dirty = true; } - if (!overlay_enabled(ovl)) { - if (op->enabled) { - op->enabled = false; - op->dirty = true; - } - return; - } - if (!ovl->info_dirty) return; @@ -557,8 +583,6 @@ static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) op->info = ovl->info; op->channel = ovl->manager->id; - - op->enabled = true; } static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) @@ -593,9 +617,6 @@ static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl) op = get_ovl_priv(ovl); - if (!op->enabled) - return; - dssdev = ovl->manager->device; size = dispc_ovl_get_fifo_size(ovl->id); @@ -828,6 +849,8 @@ void dss_ovl_get_info(struct omap_overlay *ovl, 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) @@ -842,7 +865,10 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, 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; @@ -852,6 +878,8 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, 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. @@ -875,6 +903,8 @@ err: 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); @@ -885,7 +915,10 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) 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; @@ -895,9 +928,83 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) 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; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index a5493df14eee..7aac8a3367bc 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -180,6 +180,9 @@ int dss_mgr_set_device(struct omap_overlay_manager *mgr, 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, diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 4dc6b92592d0..7d7cdf62059b 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -205,7 +205,7 @@ static ssize_t overlay_output_size_store(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, @@ -213,26 +213,19 @@ 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; } @@ -489,6 +482,9 @@ void dss_init_overlays(struct platform_device *pdev) 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; |