static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, enum dma_data_direction dir) { struct drm_gem_object *obj = buffer->priv; struct page **pages; if (omap_gem_flags(obj) & OMAP_BO_TILED) { /* TODO we would need to pin at least part of the buffer to * get de-tiled view. For now just reject it. */ return -ENOMEM; } /* make sure we have the pages: */ return omap_gem_get_pages(obj, &pages, true); }
/* update ovl info for scanout, handles cases of multi-planar fb's, etc. */ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_drm_window *win, struct omap_overlay_info *info) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); const struct format *format = omap_fb->format; struct plane *plane = &omap_fb->planes[0]; uint32_t x, y, orient = 0; info->color_mode = format->dss_format; info->pos_x = win->crtc_x; info->pos_y = win->crtc_y; info->out_width = win->crtc_w; info->out_height = win->crtc_h; info->width = win->src_w; info->height = win->src_h; x = win->src_x; y = win->src_y; if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { uint32_t w = win->src_w; uint32_t h = win->src_h; switch (win->rotation & 0xf) { default: dev_err(fb->dev->dev, "invalid rotation: %02x", (uint32_t)win->rotation); /* fallthru to default to no rotation */ case 0: case BIT(DRM_ROTATE_0): orient = 0; break; case BIT(DRM_ROTATE_90): orient = MASK_XY_FLIP | MASK_X_INVERT; break; case BIT(DRM_ROTATE_180): orient = MASK_X_INVERT | MASK_Y_INVERT; break; case BIT(DRM_ROTATE_270): orient = MASK_XY_FLIP | MASK_Y_INVERT; break; } if (win->rotation & BIT(DRM_REFLECT_X)) orient ^= MASK_X_INVERT; if (win->rotation & BIT(DRM_REFLECT_Y)) orient ^= MASK_Y_INVERT; /* adjust x,y offset for flip/invert: */ if (orient & MASK_XY_FLIP) swap(w, h); if (orient & MASK_Y_INVERT) y += h - 1; if (orient & MASK_X_INVERT) x += w - 1; omap_gem_rotated_paddr(plane->bo, orient, x, y, &info->paddr); info->rotation_type = OMAP_DSS_ROT_TILER; info->screen_width = omap_gem_tiled_stride(plane->bo, orient); } else { info->paddr = get_linear_addr(plane, format, 0, x, y); info->rotation_type = OMAP_DSS_ROT_DMA; info->screen_width = plane->pitch; } /* convert to pixels: */ info->screen_width /= format->planes[0].stride_bpp; if (format->dss_format == OMAP_DSS_COLOR_NV12) { plane = &omap_fb->planes[1]; if (info->rotation_type == OMAP_DSS_ROT_TILER) { WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED)); omap_gem_rotated_paddr(plane->bo, orient, x/2, y/2, &info->p_uv_addr); } else { info->p_uv_addr = get_linear_addr(plane, format, 1, x, y); } } else { info->p_uv_addr = 0; } }
static int ioctl_codec_create(struct drm_device *dev, void *data, struct drm_file *file) { struct dce_file_priv *priv = omap_drm_file_priv(file, dce_mapper_id); struct drm_omap_dce_codec_create *arg = data; struct dce_rpc_codec_create_rsp *rsp; int ret; /* if we are not re-starting a syscall, send req */ if (!arg->token) { struct dce_rpc_codec_create_req req = { .hdr = MKHDR(CODEC_CREATE), .codec_id = arg->codec_id, }; strncpy(req.name, arg->name, sizeof(req.name)); ret = engine_get(priv, arg->eng_handle, &req.engine); if (ret) return ret; ret = PTR_RET(get_paddr(priv, hdr(&req), &req.sparams, arg->sparams_bo)); if (ret) goto rpsend_out; ret = rpsend(priv, &arg->token, hdr(&req), sizeof(req)); rpsend_out: if (ret) return rpabort(hdr(&req), ret); } /* then wait for reply, which is interruptible */ ret = rpwait(priv, arg->token, hdr(&rsp), sizeof(*rsp)); if (ret) return ret; arg->codec_handle = codec_register(priv, rsp->codec, arg->codec_id); if (!codec_valid(priv, arg->codec_handle)) { codec_delete(priv, rsp->codec, arg->codec_id); ret = -ENOMEM; } kfree(rsp); return ret; } static int ioctl_codec_control(struct drm_device *dev, void *data, struct drm_file *file) { struct dce_file_priv *priv = omap_drm_file_priv(file, dce_mapper_id); struct drm_omap_dce_codec_control *arg = data; struct dce_rpc_codec_control_rsp *rsp; int ret; /* if we are not re-starting a syscall, send req */ if (!arg->token) { struct dce_rpc_codec_control_req req = { .hdr = MKHDR(CODEC_CONTROL), .cmd_id = arg->cmd_id, }; ret = codec_get(priv, arg->codec_handle, &req.codec, &req.codec_id); if (ret) return ret; ret = PTR_RET(get_paddr(priv, hdr(&req), &req.dparams, arg->dparams_bo)); if (ret) goto rpsend_out; ret = PTR_RET(get_paddr(priv, hdr(&req), &req.status, arg->status_bo)); if (ret) goto rpsend_out; ret = rpsend(priv, &arg->token, hdr(&req), sizeof(req)); rpsend_out: if (ret) return rpabort(hdr(&req), ret); } /* then wait for reply, which is interruptible */ ret = rpwait(priv, arg->token, hdr(&rsp), sizeof(*rsp)); if (ret) return ret; arg->result = rsp->result; kfree(rsp); return 0; } struct viddec3_in_args { int32_t size; /* struct size */ int32_t num_bytes; int32_t input_id; }; struct videnc2_in_args { int32_t size; int32_t input_id; int32_t control; }; union xdm2_buf_size { struct { int32_t width; int32_t height; } tiled; int32_t bytes; }; struct xdm2_single_buf_desc { uint32_t buf; int16_t mem_type; /* XXX should be XDM_MEMTYPE_BO */ int16_t usage_mode; union xdm2_buf_size buf_size; int32_t accessMask; }; struct xdm2_buf_desc { int32_t num_bufs; struct xdm2_single_buf_desc descs[16]; }; struct video2_buf_desc { int32_t num_planes; int32_t num_meta_planes; int32_t data_layout; struct xdm2_single_buf_desc plane_desc[3]; struct xdm2_single_buf_desc metadata_plane_desc[3]; /* rest of the struct isn't interesting to kernel.. if you are * curious look at IVIDEO2_BufDesc in ivideo.h in codec-engine */ uint32_t data[30]; }; #define XDM_MEMTYPE_RAW 0 #define XDM_MEMTYPE_TILED8 1 #define XDM_MEMTYPE_TILED16 2 #define XDM_MEMTYPE_TILED32 3 #define XDM_MEMTYPE_TILEDPAGE 4 /* copy_from_user helper that also checks to avoid overrunning * the 'to' buffer and advances dst ptr */ static inline int cfu(void **top, uint64_t from, int n, void *end) { void *to = *top; int ret; if ((to + n) >= end) { DBG("dst buffer overflow!"); return -EFAULT; } ret = copy_from_user(to, (char __user *)(uintptr_t)from, n); *top = to + n; return ret; } static inline struct drm_gem_object * handle_single_buf_desc( struct dce_file_priv *priv, struct dce_rpc_hdr *req, uint32_t base_bo, struct xdm2_single_buf_desc *desc) { struct drm_gem_object *obj; uint32_t flags; int32_t offset; /* maybe support remapping user ptrs later on.. */ if (desc->mem_type != XDM_MEMTYPE_BO && desc->mem_type != XDM_MEMTYPE_BO_OFFSET) return ERR_PTR(-EINVAL); if (desc->mem_type == XDM_MEMTYPE_BO_OFFSET) { /* desc->buf is an offset to base_bo, which is descs[0].buf as * passed to _process */ offset = desc->buf; desc->buf = base_bo; } else { offset = -1; } obj = get_paddr(priv, req, &desc->buf, desc->buf); if (IS_ERR(obj)) return obj; if (offset != -1) desc->buf += offset; flags = omap_gem_flags(obj); switch(flags & OMAP_BO_TILED) { case OMAP_BO_TILED_8: desc->mem_type = XDM_MEMTYPE_TILED8; break; case OMAP_BO_TILED_16: desc->mem_type = XDM_MEMTYPE_TILED16; break; case OMAP_BO_TILED_32: desc->mem_type = XDM_MEMTYPE_TILED32; break; default: // XXX this is where it gets a bit messy.. some codecs // might want to see XDM_MEMTYPE_RAW for bitstream buffers desc->mem_type = XDM_MEMTYPE_TILEDPAGE; break; } if (flags & OMAP_BO_TILED) { uint16_t w, h; omap_gem_tiled_size(obj, &w, &h); desc->buf_size.tiled.width = w; desc->buf_size.tiled.height = h; } // XXX not sure if the codecs care about usage_mode.. but we // know if the buffer is cached or not so we could set DATASYNC // bit if needed.. return obj; } static inline int handle_buf_desc(struct dce_file_priv *priv, void **ptr, void *end, struct dce_rpc_hdr *req, uint64_t usr, struct drm_gem_object **o1, struct drm_gem_object **o2, uint8_t *len) { struct xdm2_buf_desc *bufs = *ptr; uint32_t base_bo; int i, ret; /* read num_bufs field: */ ret = cfu(ptr, usr, 4, end); if (ret) return ret; /* read rest of structure: */ ret = cfu(ptr, usr+4, bufs->num_bufs * sizeof(bufs->descs[0]), end); if (ret) return ret; *len = (4 + bufs->num_bufs * sizeof(bufs->descs[0])) / 4; /* the bo used as a base for XDM_MEMTYPE_BO_OFFSET descriptors */ base_bo = bufs->descs[0].buf; /* handle buffer mapping.. */ for (i = 0; i < bufs->num_bufs; i++) { struct drm_gem_object *obj = handle_single_buf_desc(priv, req, base_bo, &bufs->descs[i]); if (IS_ERR(obj)) { return PTR_ERR(obj); } if (i == 0) *o1 = obj; if (o2 && (i == 1)) *o2 = obj; } return 0; } /* * VIDDEC3_process VIDENC2_process * VIDDEC3_InArgs *inArgs VIDENC2_InArgs *inArgs * XDM2_BufDesc *outBufs XDM2_BufDesc *outBufs * XDM2_BufDesc *inBufs VIDEO2_BufDesc *inBufs */ static inline int handle_videnc2(struct dce_file_priv *priv, void **ptr, void *end, int32_t *input_id, struct dce_rpc_codec_process_req *req, struct drm_omap_dce_codec_process *arg) { WARN_ON(1); // XXX not implemented // codec_lockbuf(priv, arg->codec_handle, in_args->input_id, y, uv); return -EFAULT; }