/* pin, prepare 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(fb->pixel_format); if (omap_fb->pin_count > 0) { omap_fb->pin_count++; return 0; } 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); } omap_fb->pin_count++; return 0; fail: for (i--; i >= 0; i--) { struct plane *plane = &omap_fb->planes[i]; omap_gem_put_paddr(plane->bo); plane->paddr = 0; } return ret; }
/* 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)) { 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; 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); 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); } } } 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 ret; }
static struct sg_table *omap_gem_map_dma_buf( struct dma_buf_attachment *attachment, enum dma_data_direction dir) { struct drm_gem_object *obj = attachment->dmabuf->priv; struct sg_table *sg; dma_addr_t paddr; int ret; sg = kzalloc(sizeof(*sg), GFP_KERNEL); if (!sg) return ERR_PTR(-ENOMEM); /* camera, etc, need physically contiguous.. but we need a * better way to know this.. */ ret = omap_gem_get_paddr(obj, &paddr, true); if (ret) goto out; ret = sg_alloc_table(sg, 1, GFP_KERNEL); if (ret) goto out; sg_init_table(sg->sgl, 1); sg_dma_len(sg->sgl) = obj->size; sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0); sg_dma_address(sg->sgl) = paddr; /* this should be after _get_paddr() to ensure we have pages attached */ omap_gem_dma_sync(obj, dir); out: if (ret) return ERR_PTR(ret); return sg; }