diff options
Diffstat (limited to 'drivers/staging/omapdrm')
-rw-r--r-- | drivers/staging/omapdrm/omap_crtc.c | 37 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_debugfs.c | 97 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_dmm_tiler.c | 91 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_dmm_tiler.h | 15 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_drv.c | 16 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_drv.h | 19 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_fb.c | 124 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_fbdev.c | 26 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_gem.c | 172 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_gem_helpers.c | 2 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_plane.c | 197 |
11 files changed, 638 insertions, 158 deletions
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index 17ca163..490a7f1 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -118,29 +118,35 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc) { } -static void page_flip_cb(void *arg) +static void vblank_cb(void *arg) { + static uint32_t sequence = 0; struct drm_crtc *crtc = arg; struct drm_device *dev = crtc->dev; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_pending_vblank_event *event = omap_crtc->event; - struct drm_framebuffer *old_fb = omap_crtc->old_fb; - struct timeval now; unsigned long flags; + struct timeval now; WARN_ON(!event); omap_crtc->event = NULL; - omap_crtc->old_fb = NULL; - - omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); /* wakeup userspace */ - /* TODO: this should happen *after* flip in vsync IRQ handler */ if (event) { + do_gettimeofday(&now); + spin_lock_irqsave(&dev->event_lock, flags); + /* TODO: we can't yet use the vblank time accounting, + * because omapdss lower layer is the one that knows + * the irq # and registers the handler, which more or + * less defeats how drm_irq works.. for now just fake + * the sequence number and use gettimeofday.. + * event->event.sequence = drm_vblank_count_and_time( dev, omap_crtc->id, &now); + */ + event->event.sequence = sequence++; event->event.tv_sec = now.tv_sec; event->event.tv_usec = now.tv_usec; list_add_tail(&event->base.link, @@ -150,6 +156,23 @@ static void page_flip_cb(void *arg) } } +static void page_flip_cb(void *arg) +{ + struct drm_crtc *crtc = arg; + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_framebuffer *old_fb = omap_crtc->old_fb; + + omap_crtc->old_fb = NULL; + + omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); + + /* really we'd like to setup the callback atomically w/ setting the + * new scanout buffer to avoid getting stuck waiting an extra vblank + * cycle.. for now go for correctness and later figure out speed.. + */ + omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc); +} + static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event) diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c index da920df..2f122e0 100644 --- a/drivers/staging/omapdrm/omap_debugfs.c +++ b/drivers/staging/omapdrm/omap_debugfs.c @@ -20,23 +20,118 @@ #include "omap_drv.h" #include "omap_dmm_tiler.h" +#include "drm_fb_helper.h" + + #ifdef CONFIG_DEBUG_FS +static int gem_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct omap_drm_private *priv = dev->dev_private; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(m, "All Objects:\n"); + omap_gem_describe_objects(&priv->obj_list, m); + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +static int mm_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + return drm_mm_dump_table(m, dev->mm_private); +} + +static int fb_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct omap_drm_private *priv = dev->dev_private; + struct drm_framebuffer *fb; + int ret; + + ret = mutex_lock_interruptible(&dev->mode_config.mutex); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) { + mutex_unlock(&dev->mode_config.mutex); + return ret; + } + + seq_printf(m, "fbcon "); + omap_framebuffer_describe(priv->fbdev->fb, m); + + list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + if (fb == priv->fbdev->fb) + continue; + + seq_printf(m, "user "); + omap_framebuffer_describe(fb, m); + } + + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->mode_config.mutex); + + return 0; +} + +/* list of debufs files that are applicable to all devices */ static struct drm_info_list omap_debugfs_list[] = { + {"gem", gem_show, 0}, + {"mm", mm_show, 0}, + {"fb", fb_show, 0}, +}; + +/* list of debugfs files that are specific to devices with dmm/tiler */ +static struct drm_info_list omap_dmm_debugfs_list[] = { {"tiler_map", tiler_map_show, 0}, }; int omap_debugfs_init(struct drm_minor *minor) { - return drm_debugfs_create_files(omap_debugfs_list, + struct drm_device *dev = minor->dev; + int ret; + + ret = drm_debugfs_create_files(omap_debugfs_list, ARRAY_SIZE(omap_debugfs_list), minor->debugfs_root, minor); + + if (ret) { + dev_err(dev->dev, "could not install omap_debugfs_list\n"); + return ret; + } + + if (dmm_is_available()) + ret = drm_debugfs_create_files(omap_dmm_debugfs_list, + ARRAY_SIZE(omap_dmm_debugfs_list), + minor->debugfs_root, minor); + + if (ret) { + dev_err(dev->dev, "could not install omap_dmm_debugfs_list\n"); + return ret; + } + + return ret; } void omap_debugfs_cleanup(struct drm_minor *minor) { drm_debugfs_remove_files(omap_debugfs_list, ARRAY_SIZE(omap_debugfs_list), minor); + if (dmm_is_available()) + drm_debugfs_remove_files(omap_dmm_debugfs_list, + ARRAY_SIZE(omap_dmm_debugfs_list), minor); } #endif diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c index 852d944..1ecb6a7 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.c +++ b/drivers/staging/omapdrm/omap_dmm_tiler.c @@ -34,6 +34,8 @@ #include "omap_dmm_tiler.h" #include "omap_dmm_priv.h" +#define DMM_DRIVER_NAME "dmm" + /* mappings for associating views to luts */ static struct tcm *containers[TILFMT_NFORMATS]; static struct dmm *omap_dmm; @@ -465,7 +467,12 @@ size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h) return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h; } -int omap_dmm_remove(void) +bool dmm_is_initialized(void) +{ + return omap_dmm ? true : false; +} + +static int omap_dmm_remove(struct platform_device *dev) { struct tiler_block *block, *_block; int i; @@ -499,40 +506,49 @@ int omap_dmm_remove(void) if (omap_dmm->irq != -1) free_irq(omap_dmm->irq, omap_dmm); + iounmap(omap_dmm->base); kfree(omap_dmm); + omap_dmm = NULL; } return 0; } -int omap_dmm_init(struct drm_device *dev) +static int omap_dmm_probe(struct platform_device *dev) { int ret = -EFAULT, i; struct tcm_area area = {0}; u32 hwinfo, pat_geom, lut_table_size; - struct omap_drm_platform_data *pdata = dev->dev->platform_data; - - if (!pdata || !pdata->dmm_pdata) { - dev_err(dev->dev, "dmm platform data not present, skipping\n"); - return ret; - } + struct resource *mem; omap_dmm = kzalloc(sizeof(*omap_dmm), GFP_KERNEL); if (!omap_dmm) { - dev_err(dev->dev, "failed to allocate driver data section\n"); + dev_err(&dev->dev, "failed to allocate driver data section\n"); goto fail; } /* lookup hwmod data - base address and irq */ - omap_dmm->base = pdata->dmm_pdata->base; - omap_dmm->irq = pdata->dmm_pdata->irq; - omap_dmm->dev = dev->dev; + mem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&dev->dev, "failed to get base address resource\n"); + goto fail; + } + + omap_dmm->base = ioremap(mem->start, SZ_2K); if (!omap_dmm->base) { - dev_err(dev->dev, "failed to get dmm base address\n"); + dev_err(&dev->dev, "failed to get dmm base address\n"); + goto fail; + } + + omap_dmm->irq = platform_get_irq(dev, 0); + if (omap_dmm->irq < 0) { + dev_err(&dev->dev, "failed to get IRQ resource\n"); goto fail; } + omap_dmm->dev = &dev->dev; + hwinfo = readl(omap_dmm->base + DMM_PAT_HWINFO); omap_dmm->num_engines = (hwinfo >> 24) & 0x1F; omap_dmm->num_lut = (hwinfo >> 16) & 0x1F; @@ -556,7 +572,7 @@ int omap_dmm_init(struct drm_device *dev) "omap_dmm_irq_handler", omap_dmm); if (ret) { - dev_err(dev->dev, "couldn't register IRQ %d, error %d\n", + dev_err(&dev->dev, "couldn't register IRQ %d, error %d\n", omap_dmm->irq, ret); omap_dmm->irq = -1; goto fail; @@ -575,25 +591,30 @@ int omap_dmm_init(struct drm_device *dev) omap_dmm->lut = vmalloc(lut_table_size * sizeof(*omap_dmm->lut)); if (!omap_dmm->lut) { - dev_err(dev->dev, "could not allocate lut table\n"); + dev_err(&dev->dev, "could not allocate lut table\n"); ret = -ENOMEM; goto fail; } omap_dmm->dummy_page = alloc_page(GFP_KERNEL | __GFP_DMA32); if (!omap_dmm->dummy_page) { - dev_err(dev->dev, "could not allocate dummy page\n"); + dev_err(&dev->dev, "could not allocate dummy page\n"); ret = -ENOMEM; goto fail; } + + /* set dma mask for device */ + /* NOTE: this is a workaround for the hwmod not initializing properly */ + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + omap_dmm->dummy_pa = page_to_phys(omap_dmm->dummy_page); /* alloc refill memory */ - omap_dmm->refill_va = dma_alloc_coherent(dev->dev, + omap_dmm->refill_va = dma_alloc_coherent(&dev->dev, REFILL_BUFFER_SIZE * omap_dmm->num_engines, &omap_dmm->refill_pa, GFP_KERNEL); if (!omap_dmm->refill_va) { - dev_err(dev->dev, "could not allocate refill memory\n"); + dev_err(&dev->dev, "could not allocate refill memory\n"); goto fail; } @@ -602,7 +623,7 @@ int omap_dmm_init(struct drm_device *dev) omap_dmm->num_engines * sizeof(struct refill_engine), GFP_KERNEL); if (!omap_dmm->engines) { - dev_err(dev->dev, "could not allocate engines\n"); + dev_err(&dev->dev, "could not allocate engines\n"); ret = -ENOMEM; goto fail; } @@ -624,7 +645,7 @@ int omap_dmm_init(struct drm_device *dev) omap_dmm->tcm = kzalloc(omap_dmm->num_lut * sizeof(*omap_dmm->tcm), GFP_KERNEL); if (!omap_dmm->tcm) { - dev_err(dev->dev, "failed to allocate lut ptrs\n"); + dev_err(&dev->dev, "failed to allocate lut ptrs\n"); ret = -ENOMEM; goto fail; } @@ -636,7 +657,7 @@ int omap_dmm_init(struct drm_device *dev) NULL); if (!omap_dmm->tcm[i]) { - dev_err(dev->dev, "failed to allocate container\n"); + dev_err(&dev->dev, "failed to allocate container\n"); ret = -ENOMEM; goto fail; } @@ -676,7 +697,7 @@ int omap_dmm_init(struct drm_device *dev) return 0; fail: - omap_dmm_remove(); + omap_dmm_remove(dev); return ret; } @@ -766,10 +787,18 @@ int tiler_map_show(struct seq_file *s, void *arg) const char *a2d = special; const char *m2dp = m2d, *a2dp = a2d; char nice[128]; - int h_adj = omap_dmm->lut_height / ydiv; - int w_adj = omap_dmm->lut_width / xdiv; + int h_adj; + int w_adj; unsigned long flags; + if (!omap_dmm) { + /* early return if dmm/tiler device is not initialized */ + return 0; + } + + h_adj = omap_dmm->lut_height / ydiv; + w_adj = omap_dmm->lut_width / xdiv; + map = kzalloc(h_adj * sizeof(*map), GFP_KERNEL); global_map = kzalloc((w_adj + 1) * h_adj, GFP_KERNEL); @@ -828,3 +857,17 @@ error: return 0; } #endif + +struct platform_driver omap_dmm_driver = { + .probe = omap_dmm_probe, + .remove = omap_dmm_remove, + .driver = { + .owner = THIS_MODULE, + .name = DMM_DRIVER_NAME, + }, +}; + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Andy Gross <andy.gross@ti.com>"); +MODULE_DESCRIPTION("OMAP DMM/Tiler Driver"); +MODULE_ALIAS("platform:" DMM_DRIVER_NAME); diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h index f87cb65..7b1052a 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.h +++ b/drivers/staging/omapdrm/omap_dmm_tiler.h @@ -16,6 +16,7 @@ #ifndef OMAP_DMM_TILER_H #define OMAP_DMM_TILER_H +#include <plat/cpu.h> #include "omap_drv.h" #include "tcm.h" @@ -72,10 +73,6 @@ struct tiler_block { #define TIL_ADDR(x, orient, a)\ ((u32) (x) | (orient) | ((a) << SHIFT_ACC_MODE)) -/* externally accessible functions */ -int omap_dmm_init(struct drm_device *dev); -int omap_dmm_remove(void); - #ifdef CONFIG_DEBUG_FS int tiler_map_show(struct seq_file *s, void *arg); #endif @@ -97,7 +94,9 @@ uint32_t tiler_stride(enum tiler_fmt fmt); size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h); size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h); void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h); +bool dmm_is_initialized(void); +extern struct platform_driver omap_dmm_driver; /* GEM bo flags -> tiler fmt */ static inline enum tiler_fmt gem2fmt(uint32_t flags) @@ -127,9 +126,9 @@ static inline bool validfmt(enum tiler_fmt fmt) } } -struct omap_dmm_platform_data { - void __iomem *base; - int irq; -}; +static inline int dmm_is_available(void) +{ + return cpu_is_omap44xx(); +} #endif diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 3bbea9a..3df5b4c 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -21,6 +21,7 @@ #include "drm_crtc_helper.h" #include "drm_fb_helper.h" +#include "omap_dmm_tiler.h" #define DRIVER_NAME MODULE_NAME #define DRIVER_DESC "OMAP DRM" @@ -570,6 +571,11 @@ static int dev_load(struct drm_device *dev, unsigned long flags) dev->dev_private = priv; + priv->wq = alloc_workqueue("omapdrm", + WQ_UNBOUND | WQ_NON_REENTRANT, 1); + + INIT_LIST_HEAD(&priv->obj_list); + omap_gem_init(dev); ret = omap_modeset_init(dev); @@ -598,6 +604,8 @@ static int dev_load(struct drm_device *dev, unsigned long flags) static int dev_unload(struct drm_device *dev) { + struct omap_drm_private *priv = dev->dev_private; + DBG("unload: dev=%p", dev); drm_vblank_cleanup(dev); @@ -607,6 +615,9 @@ static int dev_unload(struct drm_device *dev) omap_modeset_free(dev); omap_gem_deinit(dev); + flush_workqueue(priv->wq); + destroy_workqueue(priv->wq); + kfree(dev->dev_private); dev->dev_private = NULL; @@ -792,6 +803,9 @@ static void pdev_shutdown(struct platform_device *device) static int pdev_probe(struct platform_device *device) { DBG("%s", device->name); + if (platform_driver_register(&omap_dmm_driver)) + dev_err(&device->dev, "DMM registration failed\n"); + return drm_platform_init(&omap_drm_driver, device); } @@ -799,6 +813,8 @@ static int pdev_remove(struct platform_device *device) { DBG(""); drm_platform_exit(&omap_drm_driver, device); + + platform_driver_unregister(&omap_dmm_driver); return 0; } diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 61fe022..b7e0f07 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -42,21 +42,31 @@ struct omap_drm_private { unsigned int num_crtcs; struct drm_crtc *crtcs[8]; + unsigned int num_planes; struct drm_plane *planes[8]; + unsigned int num_encoders; struct drm_encoder *encoders[8]; + unsigned int num_connectors; struct drm_connector *connectors[8]; struct drm_fb_helper *fbdev; + struct workqueue_struct *wq; + + struct list_head obj_list; + bool has_dmm; }; #ifdef CONFIG_DEBUG_FS int omap_debugfs_init(struct drm_minor *minor); void omap_debugfs_cleanup(struct drm_minor *minor); +void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); +void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m); +void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); #endif struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); @@ -75,6 +85,8 @@ int omap_plane_mode_set(struct drm_plane *plane, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); +void omap_plane_on_endwin(struct drm_plane *plane, + void (*fxn)(void *), void *arg); struct drm_encoder *omap_encoder_init(struct drm_device *dev, struct omap_overlay_manager *mgr); @@ -92,13 +104,16 @@ void omap_connector_mode_set(struct drm_connector *connector, void omap_connector_flush(struct drm_connector *connector, int x, int y, int w, int h); +uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, + uint32_t max_formats, enum omap_color_mode supported_modes); struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd); struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); -int omap_framebuffer_pin(struct drm_framebuffer *fb); -void omap_framebuffer_unpin(struct drm_framebuffer *fb); +int omap_framebuffer_replace(struct drm_framebuffer *a, + struct drm_framebuffer *b, void *arg, + void (*unpin)(void *arg, struct drm_gem_object *bo)); void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, struct omap_overlay_info *info); struct drm_connector *omap_framebuffer_get_next_connector( diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c index d021a7e..04b235b 100644 --- a/drivers/staging/omapdrm/omap_fb.c +++ b/drivers/staging/omapdrm/omap_fb.c @@ -59,6 +59,20 @@ static const struct format formats[] = { { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true }, }; +/* convert from overlay's pixel formats bitmask to an array of fourcc's */ +uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, + uint32_t max_formats, enum omap_color_mode supported_modes) +{ + uint32_t nformats = 0; + int i = 0; + + for (i = 0; i < ARRAY_SIZE(formats) && nformats < max_formats; i++) + if (formats[i].dss_format & supported_modes) + pixel_formats[nformats++] = formats[i].pixel_format; + + return nformats; +} + /* per-plane info for the fb: */ struct plane { struct drm_gem_object *bo; @@ -87,7 +101,7 @@ static int omap_framebuffer_create_handle(struct drm_framebuffer *fb, static void omap_framebuffer_destroy(struct drm_framebuffer *fb) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - int i, n = drm_format_num_planes(omap_fb->format->pixel_format); + int i, n = drm_format_num_planes(fb->pixel_format); DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); @@ -123,41 +137,6 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .dirty = omap_framebuffer_dirty, }; -/* pins buffer in preparation for scanout */ -int omap_framebuffer_pin(struct drm_framebuffer *fb) -{ - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - int ret, i, n = drm_format_num_planes(omap_fb->format->pixel_format); - - for (i = 0; i < n; i++) { - struct plane *plane = &omap_fb->planes[i]; - ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true); - if (ret) - goto fail; - } - - return 0; - -fail: - while (--i > 0) { - struct plane *plane = &omap_fb->planes[i]; - omap_gem_put_paddr(plane->bo); - } - return ret; -} - -/* releases buffer when done with scanout */ -void omap_framebuffer_unpin(struct drm_framebuffer *fb) -{ - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - int i, n = drm_format_num_planes(omap_fb->format->pixel_format); - - for (i = 0; i < n; i++) { - struct plane *plane = &omap_fb->planes[i]; - omap_gem_put_paddr(plane->bo); - } -} - /* update ovl info for scanout, handles cases of multi-planar fb's, etc. */ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, @@ -187,10 +166,59 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, } } +/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although + * buffers to unpin are just just pushed to the unpin fifo so that the + * caller can defer unpin until vblank. + * + * Note if this fails (ie. something went very wrong!), all buffers are + * unpinned, and the caller disables the overlay. We could have tried + * to revert back to the previous set of pinned buffers but if things are + * hosed there is no guarantee that would succeed. + */ +int omap_framebuffer_replace(struct drm_framebuffer *a, + struct drm_framebuffer *b, void *arg, + void (*unpin)(void *arg, struct drm_gem_object *bo)) +{ + int ret = 0, i, na, nb; + struct omap_framebuffer *ofba = to_omap_framebuffer(a); + struct omap_framebuffer *ofbb = to_omap_framebuffer(b); + + na = a ? drm_format_num_planes(a->pixel_format) : 0; + nb = b ? drm_format_num_planes(b->pixel_format) : 0; + + for (i = 0; i < max(na, nb); i++) { + struct plane *pa, *pb; + + pa = (i < na) ? &ofba->planes[i] : NULL; + pb = (i < nb) ? &ofbb->planes[i] : NULL; + + if (pa) { + unpin(arg, pa->bo); + pa->paddr = 0; + } + + if (pb && !ret) + ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true); + } + + if (ret) { + /* something went wrong.. unpin what has been pinned */ + for (i = 0; i < nb; i++) { + struct plane *pb = &ofba->planes[i]; + if (pb->paddr) { + unpin(arg, pb->bo); + pb->paddr = 0; + } + } + } + + return ret; +} + struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - if (p >= drm_format_num_planes(omap_fb->format->pixel_format)) + if (p >= drm_format_num_planes(fb->pixel_format)) return NULL; return omap_fb->planes[p].bo; } @@ -249,6 +277,24 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb, } } +#ifdef CONFIG_DEBUG_FS +void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + int i, n = drm_format_num_planes(fb->pixel_format); + + seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, + (char *)&fb->pixel_format); + + for (i = 0; i < n; i++) { + struct plane *plane = &omap_fb->planes[i]; + seq_printf(m, " %d: offset=%d pitch=%d, obj: ", + i, plane->offset, plane->pitch); + omap_gem_describe(plane->bo, m); + } +} +#endif + struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd) { @@ -337,8 +383,8 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, plane->bo = bos[i]; plane->offset = mode_cmd->offsets[i]; - plane->pitch = mode_cmd->pitches[i]; - plane->paddr = pitch; + plane->pitch = pitch; + plane->paddr = 0; } drm_helper_mode_fill_fb_struct(fb, mode_cmd); diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c index 96940bb..11acd4c 100644 --- a/drivers/staging/omapdrm/omap_fbdev.c +++ b/drivers/staging/omapdrm/omap_fbdev.c @@ -37,6 +37,9 @@ struct omap_fbdev { struct drm_framebuffer *fb; struct drm_gem_object *bo; bool ywrap_enabled; + + /* for deferred dmm roll when getting called in atomic ctx */ + struct work_struct work; }; static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h); @@ -75,12 +78,22 @@ static void omap_fbdev_imageblit(struct fb_info *fbi, image->width, image->height); } +static void pan_worker(struct work_struct *work) +{ + struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work); + struct fb_info *fbi = fbdev->base.fbdev; + int npages; + + /* DMM roll shifts in 4K pages: */ + npages = fbi->fix.line_length >> PAGE_SHIFT; + omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages); +} + static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) { struct drm_fb_helper *helper = get_fb(fbi); struct omap_fbdev *fbdev = to_omap_fbdev(helper); - int npages; if (!helper) goto fallback; @@ -88,9 +101,12 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, if (!fbdev->ywrap_enabled) goto fallback; - /* DMM roll shifts in 4K pages: */ - npages = fbi->fix.line_length >> PAGE_SHIFT; - omap_gem_roll(fbdev->bo, var->yoffset * npages); + if (drm_can_sleep()) { + pan_worker(&fbdev->work); + } else { + struct omap_drm_private *priv = helper->dev->dev_private; + queue_work(priv->wq, &fbdev->work); + } return 0; @@ -336,6 +352,8 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) goto fail; } + INIT_WORK(&fbdev->work, pan_worker); + helper = &fbdev->base; helper->funcs = &omap_fb_helper_funcs; diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index b7d6f88..921f058 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -45,6 +45,8 @@ int _drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size); struct omap_gem_object { struct drm_gem_object base; + struct list_head mm_list; + uint32_t flags; /** width/height for tiled formats (rounded up to slot boundaries) */ @@ -151,10 +153,23 @@ static void evict_entry(struct drm_gem_object *obj, enum tiler_fmt fmt, struct usergart_entry *entry) { if (obj->dev->dev_mapping) { - size_t size = PAGE_SIZE * usergart[fmt].height; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int n = usergart[fmt].height; + size_t size = PAGE_SIZE * n; loff_t off = mmap_offset(obj) + (entry->obj_pgoff << PAGE_SHIFT); - unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); + const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + if (m > 1) { + int i; + /* if stride > than PAGE_SIZE then sparse mapping: */ + for (i = n; i > 0; i--) { + unmap_mapping_range(obj->dev->dev_mapping, + off, PAGE_SIZE, 1); + off += PAGE_SIZE * m; + } + } else { + unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); + } } entry->obj = NULL; @@ -254,13 +269,17 @@ static void omap_gem_detach_pages(struct drm_gem_object *obj) /** get mmap offset */ static uint64_t mmap_offset(struct drm_gem_object *obj) { + struct drm_device *dev = obj->dev; + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + if (!obj->map_list.map) { /* Make it mmapable */ size_t size = omap_gem_mmap_size(obj); int ret = _drm_gem_create_mmap_offset_size(obj, size); if (ret) { - dev_err(obj->dev->dev, "could not allocate mmap offset"); + dev_err(dev->dev, "could not allocate mmap offset\n"); return 0; } } @@ -336,26 +355,39 @@ static int fault_2d(struct drm_gem_object *obj, void __user *vaddr; int i, ret, slots; - if (!usergart) - return -EFAULT; - - /* TODO: this fxn might need a bit tweaking to deal w/ tiled buffers - * that are wider than 4kb + /* + * Note the height of the slot is also equal to the number of pages + * that need to be mapped in to fill 4kb wide CPU page. If the slot + * height is 64, then 64 pages fill a 4kb wide by 64 row region. + */ + const int n = usergart[fmt].height; + const int n_shift = usergart[fmt].height_shift; + + /* + * If buffer width in bytes > PAGE_SIZE then the virtual stride is + * rounded up to next multiple of PAGE_SIZE.. this need to be taken + * into account in some of the math, so figure out virtual stride + * in pages */ + const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); /* We don't use vmf->pgoff since that has the fake offset: */ pgoff = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - /* actual address we start mapping at is rounded down to previous slot + /* + * Actual address we start mapping at is rounded down to previous slot * boundary in the y direction: */ - base_pgoff = round_down(pgoff, usergart[fmt].height); - vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT); - entry = &usergart[fmt].entry[usergart[fmt].last]; + base_pgoff = round_down(pgoff, m << n_shift); + /* figure out buffer width in slots */ slots = omap_obj->width >> usergart[fmt].slot_shift; + vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT); + + entry = &usergart[fmt].entry[usergart[fmt].last]; + /* evict previous buffer using this usergart entry, if any: */ if (entry->obj) evict_entry(entry->obj, fmt, entry); @@ -363,23 +395,30 @@ static int fault_2d(struct drm_gem_object *obj, entry->obj = obj; entry->obj_pgoff = base_pgoff; - /* now convert base_pgoff to phys offset from virt offset: - */ - base_pgoff = (base_pgoff >> usergart[fmt].height_shift) * slots; - - /* map in pages. Note the height of the slot is also equal to the - * number of pages that need to be mapped in to fill 4kb wide CPU page. - * If the height is 64, then 64 pages fill a 4kb wide by 64 row region. - * Beyond the valid pixel part of the buffer, we set pages[i] to NULL to - * get a dummy page mapped in.. if someone reads/writes it they will get - * random/undefined content, but at least it won't be corrupting - * whatever other random page used to be mapped in, or other undefined - * behavior. + /* now convert base_pgoff to phys offset from virt offset: */ + base_pgoff = (base_pgoff >> n_shift) * slots; + + /* for wider-than 4k.. figure out which part of the slot-row we want: */ + if (m > 1) { + int off = pgoff % m; + entry->obj_pgoff += off; + base_pgoff /= m; + slots = min(slots - (off << n_shift), n); + base_pgoff += off << n_shift; + vaddr += off << PAGE_SHIFT; + } + + /* + * Map in pages. Beyond the valid pixel part of the buffer, we set + * pages[i] to NULL to get a dummy page mapped in.. if someone + * reads/writes it they will get random/undefined content, but at + * least it won't be corrupting whatever other random page used to + * be mapped in, or other undefined behavior. */ memcpy(pages, &omap_obj->pages[base_pgoff], sizeof(struct page *) * slots); memset(pages + slots, 0, - sizeof(struct page *) * (usergart[fmt].height - slots)); + sizeof(struct page *) * (n - slots)); ret = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true); if (ret) { @@ -387,16 +426,15 @@ static int fault_2d(struct drm_gem_object *obj, return ret; } - i = usergart[fmt].height; pfn = entry->paddr >> PAGE_SHIFT; VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, pfn, pfn << PAGE_SHIFT); - while (i--) { + for (i = n; i > 0; i--) { vm_insert_mixed(vma, (unsigned long)vaddr, pfn); pfn += usergart[fmt].stride_pfn; - vaddr += PAGE_SIZE; + vaddr += PAGE_SIZE * m; } /* simple round-robin: */ @@ -566,6 +604,8 @@ fail: /* Set scrolling position. This allows us to implement fast scrolling * for console. + * + * Call only from non-atomic contexts. */ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) { @@ -580,18 +620,6 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) omap_obj->roll = roll; - if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) { - /* this can get called from fbcon in atomic context.. so - * just ignore it and wait for next time called from - * interruptible context to update the PAT.. the result - * may be that user sees wrap-around instead of scrolling - * momentarily on the screen. If we wanted to be fancier - * we could perhaps schedule some workqueue work at this - * point. - */ - return 0; - } - mutex_lock(&obj->dev->struct_mutex); /* if we aren't mapped yet, we don't need to do anything */ @@ -774,6 +802,56 @@ void *omap_gem_vaddr(struct drm_gem_object *obj) return omap_obj->vaddr; } +#ifdef CONFIG_DEBUG_FS +void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) +{ + struct drm_device *dev = obj->dev; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + uint64_t off = 0; + + WARN_ON(! mutex_is_locked(&dev->struct_mutex)); + + if (obj->map_list.map) + off = (uint64_t)obj->map_list.hash.key; + + seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", + omap_obj->flags, obj->name, obj->refcount.refcount.counter, + off, omap_obj->paddr, omap_obj->paddr_cnt, + omap_obj->vaddr, omap_obj->roll); + + if (omap_obj->flags & OMAP_BO_TILED) { + seq_printf(m, " %dx%d", omap_obj->width, omap_obj->height); + if (omap_obj->block) { + struct tcm_area *area = &omap_obj->block->area; + seq_printf(m, " (%dx%d, %dx%d)", + area->p0.x, area->p0.y, + area->p1.x, area->p1.y); + } + } else { + seq_printf(m, " %d", obj->size); + } + + seq_printf(m, "\n"); +} + +void omap_gem_describe_objects(struct list_head *list, struct seq_file *m) +{ + struct omap_gem_object *omap_obj; + int count = 0; + size_t size = 0; + + list_for_each_entry(omap_obj, list, mm_list) { + struct drm_gem_object *obj = &omap_obj->base; + seq_printf(m, " "); + omap_gem_describe(obj, m); + count++; + size += obj->size; + } + + seq_printf(m, "Total %d objects, %zu bytes\n", count, size); +} +#endif + /* Buffer Synchronization: */ @@ -1040,6 +1118,10 @@ void omap_gem_free_object(struct drm_gem_object *obj) evict(obj); + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + list_del(&omap_obj->mm_list); + if (obj->map_list.map) { drm_gem_free_mmap_offset(obj); } @@ -1140,6 +1222,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, goto fail; } + list_add(&omap_obj->mm_list, &priv->obj_list); + obj = &omap_obj->base; if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { @@ -1186,12 +1270,11 @@ void omap_gem_init(struct drm_device *dev) const enum tiler_fmt fmts[] = { TILFMT_8BIT, TILFMT_16BIT, TILFMT_32BIT }; - int i, j, ret; + int i, j; - ret = omap_dmm_init(dev); - if (ret) { + if (!dmm_is_initialized()) { /* DMM only supported on OMAP4 and later, so this isn't fatal */ - dev_warn(dev->dev, "omap_dmm_init failed, disabling DMM\n"); + dev_warn(dev->dev, "DMM not available, disable DMM support\n"); return; } @@ -1241,6 +1324,5 @@ void omap_gem_deinit(struct drm_device *dev) /* I believe we can rely on there being no more outstanding GEM * objects which could depend on usergart/dmm at this point. */ - omap_dmm_remove(); kfree(usergart); } diff --git a/drivers/staging/omapdrm/omap_gem_helpers.c b/drivers/staging/omapdrm/omap_gem_helpers.c index 29275c7..f895363 100644 --- a/drivers/staging/omapdrm/omap_gem_helpers.c +++ b/drivers/staging/omapdrm/omap_gem_helpers.c @@ -84,7 +84,7 @@ fail: page_cache_release(pages[i]); } drm_free_large(pages); - return ERR_PTR(PTR_ERR(p)); + return ERR_CAST(p); } /** diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index 9790912..7997be7 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c @@ -17,6 +17,8 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/kfifo.h> + #include "omap_drv.h" /* some hackery because omapdss has an 'enum omap_plane' (which would be @@ -29,6 +31,11 @@ * plane funcs */ +struct callback { + void (*fxn)(void *); + void *arg; +}; + #define to_omap_plane(x) container_of(x, struct omap_plane, base) struct omap_plane { @@ -43,8 +50,84 @@ struct omap_plane { /* last fb that we pinned: */ struct drm_framebuffer *pinned_fb; + + uint32_t nformats; + uint32_t formats[32]; + + /* for synchronizing access to unpins fifo */ + struct mutex unpin_mutex; + + /* set of bo's pending unpin until next END_WIN irq */ + DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); + int num_unpins, pending_num_unpins; + + /* for deferred unpin when we need to wait for scanout complete irq */ + struct work_struct work; + + /* callback on next endwin irq */ + struct callback endwin; }; +/* map from ovl->id to the irq we are interested in for scanout-done */ +static const uint32_t id2irq[] = { + [OMAP_DSS_GFX] = DISPC_IRQ_GFX_END_WIN, + [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN, + [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN, + [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN, +}; + +static void dispc_isr(void *arg, uint32_t mask) +{ + struct drm_plane *plane = arg; + struct omap_plane *omap_plane = to_omap_plane(plane); + struct omap_drm_private *priv = plane->dev->dev_private; + + omap_dispc_unregister_isr(dispc_isr, plane, + id2irq[omap_plane->ovl->id]); + + queue_work(priv->wq, &omap_plane->work); +} + +static void unpin_worker(struct work_struct *work) +{ + struct omap_plane *omap_plane = + container_of(work, struct omap_plane, work); + struct callback endwin; + + mutex_lock(&omap_plane->unpin_mutex); + DBG("unpinning %d of %d", omap_plane->num_unpins, + omap_plane->num_unpins + omap_plane->pending_num_unpins); + while (omap_plane->num_unpins > 0) { + struct drm_gem_object *bo = NULL; + int ret = kfifo_get(&omap_plane->unpin_fifo, &bo); + WARN_ON(!ret); + omap_gem_put_paddr(bo); + drm_gem_object_unreference_unlocked(bo); + omap_plane->num_unpins--; + } + endwin = omap_plane->endwin; + omap_plane->endwin.fxn = NULL; + mutex_unlock(&omap_plane->unpin_mutex); + + if (endwin.fxn) + endwin.fxn(endwin.arg); +} + +static void install_irq(struct drm_plane *plane) +{ + struct omap_plane *omap_plane = to_omap_plane(plane); + struct omap_overlay *ovl = omap_plane->ovl; + int ret; + + ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]); + + /* + * omapdss has upper limit on # of registered irq handlers, + * which we shouldn't hit.. but if we do the limit should + * be raised or bad things happen: + */ + WARN_ON(ret == -EBUSY); +} /* push changes down to dss2 */ static int commit(struct drm_plane *plane) @@ -71,6 +154,11 @@ static int commit(struct drm_plane *plane) return ret; } + mutex_lock(&omap_plane->unpin_mutex); + omap_plane->num_unpins += omap_plane->pending_num_unpins; + omap_plane->pending_num_unpins = 0; + mutex_unlock(&omap_plane->unpin_mutex); + /* our encoder doesn't necessarily get a commit() after this, in * particular in the dpms() and mode_set_base() cases, so force the * manager to update: @@ -83,8 +171,20 @@ static int commit(struct drm_plane *plane) dev_err(dev->dev, "could not apply settings\n"); return ret; } + + /* + * NOTE: really this should be atomic w/ mgr->apply() but + * omapdss does not expose such an API + */ + if (omap_plane->num_unpins > 0) + install_irq(plane); + + } else { + struct omap_drm_private *priv = dev->dev_private; + queue_work(priv->wq, &omap_plane->work); } + if (ovl->is_enabled(ovl)) { omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, info->out_width, info->out_height); @@ -137,21 +237,48 @@ static void update_manager(struct drm_plane *plane) } } +static void unpin(void *arg, struct drm_gem_object *bo) +{ + struct drm_plane *plane = arg; + struct omap_plane *omap_plane = to_omap_plane(plane); + + if (kfifo_put(&omap_plane->unpin_fifo, + (const struct drm_gem_object **)&bo)) { + omap_plane->pending_num_unpins++; + /* also hold a ref so it isn't free'd while pinned */ + drm_gem_object_reference(bo); + } else { + dev_err(plane->dev->dev, "unpin fifo full!\n"); + omap_gem_put_paddr(bo); + } +} + /* update which fb (if any) is pinned for scanout */ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) { struct omap_plane *omap_plane = to_omap_plane(plane); - int ret = 0; + struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb; + + if (pinned_fb != fb) { + int ret; + + DBG("%p -> %p", pinned_fb, fb); + + mutex_lock(&omap_plane->unpin_mutex); + ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); + mutex_unlock(&omap_plane->unpin_mutex); + + if (ret) { + dev_err(plane->dev->dev, "could not swap %p -> %p\n", + omap_plane->pinned_fb, fb); + omap_plane->pinned_fb = NULL; + return ret; + } - if (omap_plane->pinned_fb != fb) { - if (omap_plane->pinned_fb) - omap_framebuffer_unpin(omap_plane->pinned_fb); omap_plane->pinned_fb = fb; - if (fb) - ret = omap_framebuffer_pin(fb); } - return ret; + return 0; } /* update parameters that are dependent on the framebuffer dimensions and @@ -241,6 +368,8 @@ static void omap_plane_destroy(struct drm_plane *plane) DBG("%s", omap_plane->ovl->name); omap_plane_disable(plane); drm_plane_cleanup(plane); + WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0); + kfifo_free(&omap_plane->unpin_fifo); kfree(omap_plane); } @@ -258,37 +387,34 @@ int omap_plane_dpms(struct drm_plane *plane, int mode) if (!r) r = ovl->enable(ovl); } else { + struct omap_drm_private *priv = plane->dev->dev_private; r = ovl->disable(ovl); update_pin(plane, NULL); + queue_work(priv->wq, &omap_plane->work); } return r; } +void omap_plane_on_endwin(struct drm_plane *plane, + void (*fxn)(void *), void *arg) +{ + struct omap_plane *omap_plane = to_omap_plane(plane); + + mutex_lock(&omap_plane->unpin_mutex); + omap_plane->endwin.fxn = fxn; + omap_plane->endwin.arg = arg; + mutex_unlock(&omap_plane->unpin_mutex); + + install_irq(plane); +} + static const struct drm_plane_funcs omap_plane_funcs = { .update_plane = omap_plane_update, .disable_plane = omap_plane_disable, .destroy = omap_plane_destroy, }; -static const uint32_t formats[] = { - DRM_FORMAT_RGB565, - DRM_FORMAT_RGBX4444, - DRM_FORMAT_XRGB4444, - DRM_FORMAT_RGBA4444, - DRM_FORMAT_ABGR4444, - DRM_FORMAT_XRGB1555, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_RGB888, - DRM_FORMAT_RGBX8888, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_RGBA8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_NV12, - DRM_FORMAT_YUYV, - DRM_FORMAT_UYVY, -}; - /* initialize plane */ struct drm_plane *omap_plane_init(struct drm_device *dev, struct omap_overlay *ovl, unsigned int possible_crtcs, @@ -296,21 +422,38 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, { struct drm_plane *plane = NULL; struct omap_plane *omap_plane; + int ret; DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name, possible_crtcs, priv); + /* friendly reminder to update table for future hw: */ + WARN_ON(ovl->id >= ARRAY_SIZE(id2irq)); + omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); if (!omap_plane) { dev_err(dev->dev, "could not allocate plane\n"); goto fail; } + mutex_init(&omap_plane->unpin_mutex); + + ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); + if (ret) { + dev_err(dev->dev, "could not allocate unpin FIFO\n"); + goto fail; + } + + INIT_WORK(&omap_plane->work, unpin_worker); + + omap_plane->nformats = omap_framebuffer_get_formats( + omap_plane->formats, ARRAY_SIZE(omap_plane->formats), + ovl->supported_modes); omap_plane->ovl = ovl; plane = &omap_plane->base; drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs, - formats, ARRAY_SIZE(formats), priv); + omap_plane->formats, omap_plane->nformats, priv); /* get our starting configuration, set defaults for parameters * we don't currently use, etc: @@ -330,7 +473,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, if (priv) omap_plane->info.zorder = 0; else - omap_plane->info.zorder = 1; + omap_plane->info.zorder = ovl->id; update_manager(plane); |