diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_fb.c')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fb.c | 98 |
1 files changed, 56 insertions, 42 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 8031402e795..2a5cacdc344 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -123,12 +123,16 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb, { int i; + drm_modeset_lock_all(fb->dev); + for (i = 0; i < num_clips; i++) { omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1, clips[i].x2 - clips[i].x1, clips[i].y2 - clips[i].y1); } + drm_modeset_unlock_all(fb->dev); + return 0; } @@ -214,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, info->rotation_type = OMAP_DSS_ROT_TILER; info->screen_width = omap_gem_tiled_stride(plane->bo, orient); } else { + switch (win->rotation & 0xf) { + case 0: + case BIT(DRM_ROTATE_0): + /* OK */ + break; + + default: + dev_warn(fb->dev->dev, + "rotation '%d' ignored for non-tiled fb\n", + win->rotation); + win->rotation = 0; + break; + } + info->paddr = get_linear_addr(plane, format, 0, x, y); info->rotation_type = OMAP_DSS_ROT_DMA; info->screen_width = plane->pitch; @@ -237,55 +255,49 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, } } -/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although - * buffers to unpin are 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)) +/* pin, prepare for scanout: */ +int omap_framebuffer_pin(struct drm_framebuffer *fb) { - int ret = 0, i, na, nb; - struct omap_framebuffer *ofba = to_omap_framebuffer(a); - struct omap_framebuffer *ofbb = to_omap_framebuffer(b); - uint32_t pinned_mask = 0; + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + int ret, i, n = drm_format_num_planes(fb->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; + omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE); + } - na = a ? drm_format_num_planes(a->pixel_format) : 0; - nb = b ? drm_format_num_planes(b->pixel_format) : 0; + return 0; - for (i = 0; i < max(na, nb); i++) { - struct plane *pa, *pb; +fail: + for (i--; i >= 0; i--) { + struct plane *plane = &omap_fb->planes[i]; + omap_gem_put_paddr(plane->bo); + plane->paddr = 0; + } - pa = (i < na) ? &ofba->planes[i] : NULL; - pb = (i < nb) ? &ofbb->planes[i] : NULL; + return ret; +} - if (pa) - unpin(arg, pa->bo); +/* unpin, no longer being scanned out: */ +int omap_framebuffer_unpin(struct drm_framebuffer *fb) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + int ret, i, n = drm_format_num_planes(fb->pixel_format); - if (pb && !ret) { - ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true); - if (!ret) { - omap_gem_dma_sync(pb->bo, DMA_TO_DEVICE); - pinned_mask |= (1 << i); - } - } + for (i = 0; i < n; i++) { + struct plane *plane = &omap_fb->planes[i]; + ret = omap_gem_put_paddr(plane->bo); + if (ret) + goto fail; + plane->paddr = 0; } - if (ret) { - /* something went wrong.. unpin what has been pinned */ - for (i = 0; i < nb; i++) { - if (pinned_mask & (1 << i)) { - struct plane *pb = &ofba->planes[i]; - unpin(arg, pb->bo); - } - } - } + return 0; +fail: return ret; } @@ -308,13 +320,14 @@ struct drm_connector *omap_framebuffer_get_next_connector( struct drm_connector *connector = from; if (!from) - return list_first_entry(connector_list, typeof(*from), head); + return list_first_entry_or_null(connector_list, typeof(*from), + head); list_for_each_entry_from(connector, connector_list, head) { if (connector != from) { struct drm_encoder *encoder = connector->encoder; struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; - if (crtc && crtc->fb == fb) + if (crtc && crtc->primary->fb == fb) return connector; } @@ -333,6 +346,7 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb, VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb); + /* FIXME: This is racy - no protection against modeset config changes. */ while ((connector = omap_framebuffer_get_next_connector(fb, connector))) { /* only consider connectors that are part of a chain */ if (connector->encoder && connector->encoder->crtc) { |
