]>
Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
f7e7b48e JC |
2 | /* |
3 | * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd | |
4 | * Author: Jacob Chen <jacob-chen@iotwrt.com> | |
f7e7b48e JC |
5 | */ |
6 | ||
7 | #include <linux/pm_runtime.h> | |
8 | ||
9 | #include <media/v4l2-device.h> | |
10 | #include <media/v4l2-ioctl.h> | |
11 | #include <media/v4l2-mem2mem.h> | |
12 | #include <media/videobuf2-dma-sg.h> | |
13 | #include <media/videobuf2-v4l2.h> | |
14 | ||
15 | #include "rga-hw.h" | |
16 | #include "rga.h" | |
17 | ||
18 | static int | |
19 | rga_queue_setup(struct vb2_queue *vq, | |
20 | unsigned int *nbuffers, unsigned int *nplanes, | |
21 | unsigned int sizes[], struct device *alloc_devs[]) | |
22 | { | |
23 | struct rga_ctx *ctx = vb2_get_drv_priv(vq); | |
24 | struct rga_frame *f = rga_get_frame(ctx, vq->type); | |
25 | ||
26 | if (IS_ERR(f)) | |
27 | return PTR_ERR(f); | |
28 | ||
29 | if (*nplanes) | |
30 | return sizes[0] < f->size ? -EINVAL : 0; | |
31 | ||
32 | sizes[0] = f->size; | |
33 | *nplanes = 1; | |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
38 | static int rga_buf_prepare(struct vb2_buffer *vb) | |
39 | { | |
40 | struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
41 | struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type); | |
42 | ||
43 | if (IS_ERR(f)) | |
44 | return PTR_ERR(f); | |
45 | ||
46 | vb2_set_plane_payload(vb, 0, f->size); | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | static void rga_buf_queue(struct vb2_buffer *vb) | |
52 | { | |
53 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
54 | struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
55 | ||
56 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | |
57 | } | |
58 | ||
9aecc035 EG |
59 | static void rga_buf_return_buffers(struct vb2_queue *q, |
60 | enum vb2_buffer_state state) | |
61 | { | |
62 | struct rga_ctx *ctx = vb2_get_drv_priv(q); | |
63 | struct vb2_v4l2_buffer *vbuf; | |
64 | ||
65 | for (;;) { | |
66 | if (V4L2_TYPE_IS_OUTPUT(q->type)) | |
67 | vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | |
68 | else | |
69 | vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
70 | if (!vbuf) | |
71 | break; | |
72 | v4l2_m2m_buf_done(vbuf, state); | |
73 | } | |
74 | } | |
75 | ||
f7e7b48e JC |
76 | static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count) |
77 | { | |
78 | struct rga_ctx *ctx = vb2_get_drv_priv(q); | |
79 | struct rockchip_rga *rga = ctx->rga; | |
9aecc035 | 80 | int ret; |
f7e7b48e JC |
81 | |
82 | ret = pm_runtime_get_sync(rga->dev); | |
9aecc035 EG |
83 | if (ret < 0) { |
84 | rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED); | |
85 | return ret; | |
f7e7b48e JC |
86 | } |
87 | ||
9aecc035 | 88 | return 0; |
f7e7b48e JC |
89 | } |
90 | ||
91 | static void rga_buf_stop_streaming(struct vb2_queue *q) | |
92 | { | |
93 | struct rga_ctx *ctx = vb2_get_drv_priv(q); | |
94 | struct rockchip_rga *rga = ctx->rga; | |
f7e7b48e | 95 | |
9aecc035 | 96 | rga_buf_return_buffers(q, VB2_BUF_STATE_ERROR); |
f7e7b48e JC |
97 | pm_runtime_put(rga->dev); |
98 | } | |
99 | ||
100 | const struct vb2_ops rga_qops = { | |
101 | .queue_setup = rga_queue_setup, | |
102 | .buf_prepare = rga_buf_prepare, | |
103 | .buf_queue = rga_buf_queue, | |
104 | .wait_prepare = vb2_ops_wait_prepare, | |
105 | .wait_finish = vb2_ops_wait_finish, | |
106 | .start_streaming = rga_buf_start_streaming, | |
107 | .stop_streaming = rga_buf_stop_streaming, | |
108 | }; | |
109 | ||
110 | /* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API. | |
111 | * We use it more like a scatter-gather list. | |
112 | */ | |
113 | void rga_buf_map(struct vb2_buffer *vb) | |
114 | { | |
115 | struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
116 | struct rockchip_rga *rga = ctx->rga; | |
117 | struct sg_table *sgt; | |
118 | struct scatterlist *sgl; | |
119 | unsigned int *pages; | |
120 | unsigned int address, len, i, p; | |
121 | unsigned int mapped_size = 0; | |
122 | ||
123 | if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
124 | pages = rga->src_mmu_pages; | |
125 | else | |
126 | pages = rga->dst_mmu_pages; | |
127 | ||
128 | /* Create local MMU table for RGA */ | |
129 | sgt = vb2_plane_cookie(vb, 0); | |
130 | ||
131 | for_each_sg(sgt->sgl, sgl, sgt->nents, i) { | |
132 | len = sg_dma_len(sgl) >> PAGE_SHIFT; | |
133 | address = sg_phys(sgl); | |
134 | ||
135 | for (p = 0; p < len; p++) { | |
8328ad0f GS |
136 | dma_addr_t phys = address + |
137 | ((dma_addr_t)p << PAGE_SHIFT); | |
f7e7b48e JC |
138 | |
139 | pages[mapped_size + p] = phys; | |
140 | } | |
141 | ||
142 | mapped_size += len; | |
143 | } | |
144 | ||
145 | /* sync local MMU table for RGA */ | |
146 | dma_sync_single_for_device(rga->dev, virt_to_phys(pages), | |
147 | 8 * PAGE_SIZE, DMA_BIDIRECTIONAL); | |
148 | } |