Skip to content

Commit

Permalink
OMAP: DSS2: OMAPFB: Implement auto-update mode
Browse files Browse the repository at this point in the history
Implement auto-update mode for manual-update displays. omapfb driver
uses a delayed work to update the display with a constant rate.

The update mode can be changed via OMAPFB_SET_UPDATE_MODE ioctl, which
previously called omapdss but is now handled inside omapfb, and a new
sysfs file, "update_mode".

The update interval is by default 20 times per second, but can be
changed via "auto_update_freq" module parameter. There is also a new
module parameter "auto_update", which will make omapfb start manual
update displays in auto-update mode.

This auto-update mode can be used for testing if the userspace does not
support manual update displays properly. However, it is a very
inefficient solution, and should be considered more as a hack for
testing than something that could be used as a long term solution.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
  • Loading branch information
Tomi Valkeinen committed Jul 1, 2011
1 parent 065a40b commit 27cc213
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 56 deletions.
72 changes: 36 additions & 36 deletions drivers/video/omap2/omapfb/omapfb-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi,
}
EXPORT_SYMBOL(omapfb_update_window);

static int omapfb_set_update_mode(struct fb_info *fbi,
int omapfb_set_update_mode(struct fb_info *fbi,
enum omapfb_update_mode mode)
{
struct omap_dss_device *display = fb2display(fbi);
enum omap_dss_update_mode um;
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb_display_data *d;
int r;

if (!display || !display->driver->set_update_mode)
if (!display)
return -EINVAL;

switch (mode) {
case OMAPFB_UPDATE_DISABLED:
um = OMAP_DSS_UPDATE_DISABLED;
break;
if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
return -EINVAL;

case OMAPFB_AUTO_UPDATE:
um = OMAP_DSS_UPDATE_AUTO;
break;
omapfb_lock(fbdev);

case OMAPFB_MANUAL_UPDATE:
um = OMAP_DSS_UPDATE_MANUAL;
break;
d = get_display_data(fbdev, display);

default:
return -EINVAL;
if (d->update_mode == mode) {
omapfb_unlock(fbdev);
return 0;
}

r = display->driver->set_update_mode(display, um);
r = 0;

if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
if (mode == OMAPFB_AUTO_UPDATE)
omapfb_start_auto_update(fbdev, display);
else /* MANUAL_UPDATE */
omapfb_stop_auto_update(fbdev, display);

d->update_mode = mode;
} else { /* AUTO_UPDATE */
if (mode == OMAPFB_MANUAL_UPDATE)
r = -EINVAL;
}

omapfb_unlock(fbdev);

return r;
}

static int omapfb_get_update_mode(struct fb_info *fbi,
int omapfb_get_update_mode(struct fb_info *fbi,
enum omapfb_update_mode *mode)
{
struct omap_dss_device *display = fb2display(fbi);
enum omap_dss_update_mode m;
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb_display_data *d;

if (!display)
return -EINVAL;

if (!display->driver->get_update_mode) {
*mode = OMAPFB_AUTO_UPDATE;
return 0;
}
omapfb_lock(fbdev);

m = display->driver->get_update_mode(display);
d = get_display_data(fbdev, display);

switch (m) {
case OMAP_DSS_UPDATE_DISABLED:
*mode = OMAPFB_UPDATE_DISABLED;
break;
case OMAP_DSS_UPDATE_AUTO:
*mode = OMAPFB_AUTO_UPDATE;
break;
case OMAP_DSS_UPDATE_MANUAL:
*mode = OMAPFB_MANUAL_UPDATE;
break;
default:
BUG();
}
*mode = d->update_mode;

omapfb_unlock(fbdev);

return 0;
}
Expand Down
139 changes: 119 additions & 20 deletions drivers/video/omap2/omapfb/omapfb-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ static char *def_vram;
static int def_vrfb;
static int def_rotate;
static int def_mirror;
static bool auto_update;
static unsigned int auto_update_freq;
module_param(auto_update, bool, 0);
module_param(auto_update_freq, uint, 0644);

#ifdef DEBUG
unsigned int omapfb_debug;
Expand Down Expand Up @@ -1242,13 +1246,16 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
struct omapfb_display_data *d;
int r = 0;

if (!display)
return -EINVAL;

omapfb_lock(fbdev);

d = get_display_data(fbdev, display);

switch (blank) {
case FB_BLANK_UNBLANK:
if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
Expand All @@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->driver->resume)
r = display->driver->resume(display);

if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
d->update_mode == OMAPFB_AUTO_UPDATE &&
!d->auto_update_work_enabled)
omapfb_start_auto_update(fbdev, display);

break;

case FB_BLANK_NORMAL:
Expand All @@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
goto exit;

if (d->auto_update_work_enabled)
omapfb_stop_auto_update(fbdev, display);

if (display->driver->suspend)
r = display->driver->suspend(display);

Expand Down Expand Up @@ -1724,6 +1739,78 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
return r;
}

