diff options
Diffstat (limited to 'drivers/video/omap2/omapfb')
-rw-r--r-- | drivers/video/omap2/omapfb/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 73 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 302 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-sysfs.c | 40 | ||||
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb.h | 37 |
5 files changed, 347 insertions, 107 deletions
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index aa33386..83d3fe7 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -1,5 +1,5 @@ menuconfig FB_OMAP2 - tristate "OMAP2+ frame buffer support (EXPERIMENTAL)" + tristate "OMAP2+ frame buffer support" depends on FB && OMAP2_DSS select OMAP2_VRAM diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index cff4503..df7bcce 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -27,6 +27,7 @@ #include <linux/mm.h> #include <linux/omapfb.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <video/omapdss.h> #include <plat/vrfb.h> @@ -316,67 +317,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; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 505bc12..f7c1753 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -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; @@ -804,19 +808,15 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, static void omapfb_calc_addr(const struct omapfb_info *ofbi, const struct fb_var_screeninfo *var, const struct fb_fix_screeninfo *fix, - int rotation, u32 *paddr, void __iomem **vaddr) + int rotation, u32 *paddr) { u32 data_start_p; - void __iomem *data_start_v; int offset; - if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); - data_start_v = NULL; - } else { + else data_start_p = omapfb_get_region_paddr(ofbi); - data_start_v = omapfb_get_region_vaddr(ofbi); - } if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) offset = calc_rotation_offset_vrfb(var, fix, rotation); @@ -824,16 +824,14 @@ static void omapfb_calc_addr(const struct omapfb_info *ofbi, offset = calc_rotation_offset_dma(var, fix, rotation); data_start_p += offset; - data_start_v += offset; if (offset) DBG("offset %d, %d = %d\n", var->xoffset, var->yoffset, offset); - DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); + DBG("paddr %x\n", data_start_p); *paddr = data_start_p; - *vaddr = data_start_v; } /* setup overlay according to the fb */ @@ -846,7 +844,6 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, struct fb_fix_screeninfo *fix = &fbi->fix; enum omap_color_mode mode = 0; u32 data_start_p = 0; - void __iomem *data_start_v = NULL; struct omap_overlay_info info; int xres, yres; int screen_width; @@ -876,8 +873,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, } if (ofbi->region->size) - omapfb_calc_addr(ofbi, var, fix, rotation, - &data_start_p, &data_start_v); + omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p); r = fb_mode_to_dss_mode(var, &mode); if (r) { @@ -906,7 +902,6 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, mirror = ofbi->mirror; info.paddr = data_start_p; - info.vaddr = data_start_v; info.screen_width = screen_width; info.width = xres; info.height = yres; @@ -1188,7 +1183,7 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, break; if (regno < 16) { - u16 pal; + u32 pal; pal = ((red >> (16 - var->red.length)) << var->red.offset) | ((green >> (16 - var->green.length)) << @@ -1242,6 +1237,7 @@ 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) @@ -1249,6 +1245,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi) omapfb_lock(fbdev); + d = get_display_data(fbdev, display); + switch (blank) { case FB_BLANK_UNBLANK: if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) @@ -1257,6 +1255,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: @@ -1268,6 +1271,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); @@ -1724,6 +1730,78 @@ err: 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) { @@ -1858,10 +1936,21 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) } for (i = 0; i < fbdev->num_displays; i++) { - if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED) - fbdev->displays[i]->driver->disable(fbdev->displays[i]); + struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; - omap_dss_put_device(fbdev->displays[i]); + 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); @@ -2084,14 +2173,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, int r; u8 bpp; struct omap_video_timings timings, temp_timings; + struct omapfb_display_data *d; r = omapfb_mode_to_timings(mode_str, &timings, &bpp); if (r) return r; - fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display; - fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp; - ++fbdev->num_bpp_overrides; + d = get_display_data(fbdev, display); + d->bpp_override = bpp; if (display->driver->check_timings) { r = display->driver->check_timings(display, &timings); @@ -2117,14 +2206,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev, struct omap_dss_device *dssdev) { - int i; + struct omapfb_display_data *d; BUG_ON(dssdev->driver->get_recommended_bpp == NULL); - for (i = 0; i < fbdev->num_bpp_overrides; ++i) { - if (dssdev == fbdev->bpp_overrides[i].dssdev) - return fbdev->bpp_overrides[i].bpp; - } + d = get_display_data(fbdev, dssdev); + + if (d->bpp_override != 0) + return d->bpp_override; return dssdev->driver->get_recommended_bpp(dssdev); } @@ -2156,9 +2245,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) display = NULL; for (i = 0; i < fbdev->num_displays; ++i) { - if (strcmp(fbdev->displays[i]->name, + if (strcmp(fbdev->displays[i].dssdev->name, display_str) == 0) { - display = fbdev->displays[i]; + display = fbdev->displays[i].dssdev; break; } } @@ -2178,10 +2267,92 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) return r; } +static void fb_videomode_to_omap_timings(struct fb_videomode *m, + struct omap_video_timings *t) +{ + t->x_res = m->xres; + t->y_res = m->yres; + t->pixel_clock = PICOS2KHZ(m->pixclock); + t->hsw = m->hsync_len; + t->hfp = m->right_margin; + t->hbp = m->left_margin; + t->vsw = m->vsync_len; + t->vfp = m->lower_margin; + t->vbp = m->upper_margin; +} + +static int omapfb_find_best_mode(struct omap_dss_device *display, + struct omap_video_timings *timings) +{ + struct fb_monspecs *specs; + u8 *edid; + int r, i, best_xres, best_idx, len; + + if (!display->driver->read_edid) + return -ENODEV; + + len = 0x80 * 2; + edid = kmalloc(len, GFP_KERNEL); + + r = display->driver->read_edid(display, edid, len); + if (r < 0) + goto err1; + + specs = kzalloc(sizeof(*specs), GFP_KERNEL); + + fb_edid_to_monspecs(edid, specs); + + if (edid[126] > 0) + fb_edid_add_monspecs(edid + 0x80, specs); + + best_xres = 0; + best_idx = -1; + + for (i = 0; i < specs->modedb_len; ++i) { + struct fb_videomode *m; + struct omap_video_timings t; + + m = &specs->modedb[i]; + + if (m->pixclock == 0) + continue; + + /* skip repeated pixel modes */ + if (m->xres == 2880 || m->xres == 1440) + continue; + + fb_videomode_to_omap_timings(m, &t); + + r = display->driver->check_timings(display, &t); + if (r == 0 && best_xres < m->xres) { + best_xres = m->xres; + best_idx = i; + } + } + + if (best_xres == 0) { + r = -ENOENT; + goto err2; + } + + fb_videomode_to_omap_timings(&specs->modedb[best_idx], timings); + + r = 0; + +err2: + fb_destroy_modedb(specs->modedb); + kfree(specs); +err1: + kfree(edid); + + return r; +} + 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); @@ -2191,8 +2362,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) { @@ -2201,16 +2384,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) { @@ -2219,15 +2392,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; @@ -2275,14 +2440,23 @@ 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; + dev_warn(&pdev->dev, "no driver for display: %s\n", + dssdev->name); + omap_dss_put_device(dssdev); + continue; } - fbdev->displays[fbdev->num_displays++] = 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) @@ -2302,9 +2476,27 @@ static int omapfb_probe(struct platform_device *pdev) for (i = 0; i < fbdev->num_managers; i++) fbdev->managers[i] = omap_dss_get_overlay_manager(i); + /* gfx overlay should be the default one. find a display + * connected to that, and use it as default display */ + ovl = omap_dss_get_overlay(0); + if (ovl->manager && ovl->manager->device) { + def_display = ovl->manager->device; + } else { + dev_warn(&pdev->dev, "cannot find default display\n"); + def_display = NULL; + } + if (def_mode && strlen(def_mode) > 0) { if (omapfb_parse_def_modes(fbdev)) dev_warn(&pdev->dev, "cannot parse default modes\n"); + } else if (def_display && def_display->driver->set_timings && + def_display->driver->check_timings) { + struct omap_video_timings t; + + r = omapfb_find_best_mode(def_display, &t); + + if (r == 0) + def_display->driver->set_timings(def_display, &t); } r = omapfb_create_framebuffers(fbdev); @@ -2321,16 +2513,6 @@ static int omapfb_probe(struct platform_device *pdev) DBG("mgr->apply'ed\n"); - /* gfx overlay should be the default one. find a display - * connected to that, and use it as default display */ - ovl = omap_dss_get_overlay(0); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; - } else { - dev_warn(&pdev->dev, "cannot find default display\n"); - def_display = NULL; - } - if (def_display) { r = omapfb_init_display(fbdev, def_display); if (r) { diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 2f5e817..1694d51 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -104,16 +104,14 @@ static ssize_t store_mirror(struct device *dev, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - int mirror; + bool mirror; int r; struct fb_var_screeninfo new_var; - r = kstrtoint(buf, 0, &mirror); + r = strtobool(buf, &mirror); if (r) return r; - mirror = !!mirror; - if (!lock_fb_info(fbi)) return -ENODEV; @@ -518,6 +516,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), @@ -528,6 +559,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) diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index aa1b1d9..fdf0ede 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -73,6 +73,15 @@ struct omapfb_info { bool mirror; }; +struct omapfb_display_data { + struct omapfb2_device *fbdev; + struct omap_dss_device *dssdev; + u8 bpp_override; + enum omapfb_update_mode update_mode; + bool auto_update_work_enabled; + struct delayed_work auto_update_work; +}; + struct omapfb2_device { struct device *dev; struct mutex mtx; @@ -86,17 +95,13 @@ struct omapfb2_device { struct omapfb2_mem_region regions[10]; unsigned num_displays; - struct omap_dss_device *displays[10]; + struct omapfb_display_data displays[10]; unsigned num_overlays; struct omap_overlay *overlays[10]; unsigned num_managers; struct omap_overlay_manager *managers[10]; - unsigned num_bpp_overrides; - struct { - struct omap_dss_device *dssdev; - u8 bpp; - } bpp_overrides[10]; + struct workqueue_struct *auto_update_wq; }; struct omapfb_colormode { @@ -128,6 +133,13 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode, int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, u16 posx, u16 posy, u16 outw, u16 outh); +void omapfb_start_auto_update(struct omapfb2_device *fbdev, + struct omap_dss_device *display); +void omapfb_stop_auto_update(struct omapfb2_device *fbdev, + struct omap_dss_device *display); +int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode); +int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode); + /* find the display connected to this fb, if any */ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) { @@ -143,6 +155,19 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) return NULL; } +static inline struct omapfb_display_data *get_display_data( + struct omapfb2_device *fbdev, struct omap_dss_device *dssdev) +{ + int i; + + for (i = 0; i < fbdev->num_displays; ++i) + if (fbdev->displays[i].dssdev == dssdev) + return &fbdev->displays[i]; + + /* This should never happen */ + BUG(); +} + static inline void omapfb_lock(struct omapfb2_device *fbdev) { mutex_lock(&fbdev->mtx); |