summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/rockchip/rga
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
commit01a69402cf9d38ff180345d55c2ee51c7e89fbc7 (patch)
treeb406c5242a088c4f59c6e4b719b783f43aca6ae9 /drivers/media/platform/rockchip/rga
parentAdding upstream version 6.7.12. (diff)
downloadlinux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.tar.xz
linux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.zip
Adding upstream version 6.8.9.upstream/6.8.9
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/media/platform/rockchip/rga')
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c162
-rw-r--r--drivers/media/platform/rockchip/rga/rga-hw.c146
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c174
-rw-r--r--drivers/media/platform/rockchip/rga/rga.h35
4 files changed, 325 insertions, 192 deletions
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 81508ed5ab..662c81b6d0 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -5,7 +5,9 @@
*/
#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
@@ -15,6 +17,26 @@
#include "rga-hw.h"
#include "rga.h"
+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 rga_dma_desc *tmp = desc;
+ size_t n_desc = 0;
+ dma_addr_t addr;
+
+ for_each_sgtable_dma_page(sgt, &iter, 0) {
+ if (n_desc > max_desc)
+ return -EINVAL;
+ addr = sg_page_iter_dma_address(&iter);
+ tmp->addr = lower_32_bits(addr);
+ tmp++;
+ n_desc++;
+ }
+
+ return n_desc;
+}
+
static int
rga_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
@@ -22,28 +44,105 @@ rga_queue_setup(struct vb2_queue *vq,
{
struct rga_ctx *ctx = vb2_get_drv_priv(vq);
struct rga_frame *f = rga_get_frame(ctx, vq->type);
+ const struct v4l2_pix_format_mplane *pix_fmt;
+ int i;
if (IS_ERR(f))
return PTR_ERR(f);
- if (*nplanes)
- return sizes[0] < f->size ? -EINVAL : 0;
+ pix_fmt = &f->pix;
+
+ if (*nplanes) {
+ 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;
+}
+
+static int rga_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
+ struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct rockchip_rga *rga = ctx->rga;
+ struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
+ size_t n_desc = 0;
- sizes[0] = f->size;
- *nplanes = 1;
+ n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+
+ rbuf->n_desc = n_desc;
+ rbuf->dma_desc = dma_alloc_coherent(rga->dev,
+ rbuf->n_desc * sizeof(*rbuf->dma_desc),
+ &rbuf->dma_desc_pa, GFP_KERNEL);
+ if (!rbuf->dma_desc)
+ return -ENOMEM;
return 0;
}
+static int get_plane_offset(struct rga_frame *f, int plane)
+{
+ if (plane == 0)
+ return 0;
+ if (plane == 1)
+ return f->width * f->height;
+ if (plane == 2)
+ return f->width * f->height + (f->width * f->height / f->fmt->uv_factor);
+
+ return -EINVAL;
+}
+
static int rga_buf_prepare(struct vb2_buffer *vb)
{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
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))
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 */
+ 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;
+ }
+
+ /* Fill the remaining planes */
+ info = v4l2_format_info(f->fmt->fourcc);
+ 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;
}
@@ -56,6 +155,17 @@ static void rga_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
+static void rga_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
+ struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct rockchip_rga *rga = ctx->rga;
+
+ dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
+ rbuf->dma_desc, rbuf->dma_desc_pa);
+}
+
static void rga_buf_return_buffers(struct vb2_queue *q,
enum vb2_buffer_state state)
{
@@ -99,50 +209,12 @@ static void rga_buf_stop_streaming(struct vb2_queue *q)
const struct vb2_ops rga_qops = {
.queue_setup = rga_queue_setup,
+ .buf_init = rga_buf_init,
.buf_prepare = rga_buf_prepare,
.buf_queue = rga_buf_queue,
+ .buf_cleanup = rga_buf_cleanup,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.start_streaming = rga_buf_start_streaming,
.stop_streaming = rga_buf_stop_streaming,
};
-
-/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
- * We use it more like a scatter-gather list.
- */
-void rga_buf_map(struct vb2_buffer *vb)
-{
- struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct rockchip_rga *rga = ctx->rga;
- struct sg_table *sgt;
- struct scatterlist *sgl;
- unsigned int *pages;
- unsigned int address, len, i, p;
- unsigned int mapped_size = 0;
-
- if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- pages = rga->src_mmu_pages;
- else
- pages = rga->dst_mmu_pages;
-
- /* Create local MMU table for RGA */
- sgt = vb2_plane_cookie(vb, 0);
-
- for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
- len = sg_dma_len(sgl) >> PAGE_SHIFT;
- address = sg_phys(sgl);
-
- for (p = 0; p < len; p++) {
- dma_addr_t phys = address +
- ((dma_addr_t)p << PAGE_SHIFT);
-
- pages[mapped_size + p] = phys;
- }
-
- mapped_size += len;
- }
-
- /* sync local MMU table for RGA */
- dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
- 8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
-}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index aaa96f2563..11c3d72347 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -16,12 +16,6 @@ enum e_rga_start_pos {
RB = 3,
};
-struct rga_addr_offset {
- unsigned int y_off;
- unsigned int u_off;
- unsigned int v_off;
-};
-
struct rga_corners_addr_offset {
struct rga_addr_offset left_top;
struct rga_addr_offset right_top;
@@ -43,13 +37,13 @@ static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
}
static struct rga_corners_addr_offset
-rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
- unsigned int w, unsigned int h)
+rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
+ unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
struct rga_corners_addr_offset offsets;
struct rga_addr_offset *lt, *lb, *rt, *rb;
unsigned int x_div = 0,
- y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
+ y_div = 0, uv_stride = 0, pixel_width = 0;
lt = &offsets.left_top;
lb = &offsets.left_bottom;
@@ -58,14 +52,12 @@ rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
x_div = frm->fmt->x_div;
y_div = frm->fmt->y_div;
- uv_factor = frm->fmt->uv_factor;
uv_stride = frm->stride / x_div;
pixel_width = frm->stride / frm->width;
- lt->y_off = y * frm->stride + x * pixel_width;
- lt->u_off =
- frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
- lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
+ lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
+ lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
+ lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;
lb->y_off = lt->y_off + (h - 1) * frm->stride;
lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
@@ -119,40 +111,40 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
return NULL;
}
-static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
+static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
- dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+ dest[reg >> 2] = dma_addr >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7;
}
-static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
+static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
- dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+ dest[reg >> 2] = dma_addr >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7 << 4;
}
-static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
+static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
- dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+ dest[reg >> 2] = dma_addr >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7 << 8;
@@ -163,7 +155,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int scale_dst_w, scale_dst_h;
- unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
+ unsigned int src_h, src_w, dst_h, dst_w;
union rga_src_info src_info;
union rga_dst_info dst_info;
union rga_src_x_factor x_factor;
@@ -173,18 +165,10 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
- struct rga_addr_offset *dst_offset;
- struct rga_corners_addr_offset offsets;
- struct rga_corners_addr_offset src_offsets;
-
src_h = ctx->in.crop.height;
src_w = ctx->in.crop.width;
- src_x = ctx->in.crop.left;
- src_y = ctx->in.crop.top;
dst_h = ctx->out.crop.height;
dst_w = ctx->out.crop.width;
- dst_x = ctx->out.crop.left;
- dst_y = ctx->out.crop.top;
src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
@@ -312,18 +296,37 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
dst_act_info.data.act_height = dst_h - 1;
dst_act_info.data.act_width = dst_w - 1;
- /*
- * Calculate the source framebuffer base address with offset pixel.
- */
- src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
- src_w, src_h);
+ dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
+ dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
+ dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
+ dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+
+ dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+
+ dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
+ dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
+
+ dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
+}
+
+static void rga_cmd_set_src_info(struct rga_ctx *ctx,
+ struct rga_addr_offset *offset)
+{
+ struct rga_corners_addr_offset src_offsets;
+ struct rockchip_rga *rga = ctx->rga;
+ u32 *dest = rga->cmdbuf_virt;
+ unsigned int src_h, src_w, src_x, src_y;
+
+ src_h = ctx->in.crop.height;
+ src_w = ctx->in.crop.width;
+ src_x = ctx->in.crop.left;
+ src_y = ctx->in.crop.top;
/*
- * Configure the dest framebuffer base address with pixel offset.
+ * Calculate the source framebuffer base address with offset pixel.
*/
- offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
- dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
- src_info.data.mir_mode);
+ src_offsets = rga_get_addr_offset(&ctx->in, offset,
+ src_x, src_y, src_w, src_h);
dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.y_off;
@@ -331,13 +334,49 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
src_offsets.left_top.u_off;
dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.v_off;
+}
- dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
- dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
- dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
- dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
+ struct rga_addr_offset *offset)
+{
+ struct rga_addr_offset *dst_offset;
+ struct rga_corners_addr_offset offsets;
+ struct rockchip_rga *rga = ctx->rga;
+ u32 *dest = rga->cmdbuf_virt;
+ unsigned int dst_h, dst_w, dst_x, dst_y;
+ unsigned int mir_mode = 0;
+ unsigned int rot_mode = 0;
- dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+ dst_h = ctx->out.crop.height;
+ dst_w = ctx->out.crop.width;
+ dst_x = ctx->out.crop.left;
+ dst_y = ctx->out.crop.top;
+
+ if (ctx->vflip)
+ mir_mode |= RGA_SRC_MIRR_MODE_X;
+ if (ctx->hflip)
+ mir_mode |= RGA_SRC_MIRR_MODE_Y;
+
+ switch (ctx->rotate) {
+ case 90:
+ rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
+ break;
+ case 180:
+ rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
+ break;
+ case 270:
+ rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
+ break;
+ default:
+ rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
+ break;
+ }
+
+ /*
+ * Configure the dest framebuffer base address with pixel offset.
+ */
+ offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w, dst_h);
+ dst_offset = rga_lookup_draw_pos(&offsets, mir_mode, rot_mode);
dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->y_off;
@@ -345,11 +384,6 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
dst_offset->u_off;
dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->v_off;
-
- dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
- dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
-
- dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
}
static void rga_cmd_set_mode(struct rga_ctx *ctx)
@@ -375,22 +409,25 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx)
dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
}
-static void rga_cmd_set(struct rga_ctx *ctx)
+static void rga_cmd_set(struct rga_ctx *ctx,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
{
struct rockchip_rga *rga = ctx->rga;
memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
- rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
+ rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
/*
* Due to hardware bug,
* src1 mmu also should be configured when using alpha blending.
*/
- rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
+ rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
- rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
+ rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
rga_cmd_set_mode(ctx);
+ rga_cmd_set_src_info(ctx, &src->offset);
+ rga_cmd_set_dst_info(ctx, &dst->offset);
rga_cmd_set_trans_info(ctx);
rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
@@ -400,11 +437,12 @@ static void rga_cmd_set(struct rga_ctx *ctx)
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
-void rga_hw_start(struct rockchip_rga *rga)
+void rga_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
{
struct rga_ctx *ctx = rga->curr;
- rga_cmd_set(ctx);
+ rga_cmd_set(ctx, src, dst);
rga_write(rga, RGA_SYS_CTRL, 0x00);
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 25f5b5eebf..00fdfa9e10 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -45,10 +45,7 @@ static void device_run(void *prv)
src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
- rga_buf_map(&src->vb2_buf);
- rga_buf_map(&dst->vb2_buf);
-
- rga_hw_start(rga);
+ rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
spin_unlock_irqrestore(&rga->ctrl_lock, flags);
}
@@ -96,12 +93,13 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
struct rga_ctx *ctx = priv;
int ret;
- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->ops = &rga_qops;
src_vq->mem_ops = &vb2_dma_sg_memops;
- src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->gfp_flags = __GFP_DMA32;
+ src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->rga->mutex;
src_vq->dev = ctx->rga->v4l2_dev.dev;
@@ -110,12 +108,13 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
if (ret)
return ret;
- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->ops = &rga_qops;
dst_vq->mem_ops = &vb2_dma_sg_memops;
- dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->gfp_flags = __GFP_DMA32;
+ dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->rga->mutex;
dst_vq->dev = ctx->rga->v4l2_dev.dev;
@@ -282,6 +281,15 @@ static struct rga_fmt formats[] = {
.x_div = 1,
},
{
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420SP,
+ .depth = 12,
+ .uv_factor = 4,
+ .y_div = 2,
+ .x_div = 1,
+ },
+ {
.fourcc = V4L2_PIX_FMT_NV16,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV422SP,
@@ -321,12 +329,12 @@ static struct rga_fmt formats[] = {
#define NUM_FORMATS ARRAY_SIZE(formats)
-static struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
+static struct rga_fmt *rga_fmt_find(u32 pixelformat)
{
unsigned int i;
for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].fourcc == f->fmt.pix.pixelformat)
+ if (formats[i].fourcc == pixelformat)
return &formats[i];
}
return NULL;
@@ -345,14 +353,11 @@ static struct rga_frame def_frame = {
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
{
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (V4L2_TYPE_IS_OUTPUT(type))
return &ctx->in;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (V4L2_TYPE_IS_CAPTURE(type))
return &ctx->out;
- default:
- return ERR_PTR(-EINVAL);
- }
+ return ERR_PTR(-EINVAL);
}
static int rga_open(struct file *file)
@@ -369,6 +374,11 @@ static int rga_open(struct file *file)
ctx->in = 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)) {
kfree(ctx);
return -ERESTARTSYS;
@@ -449,6 +459,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
+ struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = prv;
struct vb2_queue *vq;
struct rga_frame *frm;
@@ -460,58 +471,43 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
if (IS_ERR(frm))
return PTR_ERR(frm);
- f->fmt.pix.width = frm->width;
- f->fmt.pix.height = frm->height;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.pixelformat = frm->fmt->fourcc;
- f->fmt.pix.bytesperline = frm->stride;
- f->fmt.pix.sizeimage = frm->size;
- f->fmt.pix.colorspace = frm->colorspace;
+ v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height);
+
+ pix_fmt->field = V4L2_FIELD_NONE;
+ pix_fmt->colorspace = frm->colorspace;
return 0;
}
static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
+ struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_fmt *fmt;
- fmt = rga_fmt_find(f);
- if (!fmt) {
+ fmt = rga_fmt_find(pix_fmt->pixelformat);
+ if (!fmt)
fmt = &formats[0];
- f->fmt.pix.pixelformat = fmt->fourcc;
- }
- f->fmt.pix.field = V4L2_FIELD_NONE;
+ pix_fmt->width = clamp(pix_fmt->width,
+ (u32)MIN_WIDTH, (u32)MAX_WIDTH);
+ pix_fmt->height = clamp(pix_fmt->height,
+ (u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
- if (f->fmt.pix.width > MAX_WIDTH)
- f->fmt.pix.width = MAX_WIDTH;
- if (f->fmt.pix.height > MAX_HEIGHT)
- f->fmt.pix.height = MAX_HEIGHT;
-
- if (f->fmt.pix.width < MIN_WIDTH)
- f->fmt.pix.width = MIN_WIDTH;
- if (f->fmt.pix.height < MIN_HEIGHT)
- f->fmt.pix.height = MIN_HEIGHT;
-
- if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP)
- f->fmt.pix.bytesperline = f->fmt.pix.width;
- else
- f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
-
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3;
+ v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
+ pix_fmt->field = V4L2_FIELD_NONE;
return 0;
}
static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
+ struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = prv;
struct rockchip_rga *rga = ctx->rga;
struct vb2_queue *vq;
struct rga_frame *frm;
- struct rga_fmt *fmt;
int ret = 0;
+ int i;
/* Adjust all values accordingly to the hardware capabilities
* and chosen format.
@@ -527,15 +523,14 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
frm = rga_get_frame(ctx, f->type);
if (IS_ERR(frm))
return PTR_ERR(frm);
- fmt = rga_fmt_find(f);
- if (!fmt)
- return -EINVAL;
- frm->width = f->fmt.pix.width;
- frm->height = f->fmt.pix.height;
- frm->size = f->fmt.pix.sizeimage;
- frm->fmt = fmt;
- frm->stride = f->fmt.pix.bytesperline;
- frm->colorspace = f->fmt.pix.colorspace;
+ frm->width = pix_fmt->width;
+ frm->height = pix_fmt->height;
+ frm->size = 0;
+ for (i = 0; i < pix_fmt->num_planes; i++)
+ frm->size += pix_fmt->plane_fmt[i].sizeimage;
+ frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
+ frm->stride = pix_fmt->plane_fmt[0].bytesperline;
+ frm->colorspace = pix_fmt->colorspace;
/* Reset crop settings */
frm->crop.left = 0;
@@ -543,6 +538,21 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
frm->crop.width = frm->width;
frm->crop.height = frm->height;
+ frm->pix = *pix_fmt;
+
+ v4l2_dbg(debug, 1, &rga->v4l2_dev,
+ "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
+ V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
+ &frm->fmt->fourcc, frm->width, frm->height,
+ frm->stride, frm->size);
+
+ for (i = 0; i < pix_fmt->num_planes; i++) {
+ v4l2_dbg(debug, 1, &rga->v4l2_dev,
+ "plane[%d]: size %d, bytesperline %d\n",
+ i, pix_fmt->plane_fmt[i].sizeimage,
+ pix_fmt->plane_fmt[i].bytesperline);
+ }
+
return 0;
}
@@ -560,21 +570,21 @@ static int vidioc_g_selection(struct file *file, void *prv,
switch (s->target) {
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!V4L2_TYPE_IS_CAPTURE(s->type))
return -EINVAL;
break;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
return -EINVAL;
break;
case V4L2_SEL_TGT_COMPOSE:
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!V4L2_TYPE_IS_CAPTURE(s->type))
return -EINVAL;
use_frame = true;
break;
case V4L2_SEL_TGT_CROP:
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
return -EINVAL;
use_frame = true;
break;
@@ -612,7 +622,7 @@ static int vidioc_s_selection(struct file *file, void *prv,
* COMPOSE target is only valid for capture buffer type, return
* error for output buffer type
*/
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!V4L2_TYPE_IS_CAPTURE(s->type))
return -EINVAL;
break;
case V4L2_SEL_TGT_CROP:
@@ -620,7 +630,7 @@ static int vidioc_s_selection(struct file *file, void *prv,
* CROP target is only valid for output buffer type, return
* error for capture buffer type
*/
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
return -EINVAL;
break;
/*
@@ -653,14 +663,14 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
.vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_out = vidioc_g_fmt,
- .vidioc_try_fmt_vid_out = vidioc_try_fmt,
- .vidioc_s_fmt_vid_out = vidioc_s_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
@@ -687,7 +697,7 @@ static const struct video_device rga_videodev = {
.minor = -1,
.release = video_device_release,
.vfl_dir = VFL_DIR_M2M,
- .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+ .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
};
static int rga_enable_clocks(struct rockchip_rga *rga)
@@ -827,6 +837,12 @@ static int rga_probe(struct platform_device *pdev)
goto err_put_clk;
}
+ ret = dma_set_mask_and_coherent(rga->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(rga->dev, "32-bit DMA not supported");
+ goto err_put_clk;
+ }
+
ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
if (ret)
goto err_put_clk;
@@ -872,26 +888,13 @@ static int rga_probe(struct platform_device *pdev)
goto rel_m2m;
}
- rga->src_mmu_pages =
- (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
- if (!rga->src_mmu_pages) {
- ret = -ENOMEM;
- goto free_dma;
- }
- rga->dst_mmu_pages =
- (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
- if (!rga->dst_mmu_pages) {
- ret = -ENOMEM;
- goto free_src_pages;
- }
-
def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
def_frame.size = def_frame.stride * def_frame.height;
ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
if (ret) {
v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
- goto free_dst_pages;
+ goto free_dma;
}
v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
@@ -899,10 +902,6 @@ static int rga_probe(struct platform_device *pdev)
return 0;
-free_dst_pages:
- free_pages((unsigned long)rga->dst_mmu_pages, 3);
-free_src_pages:
- free_pages((unsigned long)rga->src_mmu_pages, 3);
free_dma:
dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
@@ -925,9 +924,6 @@ static void rga_remove(struct platform_device *pdev)
dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
- free_pages((unsigned long)rga->src_mmu_pages, 3);
- free_pages((unsigned long)rga->dst_mmu_pages, 3);
-
v4l2_info(&rga->v4l2_dev, "Removing\n");
v4l2_m2m_release(rga->m2m_dev);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 5fa9d2f366..3502dff605 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -34,12 +34,17 @@ struct rga_frame {
/* Image format */
struct rga_fmt *fmt;
+ struct v4l2_pix_format_mplane pix;
/* Variables that can calculated once and reused */
u32 stride;
u32 size;
};
+struct rga_dma_desc {
+ u32 addr;
+};
+
struct rockchip_rga_version {
u32 major;
u32 minor;
@@ -81,15 +86,36 @@ struct rockchip_rga {
struct rga_ctx *curr;
dma_addr_t cmdbuf_phy;
void *cmdbuf_virt;
- unsigned int *src_mmu_pages;
- unsigned int *dst_mmu_pages;
};
+struct rga_addr_offset {
+ unsigned int y_off;
+ unsigned int u_off;
+ unsigned int v_off;
+};
+
+struct rga_vb_buffer {
+ struct vb2_v4l2_buffer vb_buf;
+ struct list_head queue;
+
+ /* RGA MMU mapping for this buffer */
+ struct rga_dma_desc *dma_desc;
+ dma_addr_t dma_desc_pa;
+ size_t n_desc;
+
+ /* Plane offsets of this buffer into the mapping */
+ struct rga_addr_offset offset;
+};
+
+static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb)
+{
+ return container_of(vb, struct rga_vb_buffer, vb_buf);
+}
+
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
/* RGA Buffers Manage */
extern const struct vb2_ops rga_qops;
-void rga_buf_map(struct vb2_buffer *vb);
/* RGA Hardware */
static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
@@ -110,6 +136,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
rga_write(rga, reg, temp);
};
-void rga_hw_start(struct rockchip_rga *rga);
+void rga_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
#endif