static void omapfb_auto_update_work(struct work_struct *work)
{
struct omap_dss_device *dssdev;
struct omap_dss_driver *dssdrv;
struct omapfb_display_data *d;
u16 w, h;
unsigned int freq;
struct omapfb2_device *fbdev;

d = container_of(work, struct omapfb_display_data,
auto_update_work.work);

dssdev = d->dssdev;
dssdrv = dssdev->driver;
fbdev = d->fbdev;

if (!dssdrv || !dssdrv->update)
return;

if (dssdrv->sync)
dssdrv->sync(dssdev);

dssdrv->get_resolution(dssdev, &w, &h);
dssdrv->update(dssdev, 0, 0, w, h);

freq = auto_update_freq;
if (freq == 0)
freq = 20;
queue_delayed_work(fbdev->auto_update_wq,
&d->auto_update_work, HZ / freq);
}

void omapfb_start_auto_update(struct omapfb2_device *fbdev,
struct omap_dss_device *display)
{
struct omapfb_display_data *d;

if (fbdev->auto_update_wq == NULL) {
struct workqueue_struct *wq;

wq = create_singlethread_workqueue("omapfb_auto_update");

if (wq == NULL) {
dev_err(fbdev->dev, "Failed to create workqueue for "
"auto-update\n");
return;
}

fbdev->auto_update_wq = wq;
}

d = get_display_data(fbdev, display);

INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);

d->auto_update_work_enabled = true;

omapfb_auto_update_work(&d->auto_update_work.work);
}

void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
struct omap_dss_device *display)
{
struct omapfb_display_data *d;

d = get_display_data(fbdev, display);

cancel_delayed_work_sync(&d->auto_update_work);

d->auto_update_work_enabled = false;
}

/* initialize fb_info, var, fix to something sane based on the display */
static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
{
Expand Down Expand Up @@ -1859,12 +1946,22 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)

for (i = 0; i < fbdev->num_displays; i++) {
struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;

if (fbdev->displays[i].auto_update_work_enabled)
omapfb_stop_auto_update(fbdev, dssdev);

if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
dssdev->driver->disable(dssdev);

omap_dss_put_device(dssdev);
}

if (fbdev->auto_update_wq != NULL) {
flush_workqueue(fbdev->auto_update_wq);
destroy_workqueue(fbdev->auto_update_wq);
fbdev->auto_update_wq = NULL;
}

dev_set_drvdata(fbdev->dev, NULL);
kfree(fbdev);
}
Expand Down Expand Up @@ -2183,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
struct omap_dss_device *dssdev)
{
struct omap_dss_driver *dssdrv = dssdev->driver;
struct omapfb_display_data *d;
int r;

r = dssdrv->enable(dssdev);
Expand All @@ -2192,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
return r;
}

d = get_display_data(fbdev, dssdev);

d->fbdev = fbdev;

if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
u16 w, h;

if (auto_update) {
omapfb_start_auto_update(fbdev, dssdev);
d->update_mode = OMAPFB_AUTO_UPDATE;
} else {
d->update_mode = OMAPFB_MANUAL_UPDATE;
}

if (dssdrv->enable_te) {
r = dssdrv->enable_te(dssdev, 1);
if (r) {
Expand All @@ -2202,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
}
}

if (dssdrv->set_update_mode) {
r = dssdrv->set_update_mode(dssdev,
OMAP_DSS_UPDATE_MANUAL);
if (r) {
dev_err(fbdev->dev,
"Failed to set update mode\n");
return r;
}
}

dssdrv->get_resolution(dssdev, &w, &h);
r = dssdrv->update(dssdev, 0, 0, w, h);
if (r) {
Expand All @@ -2220,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
return r;
}
} else {
if (dssdrv->set_update_mode) {
r = dssdrv->set_update_mode(dssdev,
OMAP_DSS_UPDATE_AUTO);
if (r) {
dev_err(fbdev->dev,
"Failed to set update mode\n");
return r;
}
}
d->update_mode = OMAPFB_AUTO_UPDATE;
}

return 0;
Expand Down Expand Up @@ -2276,14 +2368,21 @@ static int omapfb_probe(struct platform_device *pdev)
fbdev->num_displays = 0;
dssdev = NULL;
for_each_dss_dev(dssdev) {
struct omapfb_display_data *d;

omap_dss_get_device(dssdev);

if (!dssdev->driver) {
dev_err(&pdev->dev, "no driver for display\n");
r = -ENODEV;
}

fbdev->displays[fbdev->num_displays++].dssdev = dssdev;
d = &fbdev->displays[fbdev->num_displays++];
d->dssdev = dssdev;
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
d->update_mode = OMAPFB_MANUAL_UPDATE;
else
d->update_mode = OMAPFB_AUTO_UPDATE;
}

if (r)
Expand Down
34 changes: 34 additions & 0 deletions drivers/video/omap2/omapfb/omapfb-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
}

static ssize_t show_upd_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fb_info *fbi = dev_get_drvdata(dev);
enum omapfb_update_mode mode;
int r;

r = omapfb_get_update_mode(fbi, &mode);

if (r)
return r;

return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
}

static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct fb_info *fbi = dev_get_drvdata(dev);
unsigned mode;
int r;

r = kstrtouint(buf, 0, &mode);
if (r)
return r;

r = omapfb_set_update_mode(fbi, mode);
if (r)
return r;

return count;
}

static struct device_attribute omapfb_attrs[] = {
__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
store_rotate_type),
Expand All @@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = {
store_overlays_rotate),
__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
};

int omapfb_create_sysfs(struct omapfb2_device *fbdev)
Expand Down
Loading

0 comments on commit 27cc213

Please sign in to comment.