static int codec_lockbuf(struct dce_file_priv *priv, uint32_t codec_handle, int32_t id, struct drm_gem_object *y, struct drm_gem_object *uv) { struct dce_codec *codec = &priv->codecs[codec_handle-1]; int i; for (i = 0; i < ARRAY_SIZE(codec->locked_buffers); i++) { struct dce_buffer *buf = &codec->locked_buffers[i]; if (buf->id == 0) { dma_addr_t paddr; DBG("lock[%d]: y=%p, uv=%p", id, y, uv); /* for now, until the codecs support relocated buffers, keep * an extra ref and paddr to keep it pinned */ drm_gem_object_reference(y); omap_gem_get_paddr(y, &paddr, true); if (uv) { drm_gem_object_reference(uv); omap_gem_get_paddr(uv, &paddr, true); } buf->id = id; buf->y = y; buf->uv = uv; return 0; } } dev_err(priv->dev->dev, "too many locked buffers!\n"); return -ENOMEM; }
/* 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; }
/* GEM buffer -> paddr, plus add the buffer to the txn bookkeeping of * associated buffers that eventually need to be cleaned up when the * transaction completes */ static struct drm_gem_object * get_paddr(struct dce_file_priv *priv, struct dce_rpc_hdr *req, uint32_t *paddrp, int bo) { struct omap_dce_txn *txn = &txns[req->req_id % ARRAY_SIZE(txns)]; struct drm_gem_object *obj; dma_addr_t paddr; int ret; long t; if (txn->bo_count >= ARRAY_SIZE(txn->objs)) { DBG("too many buffers!"); return ERR_PTR(-ENOMEM); } obj = drm_gem_object_lookup(priv->dev, priv->file, bo); if (!obj) { DBG("bad handle: %d", bo); return ERR_PTR(-ENOENT); } t = mark(NULL); ret = omap_gem_get_paddr(obj, &paddr, true); DBG("get_paddr in %ld us", mark(&t)); if (ret) { DBG("cannot map: %d", ret); return ERR_PTR(ret); } /* the coproc can only see 32bit addresses.. this might need * to be revisited in the future with some conversion between * device address and host address. But currently they are * the same. */ *paddrp = (uint32_t)paddr; txn->objs[txn->bo_count++] = obj; DBG("obj=%p", obj); return obj; }
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; }
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo) { struct omap_framebuffer *omap_fb; struct drm_framebuffer *fb = NULL; int size, ret; DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%d)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, mode_cmd->bpp); /* in case someone tries to feed us a completely bogus stride: */ mode_cmd->pitch = align_pitch(mode_cmd->pitch, mode_cmd->width, mode_cmd->bpp); omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); if (!omap_fb) { dev_err(dev->dev, "could not allocate fb\n"); goto fail; } fb = &omap_fb->base; ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); goto fail; } DBG("create: FB ID: %d (%p)", fb->base.id, fb); size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height); if (bo) { DBG("using existing %d byte buffer (needed %d)", bo->size, size); if (size > bo->size) { dev_err(dev->dev, "provided buffer object is too small!\n"); goto fail; } } else { /* for convenience of all the various callers who don't want * to be bothered to allocate their own buffer.. */ union omap_gem_size gsize = { .bytes = size, }; DBG("allocating %d bytes for fb %d", size, dev->primary->index); bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); if (!bo) { dev_err(dev->dev, "failed to allocate buffer object\n"); goto fail; } } omap_fb->bo = bo; omap_fb->size = size; if (omap_gem_get_paddr(bo, &omap_fb->paddr, true)) { dev_err(dev->dev, "could not map (paddr)!\n"); goto fail; } drm_helper_mode_fill_fb_struct(fb, mode_cmd); return fb; fail: if (fb) { omap_framebuffer_destroy(fb); } return NULL; }