mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 22:26:55 +00:00
media: rockchip: rga: rework buffer handling for multi-planar formats
Multi-planar formats may have multiple planes that must be handled and correctly mapped into a continuous buffer for the RGA by using the DMA descriptors. The plane offsets in the continuous mapping may now start at page boundaries and the previous calculation based on the frame sizes is only valid for planar buffers in a single memory. Therefore, the offsets must be detected and set while creating the mapping. Signed-off-by: Michael Tretter <m.tretter@pengutronix.de> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
parent
0148bcd77d
commit
a61ff67ffb
3 changed files with 58 additions and 11 deletions
|
@ -7,6 +7,7 @@
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
|
|
||||||
|
#include <media/v4l2-common.h>
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
#include <media/v4l2-ioctl.h>
|
#include <media/v4l2-ioctl.h>
|
||||||
#include <media/v4l2-mem2mem.h>
|
#include <media/v4l2-mem2mem.h>
|
||||||
|
@ -16,7 +17,8 @@
|
||||||
#include "rga-hw.h"
|
#include "rga-hw.h"
|
||||||
#include "rga.h"
|
#include "rga.h"
|
||||||
|
|
||||||
static size_t fill_descriptors(struct rga_dma_desc *desc, struct sg_table *sgt)
|
static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc,
|
||||||
|
struct sg_table *sgt)
|
||||||
{
|
{
|
||||||
struct sg_dma_page_iter iter;
|
struct sg_dma_page_iter iter;
|
||||||
struct rga_dma_desc *tmp = desc;
|
struct rga_dma_desc *tmp = desc;
|
||||||
|
@ -24,6 +26,8 @@ static size_t fill_descriptors(struct rga_dma_desc *desc, struct sg_table *sgt)
|
||||||
dma_addr_t addr;
|
dma_addr_t addr;
|
||||||
|
|
||||||
for_each_sgtable_dma_page(sgt, &iter, 0) {
|
for_each_sgtable_dma_page(sgt, &iter, 0) {
|
||||||
|
if (n_desc > max_desc)
|
||||||
|
return -EINVAL;
|
||||||
addr = sg_page_iter_dma_address(&iter);
|
addr = sg_page_iter_dma_address(&iter);
|
||||||
tmp->addr = lower_32_bits(addr);
|
tmp->addr = lower_32_bits(addr);
|
||||||
tmp++;
|
tmp++;
|
||||||
|
@ -40,15 +44,29 @@ rga_queue_setup(struct vb2_queue *vq,
|
||||||
{
|
{
|
||||||
struct rga_ctx *ctx = vb2_get_drv_priv(vq);
|
struct rga_ctx *ctx = vb2_get_drv_priv(vq);
|
||||||
struct rga_frame *f = rga_get_frame(ctx, vq->type);
|
struct rga_frame *f = rga_get_frame(ctx, vq->type);
|
||||||
|
const struct v4l2_pix_format_mplane *pix_fmt;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (IS_ERR(f))
|
if (IS_ERR(f))
|
||||||
return PTR_ERR(f);
|
return PTR_ERR(f);
|
||||||
|
|
||||||
if (*nplanes)
|
pix_fmt = &f->pix;
|
||||||
return sizes[0] < f->size ? -EINVAL : 0;
|
|
||||||
|
|
||||||
sizes[0] = f->size;
|
if (*nplanes) {
|
||||||
*nplanes = 1;
|
if (*nplanes != pix_fmt->num_planes)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < pix_fmt->num_planes; i++)
|
||||||
|
if (sizes[i] < pix_fmt->plane_fmt[i].sizeimage)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nplanes = pix_fmt->num_planes;
|
||||||
|
|
||||||
|
for (i = 0; i < pix_fmt->num_planes; i++)
|
||||||
|
sizes[i] = pix_fmt->plane_fmt[i].sizeimage;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -92,18 +110,39 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
|
||||||
struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
|
struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
|
||||||
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
|
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
|
||||||
struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
|
struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
|
||||||
|
ssize_t n_desc = 0;
|
||||||
|
size_t curr_desc = 0;
|
||||||
|
int i;
|
||||||
|
const struct v4l2_format_info *info;
|
||||||
|
unsigned int offsets[VIDEO_MAX_PLANES];
|
||||||
|
|
||||||
if (IS_ERR(f))
|
if (IS_ERR(f))
|
||||||
return PTR_ERR(f);
|
return PTR_ERR(f);
|
||||||
|
|
||||||
vb2_set_plane_payload(vb, 0, f->size);
|
for (i = 0; i < vb->num_planes; i++) {
|
||||||
|
vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
|
||||||
|
|
||||||
/* Create local MMU table for RGA */
|
/* Create local MMU table for RGA */
|
||||||
fill_descriptors(rbuf->dma_desc, vb2_dma_sg_plane_desc(vb, 0));
|
n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
|
||||||
|
rbuf->n_desc - curr_desc,
|
||||||
|
vb2_dma_sg_plane_desc(vb, i));
|
||||||
|
if (n_desc < 0) {
|
||||||
|
v4l2_err(&ctx->rga->v4l2_dev,
|
||||||
|
"Failed to map video buffer to RGA\n");
|
||||||
|
return n_desc;
|
||||||
|
}
|
||||||
|
offsets[i] = curr_desc << PAGE_SHIFT;
|
||||||
|
curr_desc += n_desc;
|
||||||
|
}
|
||||||
|
|
||||||
rbuf->offset.y_off = get_plane_offset(f, 0);
|
/* Fill the remaining planes */
|
||||||
rbuf->offset.u_off = get_plane_offset(f, 1);
|
info = v4l2_format_info(f->fmt->fourcc);
|
||||||
rbuf->offset.v_off = get_plane_offset(f, 2);
|
for (i = info->mem_planes; i < info->comp_planes; i++)
|
||||||
|
offsets[i] = get_plane_offset(f, i);
|
||||||
|
|
||||||
|
rbuf->offset.y_off = offsets[0];
|
||||||
|
rbuf->offset.u_off = offsets[1];
|
||||||
|
rbuf->offset.v_off = offsets[2];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,6 +365,11 @@ static int rga_open(struct file *file)
|
||||||
ctx->in = def_frame;
|
ctx->in = def_frame;
|
||||||
ctx->out = def_frame;
|
ctx->out = def_frame;
|
||||||
|
|
||||||
|
v4l2_fill_pixfmt_mp(&ctx->in.pix,
|
||||||
|
ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height);
|
||||||
|
v4l2_fill_pixfmt_mp(&ctx->out.pix,
|
||||||
|
ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height);
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&rga->mutex)) {
|
if (mutex_lock_interruptible(&rga->mutex)) {
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
@ -524,6 +529,8 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
|
||||||
frm->crop.width = frm->width;
|
frm->crop.width = frm->width;
|
||||||
frm->crop.height = frm->height;
|
frm->crop.height = frm->height;
|
||||||
|
|
||||||
|
frm->pix = *pix_fmt;
|
||||||
|
|
||||||
v4l2_dbg(debug, 1, &rga->v4l2_dev,
|
v4l2_dbg(debug, 1, &rga->v4l2_dev,
|
||||||
"[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
|
"[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
|
||||||
V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
|
V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct rga_frame {
|
||||||
|
|
||||||
/* Image format */
|
/* Image format */
|
||||||
struct rga_fmt *fmt;
|
struct rga_fmt *fmt;
|
||||||
|
struct v4l2_pix_format_mplane pix;
|
||||||
|
|
||||||
/* Variables that can calculated once and reused */
|
/* Variables that can calculated once and reused */
|
||||||
u32 stride;
|
u32 stride;
|
||||||
|
|
Loading…
Reference in a new issue