summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/omap/omap_vout.c33
-rw-r--r--drivers/video/omap2/dss/apply.c163
-rw-r--r--drivers/video/omap2/dss/dss.h3
-rw-r--r--drivers/video/omap2/dss/overlay.c20
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c30
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c4
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h11
-rw-r--r--include/video/omapdss.h6
9 files changed, 190 insertions, 82 deletions
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 9c5c19f142d..27c19fe7868 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -423,7 +423,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
"%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);
@@ -942,12 +942,8 @@ static int omap_vout_release(struct file *file)
/* 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);
@@ -1667,7 +1663,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
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;
@@ -1686,6 +1681,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
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:
@@ -1715,16 +1720,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
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 */
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 107a4ae6e5a..eb28a7f178d 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 a5493df14ee..7aac8a3367b 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 4dc6b92592d..7d7cdf62059 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;
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index df7bcce5b10..562b5cc0760 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -111,28 +111,22 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
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;
@@ -146,6 +140,12 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
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);
@@ -196,7 +196,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
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);
@@ -238,7 +238,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
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;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 70aa47de714..91b49b53069 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -2067,6 +2067,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
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) {
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 1694d5148f3..e8d8cc76a43 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -473,7 +473,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
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;
}
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index fdf0edeccf4..b03fb1365ce 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -181,13 +181,10 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev)
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 *
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 6e3e7a71683..9d01ff66659 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -352,8 +352,6 @@ struct omap_dss_cpr_coefs {
};
struct omap_overlay_info {
- bool enabled;
-
u32 paddr;
u32 p_uv_addr; /* for NV12 format */
u16 screen_width;
@@ -391,6 +389,10 @@ struct omap_overlay {
/* 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);