Skip to content

Commit

Permalink
OMAPDSS: APPLY: rewrite overlay enable/disable
Browse files Browse the repository at this point in the history
Overlays are currently enabled and disabled with a boolean in the struct
omap_overlay_info. The overlay info is set with ovl->set_overlay_info(),
and made into use with mgr->apply().

This doesn't work properly, as the enable/disable status may affect also
other overlays, for example when using fifo-merge. Thus the enabling and
disabling of the overlay needs to be done outside the normal overlay
configuration.

This patch achieves that by doing the following things:

1) Add function pointers to struct omap_overlay: enable(), disable() and
is_enabled(). These are used to do the obvious. The functions may block.

2) Move the "enabled" field from struct omap_overlay to ovl_priv_data.

3) Add a new route for settings to be applied to the HW, called
"extra_info". The status of the normal info and extra_info are tracked
separately.

The point here is to allow the normal info to be changed and
applied in non-blocking matter, whereas the extra_info can only be
changed when holding the mutex. This makes it possible to, for example,
set the overlay enable flag, apply it, and wait until the HW has taken
the flag into use.

This is not possible if the enable flag would be in the normal info, as
a new value for the flag could be set at any time from the users of
omapdss.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
  • Loading branch information
Tomi Valkeinen committed Dec 2, 2011
1 parent 43a972d commit aaa874a
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 82 deletions.
33 changes: 15 additions & 18 deletions drivers/media/video/omap/omap_vout.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand Down Expand Up @@ -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 */
Expand Down
163 changes: 135 additions & 28 deletions drivers/video/omap2/dss/apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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.
Expand All @@ -875,6 +903,8 @@ int dss_ovl_set_manager(struct omap_overlay *ovl,

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);
Expand All @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions drivers/video/omap2/dss/dss.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit aaa874a

Please sign in to comment.