123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- /*
- * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd
- * Author: Jacob Chen <jacob-chen@iotwrt.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/pm_runtime.h>
- #include <media/v4l2-device.h>
- #include <media/v4l2-ioctl.h>
- #include <media/v4l2-mem2mem.h>
- #include <media/videobuf2-dma-sg.h>
- #include <media/videobuf2-v4l2.h>
- #include "rga-hw.h"
- #include "rga.h"
- static int
- rga_queue_setup(struct vb2_queue *vq,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], struct device *alloc_devs[])
- {
- struct rga_ctx *ctx = vb2_get_drv_priv(vq);
- struct rga_frame *f = rga_get_frame(ctx, vq->type);
- if (IS_ERR(f))
- return PTR_ERR(f);
- if (*nplanes)
- return sizes[0] < f->size ? -EINVAL : 0;
- sizes[0] = f->size;
- *nplanes = 1;
- return 0;
- }
- static int rga_buf_prepare(struct vb2_buffer *vb)
- {
- struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
- if (IS_ERR(f))
- return PTR_ERR(f);
- vb2_set_plane_payload(vb, 0, f->size);
- return 0;
- }
- static void rga_buf_queue(struct vb2_buffer *vb)
- {
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
- }
- static void rga_buf_return_buffers(struct vb2_queue *q,
- enum vb2_buffer_state state)
- {
- struct rga_ctx *ctx = vb2_get_drv_priv(q);
- struct vb2_v4l2_buffer *vbuf;
- for (;;) {
- if (V4L2_TYPE_IS_OUTPUT(q->type))
- vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- else
- vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
- if (!vbuf)
- break;
- v4l2_m2m_buf_done(vbuf, state);
- }
- }
- static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
- {
- struct rga_ctx *ctx = vb2_get_drv_priv(q);
- struct rockchip_rga *rga = ctx->rga;
- int ret;
- ret = pm_runtime_get_sync(rga->dev);
- if (ret < 0) {
- rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED);
- return ret;
- }
- return 0;
- }
- static void rga_buf_stop_streaming(struct vb2_queue *q)
- {
- struct rga_ctx *ctx = vb2_get_drv_priv(q);
- struct rockchip_rga *rga = ctx->rga;
- rga_buf_return_buffers(q, VB2_BUF_STATE_ERROR);
- pm_runtime_put(rga->dev);
- }
- const struct vb2_ops rga_qops = {
- .queue_setup = rga_queue_setup,
- .buf_prepare = rga_buf_prepare,
- .buf_queue = rga_buf_queue,
- .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);
- }
|