1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/clk.h>
5*4882a593Smuzhiyun #include <linux/delay.h>
6*4882a593Smuzhiyun #include <media/v4l2-device.h>
7*4882a593Smuzhiyun #include <media/v4l2-fh.h>
8*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
9*4882a593Smuzhiyun #include <media/videobuf2-dma-contig.h>
10*4882a593Smuzhiyun #include <media/videobuf2-v4l2.h>
11*4882a593Smuzhiyun #include <linux/pm_runtime.h>
12*4882a593Smuzhiyun #include <linux/rk-ispp-config.h>
13*4882a593Smuzhiyun #include <uapi/linux/rk-video-format.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "hw.h"
16*4882a593Smuzhiyun #include "ispp.h"
17*4882a593Smuzhiyun #include "regs.h"
18*4882a593Smuzhiyun #include "stream.h"
19*4882a593Smuzhiyun #include "common.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun struct rkispp_fec_buf {
22*4882a593Smuzhiyun struct list_head list;
23*4882a593Smuzhiyun struct file *file;
24*4882a593Smuzhiyun int fd;
25*4882a593Smuzhiyun struct dma_buf *dbuf;
26*4882a593Smuzhiyun void *mem;
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun static const struct vb2_mem_ops *g_ops = &vb2_dma_contig_memops;
30*4882a593Smuzhiyun
fec_buf_add(struct file * file,int fd,int size)31*4882a593Smuzhiyun static void *fec_buf_add(struct file *file, int fd, int size)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct rkispp_fec_dev *fec = video_drvdata(file);
34*4882a593Smuzhiyun struct rkispp_fec_buf *buf = NULL;
35*4882a593Smuzhiyun struct dma_buf *dbuf;
36*4882a593Smuzhiyun void *mem = NULL;
37*4882a593Smuzhiyun bool is_add = true;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun dbuf = dma_buf_get(fd);
40*4882a593Smuzhiyun v4l2_dbg(4, rkispp_debug, &fec->v4l2_dev,
41*4882a593Smuzhiyun "%s file:%p fd:%d dbuf:%p\n", __func__, file, fd, dbuf);
42*4882a593Smuzhiyun if (IS_ERR_OR_NULL(dbuf)) {
43*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev, "invalid dmabuf fd:%d for in picture", fd);
44*4882a593Smuzhiyun return mem;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun if (size && dbuf->size < size) {
47*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev,
48*4882a593Smuzhiyun "input fd:%d size error:%zu < %u\n", fd, dbuf->size, size);
49*4882a593Smuzhiyun dma_buf_put(dbuf);
50*4882a593Smuzhiyun return mem;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun mutex_lock(&fec->hw->dev_lock);
54*4882a593Smuzhiyun list_for_each_entry(buf, &fec->list, list) {
55*4882a593Smuzhiyun if (buf->file == file && buf->fd == fd && buf->dbuf == dbuf) {
56*4882a593Smuzhiyun is_add = false;
57*4882a593Smuzhiyun break;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (is_add) {
62*4882a593Smuzhiyun mem = g_ops->attach_dmabuf(fec->hw->dev, dbuf, dbuf->size, DMA_BIDIRECTIONAL);
63*4882a593Smuzhiyun if (IS_ERR(mem)) {
64*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev, "failed to attach dmabuf, fd:%d\n", fd);
65*4882a593Smuzhiyun dma_buf_put(dbuf);
66*4882a593Smuzhiyun goto end;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun if (g_ops->map_dmabuf(mem)) {
69*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev, "failed to map, fd:%d\n", fd);
70*4882a593Smuzhiyun g_ops->detach_dmabuf(mem);
71*4882a593Smuzhiyun dma_buf_put(dbuf);
72*4882a593Smuzhiyun mem = NULL;
73*4882a593Smuzhiyun goto end;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun buf = kzalloc(sizeof(struct rkispp_fec_buf), GFP_KERNEL);
76*4882a593Smuzhiyun if (!buf) {
77*4882a593Smuzhiyun g_ops->unmap_dmabuf(mem);
78*4882a593Smuzhiyun g_ops->detach_dmabuf(mem);
79*4882a593Smuzhiyun dma_buf_put(dbuf);
80*4882a593Smuzhiyun mem = NULL;
81*4882a593Smuzhiyun goto end;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun buf->fd = fd;
84*4882a593Smuzhiyun buf->file = file;
85*4882a593Smuzhiyun buf->dbuf = dbuf;
86*4882a593Smuzhiyun buf->mem = mem;
87*4882a593Smuzhiyun list_add_tail(&buf->list, &fec->list);
88*4882a593Smuzhiyun } else {
89*4882a593Smuzhiyun dma_buf_put(dbuf);
90*4882a593Smuzhiyun mem = buf->mem;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun end:
93*4882a593Smuzhiyun mutex_unlock(&fec->hw->dev_lock);
94*4882a593Smuzhiyun return mem;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
fec_buf_del(struct file * file,int fd,bool is_all)97*4882a593Smuzhiyun static void fec_buf_del(struct file *file, int fd, bool is_all)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun struct rkispp_fec_dev *fec = video_drvdata(file);
100*4882a593Smuzhiyun struct rkispp_fec_buf *buf, *next;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun mutex_lock(&fec->hw->dev_lock);
103*4882a593Smuzhiyun list_for_each_entry_safe(buf, next, &fec->list, list) {
104*4882a593Smuzhiyun if (buf->file == file && (is_all || buf->fd == fd)) {
105*4882a593Smuzhiyun v4l2_dbg(4, rkispp_debug, &fec->v4l2_dev,
106*4882a593Smuzhiyun "%s file:%p fd:%d dbuf:%p\n",
107*4882a593Smuzhiyun __func__, file, buf->fd, buf->dbuf);
108*4882a593Smuzhiyun g_ops->unmap_dmabuf(buf->mem);
109*4882a593Smuzhiyun g_ops->detach_dmabuf(buf->mem);
110*4882a593Smuzhiyun dma_buf_put(buf->dbuf);
111*4882a593Smuzhiyun buf->file = NULL;
112*4882a593Smuzhiyun buf->mem = NULL;
113*4882a593Smuzhiyun buf->dbuf = NULL;
114*4882a593Smuzhiyun buf->fd = -1;
115*4882a593Smuzhiyun list_del(&buf->list);
116*4882a593Smuzhiyun kfree(buf);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun mutex_unlock(&fec->hw->dev_lock);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
fec_running(struct file * file,struct rkispp_fec_in_out * buf)122*4882a593Smuzhiyun static int fec_running(struct file *file, struct rkispp_fec_in_out *buf)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun struct rkispp_fec_dev *fec = video_drvdata(file);
125*4882a593Smuzhiyun u32 in_fmt, out_fmt, in_mult = 1, out_mult = 1;
126*4882a593Smuzhiyun u32 in_size, in_offs, out_size, out_offs, val;
127*4882a593Smuzhiyun u32 in_w = buf->in_width, in_h = buf->in_height;
128*4882a593Smuzhiyun u32 out_w = buf->out_width, out_h = buf->out_height;
129*4882a593Smuzhiyun u32 density, mesh_size;
130*4882a593Smuzhiyun void __iomem *base = fec->hw->base_addr;
131*4882a593Smuzhiyun void *mem;
132*4882a593Smuzhiyun int ret = -EINVAL;
133*4882a593Smuzhiyun ktime_t t = 0;
134*4882a593Smuzhiyun s64 us = 0;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun if (rkispp_debug)
137*4882a593Smuzhiyun t = ktime_get();
138*4882a593Smuzhiyun v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
139*4882a593Smuzhiyun "%s enter %dx%d->%dx%d format(in:%c%c%c%c out:%c%c%c%c)\n",
140*4882a593Smuzhiyun __func__, in_w, in_h, out_w, out_h,
141*4882a593Smuzhiyun buf->in_fourcc, buf->in_fourcc >> 8,
142*4882a593Smuzhiyun buf->in_fourcc >> 16, buf->in_fourcc >> 24,
143*4882a593Smuzhiyun buf->out_fourcc, buf->out_fourcc >> 8,
144*4882a593Smuzhiyun buf->out_fourcc >> 16, buf->out_fourcc >> 24);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun if (clk_get_rate(fec->hw->clks[0]) <= fec->hw->core_clk_min)
147*4882a593Smuzhiyun rkispp_set_clk_rate(fec->hw->clks[0], fec->hw->core_clk_max);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun init_completion(&fec->cmpl);
150*4882a593Smuzhiyun density = out_w > 1920 ? SW_MESH_DENSITY : 0;
151*4882a593Smuzhiyun mesh_size = cal_fec_mesh(out_w, out_h, !!density);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun switch (buf->in_fourcc) {
154*4882a593Smuzhiyun case V4L2_PIX_FMT_YUYV:
155*4882a593Smuzhiyun in_fmt = FMT_YC_SWAP | FMT_YUYV | FMT_YUV422;
156*4882a593Smuzhiyun in_mult = 2;
157*4882a593Smuzhiyun break;
158*4882a593Smuzhiyun case V4L2_PIX_FMT_UYVY:
159*4882a593Smuzhiyun in_fmt = FMT_YUYV | FMT_YUV422;
160*4882a593Smuzhiyun in_mult = 2;
161*4882a593Smuzhiyun break;
162*4882a593Smuzhiyun case V4L2_PIX_FMT_NV16:
163*4882a593Smuzhiyun in_fmt = FMT_YUV422;
164*4882a593Smuzhiyun break;
165*4882a593Smuzhiyun case V4L2_PIX_FMT_NV12:
166*4882a593Smuzhiyun in_fmt = FMT_YUV420;
167*4882a593Smuzhiyun break;
168*4882a593Smuzhiyun default:
169*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev,
170*4882a593Smuzhiyun "no support in format:%c%c%c%c\n",
171*4882a593Smuzhiyun buf->in_fourcc, buf->in_fourcc >> 8,
172*4882a593Smuzhiyun buf->in_fourcc >> 16, buf->in_fourcc >> 24);
173*4882a593Smuzhiyun return -EINVAL;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun in_offs = in_w * in_h;
176*4882a593Smuzhiyun in_size = (in_fmt & FMT_YUV422) ?
177*4882a593Smuzhiyun in_w * in_h * 2 : in_w * in_h * 3 / 2;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun switch (buf->out_fourcc) {
180*4882a593Smuzhiyun case V4L2_PIX_FMT_YUYV:
181*4882a593Smuzhiyun out_fmt = FMT_YC_SWAP | FMT_YUYV | FMT_YUV422;
182*4882a593Smuzhiyun out_mult = 2;
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun case V4L2_PIX_FMT_UYVY:
185*4882a593Smuzhiyun out_fmt = FMT_YUYV | FMT_YUV422;
186*4882a593Smuzhiyun out_mult = 2;
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun case V4L2_PIX_FMT_NV16:
189*4882a593Smuzhiyun out_fmt = FMT_YUV422;
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun case V4L2_PIX_FMT_NV12:
192*4882a593Smuzhiyun out_fmt = FMT_YUV420;
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun case V4L2_PIX_FMT_FBC2:
195*4882a593Smuzhiyun out_fmt = FMT_YUV422 | FMT_FBC;
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun case V4L2_PIX_FMT_FBC0:
198*4882a593Smuzhiyun out_fmt = FMT_YUV420 | FMT_FBC;
199*4882a593Smuzhiyun break;
200*4882a593Smuzhiyun default:
201*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev, "no support out format:%c%c%c%c\n",
202*4882a593Smuzhiyun buf->out_fourcc, buf->out_fourcc >> 8,
203*4882a593Smuzhiyun buf->out_fourcc >> 16, buf->out_fourcc >> 24);
204*4882a593Smuzhiyun return -EINVAL;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun out_size = 0;
207*4882a593Smuzhiyun out_offs = out_w * out_h;
208*4882a593Smuzhiyun if (out_fmt & FMT_FBC) {
209*4882a593Smuzhiyun out_w = ALIGN(out_w, 16);
210*4882a593Smuzhiyun out_h = ALIGN(out_h, 16);
211*4882a593Smuzhiyun out_offs = out_w * out_h >> 4;
212*4882a593Smuzhiyun out_size = out_offs;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun out_size += (out_fmt & FMT_YUV422) ?
215*4882a593Smuzhiyun out_w * out_h * 2 : out_w * out_h * 3 / 2;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* input picture buf */
218*4882a593Smuzhiyun mem = fec_buf_add(file, buf->in_pic_fd, in_size);
219*4882a593Smuzhiyun if (!mem)
220*4882a593Smuzhiyun goto free_buf;
221*4882a593Smuzhiyun val = *((dma_addr_t *)g_ops->cookie(mem));
222*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_RD_Y_BASE);
223*4882a593Smuzhiyun val += in_offs;
224*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_RD_UV_BASE);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* output picture buf */
227*4882a593Smuzhiyun mem = fec_buf_add(file, buf->out_pic_fd, out_size);
228*4882a593Smuzhiyun if (!mem)
229*4882a593Smuzhiyun goto free_buf;
230*4882a593Smuzhiyun val = *((dma_addr_t *)g_ops->cookie(mem));
231*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_WR_Y_BASE);
232*4882a593Smuzhiyun val += out_offs;
233*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_WR_UV_BASE);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /* mesh xint buf */
236*4882a593Smuzhiyun mem = fec_buf_add(file, buf->mesh_xint_fd, mesh_size * 2);
237*4882a593Smuzhiyun if (!mem)
238*4882a593Smuzhiyun goto free_buf;
239*4882a593Smuzhiyun val = *((dma_addr_t *)g_ops->cookie(mem));
240*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_MESH_XINT_BASE);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* mesh xfra buf */
243*4882a593Smuzhiyun mem = fec_buf_add(file, buf->mesh_xfra_fd, mesh_size);
244*4882a593Smuzhiyun if (!mem)
245*4882a593Smuzhiyun goto free_buf;
246*4882a593Smuzhiyun val = *((dma_addr_t *)g_ops->cookie(mem));
247*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_MESH_XFRA_BASE);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* mesh yint buf */
250*4882a593Smuzhiyun mem = fec_buf_add(file, buf->mesh_yint_fd, mesh_size * 2);
251*4882a593Smuzhiyun if (!mem)
252*4882a593Smuzhiyun goto free_buf;
253*4882a593Smuzhiyun val = *((dma_addr_t *)g_ops->cookie(mem));
254*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_MESH_YINT_BASE);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /* mesh yfra buf */
257*4882a593Smuzhiyun mem = fec_buf_add(file, buf->mesh_yfra_fd, mesh_size);
258*4882a593Smuzhiyun if (!mem)
259*4882a593Smuzhiyun goto free_buf;
260*4882a593Smuzhiyun val = *((dma_addr_t *)g_ops->cookie(mem));
261*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_MESH_YFRA_BASE);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun val = out_fmt << 4 | in_fmt;
264*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_CTRL);
265*4882a593Smuzhiyun val = ALIGN(in_w * in_mult, 16) >> 2;
266*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_RD_VIR_STRIDE);
267*4882a593Smuzhiyun val = ALIGN(out_w * out_mult, 16) >> 2;
268*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_WR_VIR_STRIDE);
269*4882a593Smuzhiyun val = out_h << 16 | out_w;
270*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_DST_SIZE);
271*4882a593Smuzhiyun val = in_h << 16 | in_w;
272*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_SRC_SIZE);
273*4882a593Smuzhiyun writel(mesh_size, base + RKISPP_FEC_MESH_SIZE);
274*4882a593Smuzhiyun val = SW_FEC_EN | density;
275*4882a593Smuzhiyun writel(val, base + RKISPP_FEC_CORE_CTRL);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun writel(FEC_FORCE_UPD, base + RKISPP_CTRL_UPDATE);
278*4882a593Smuzhiyun v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
279*4882a593Smuzhiyun "0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n"
280*4882a593Smuzhiyun "0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n"
281*4882a593Smuzhiyun "0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x 0x%x:0x%x\n",
282*4882a593Smuzhiyun RKISPP_CTRL_SYS_STATUS, readl(base + RKISPP_CTRL_SYS_STATUS),
283*4882a593Smuzhiyun RKISPP_FEC_CTRL, readl(base + RKISPP_FEC_CTRL),
284*4882a593Smuzhiyun RKISPP_FEC_RD_VIR_STRIDE, readl(base + RKISPP_FEC_RD_VIR_STRIDE),
285*4882a593Smuzhiyun RKISPP_FEC_WR_VIR_STRIDE, readl(base + RKISPP_FEC_WR_VIR_STRIDE),
286*4882a593Smuzhiyun RKISPP_FEC_RD_Y_BASE_SHD, readl(base + RKISPP_FEC_RD_Y_BASE_SHD),
287*4882a593Smuzhiyun RKISPP_FEC_RD_UV_BASE_SHD, readl(base + RKISPP_FEC_RD_UV_BASE_SHD),
288*4882a593Smuzhiyun RKISPP_FEC_MESH_XINT_BASE_SHD, readl(base + RKISPP_FEC_MESH_XINT_BASE_SHD),
289*4882a593Smuzhiyun RKISPP_FEC_MESH_XFRA_BASE_SHD, readl(base + RKISPP_FEC_MESH_XFRA_BASE_SHD),
290*4882a593Smuzhiyun RKISPP_FEC_MESH_YINT_BASE_SHD, readl(base + RKISPP_FEC_MESH_YINT_BASE_SHD),
291*4882a593Smuzhiyun RKISPP_FEC_MESH_YFRA_BASE_SHD, readl(base + RKISPP_FEC_MESH_YFRA_BASE_SHD),
292*4882a593Smuzhiyun RKISPP_FEC_WR_Y_BASE_SHD, readl(base + RKISPP_FEC_WR_Y_BASE_SHD),
293*4882a593Smuzhiyun RKISPP_FEC_WR_UV_BASE_SHD, readl(base + RKISPP_FEC_WR_UV_BASE_SHD),
294*4882a593Smuzhiyun RKISPP_FEC_CORE_CTRL, readl(base + RKISPP_FEC_CORE_CTRL),
295*4882a593Smuzhiyun RKISPP_FEC_DST_SIZE, readl(base + RKISPP_FEC_DST_SIZE),
296*4882a593Smuzhiyun RKISPP_FEC_SRC_SIZE, readl(base + RKISPP_FEC_SRC_SIZE),
297*4882a593Smuzhiyun RKISPP_FEC_MESH_SIZE, readl(base + RKISPP_FEC_MESH_SIZE));
298*4882a593Smuzhiyun if (!fec->hw->is_shutdown)
299*4882a593Smuzhiyun writel(FEC_ST, base + RKISPP_CTRL_STRT);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun ret = wait_for_completion_timeout(&fec->cmpl, msecs_to_jiffies(300));
302*4882a593Smuzhiyun if (!ret) {
303*4882a593Smuzhiyun v4l2_err(&fec->v4l2_dev, "fec working timeout\n");
304*4882a593Smuzhiyun ret = -EAGAIN;
305*4882a593Smuzhiyun } else {
306*4882a593Smuzhiyun ret = 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun writel(SW_FEC2DDR_DIS, base + RKISPP_FEC_CORE_CTRL);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (rkispp_debug)
311*4882a593Smuzhiyun us = ktime_us_delta(ktime_get(), t);
312*4882a593Smuzhiyun v4l2_dbg(3, rkispp_debug, &fec->v4l2_dev,
313*4882a593Smuzhiyun "%s exit ret:%d, time:%lldus\n", __func__, ret, us);
314*4882a593Smuzhiyun return ret;
315*4882a593Smuzhiyun free_buf:
316*4882a593Smuzhiyun fec_buf_del(file, 0, true);
317*4882a593Smuzhiyun return ret;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
fec_ioctl_default(struct file * file,void * fh,bool valid_prio,unsigned int cmd,void * arg)320*4882a593Smuzhiyun static long fec_ioctl_default(struct file *file, void *fh,
321*4882a593Smuzhiyun bool valid_prio, unsigned int cmd, void *arg)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun long ret = 0;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (!arg)
326*4882a593Smuzhiyun return -EINVAL;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun switch (cmd) {
329*4882a593Smuzhiyun case RKISPP_CMD_FEC_IN_OUT:
330*4882a593Smuzhiyun ret = fec_running(file, arg);
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun case RKISPP_CMD_FEC_BUF_ADD:
333*4882a593Smuzhiyun if (!fec_buf_add(file, *(int *)arg, 0))
334*4882a593Smuzhiyun ret = -ENOMEM;
335*4882a593Smuzhiyun break;
336*4882a593Smuzhiyun case RKISPP_CMD_FEC_BUF_DEL:
337*4882a593Smuzhiyun fec_buf_del(file, *(int *)arg, false);
338*4882a593Smuzhiyun break;
339*4882a593Smuzhiyun default:
340*4882a593Smuzhiyun ret = -EFAULT;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun return ret;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun static const struct v4l2_ioctl_ops fec_ioctl_ops = {
347*4882a593Smuzhiyun .vidioc_default = fec_ioctl_default,
348*4882a593Smuzhiyun };
349*4882a593Smuzhiyun
fec_open(struct file * file)350*4882a593Smuzhiyun static int fec_open(struct file *file)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun struct rkispp_fec_dev *fec = video_drvdata(file);
353*4882a593Smuzhiyun int ret;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun ret = v4l2_fh_open(file);
356*4882a593Smuzhiyun if (ret)
357*4882a593Smuzhiyun goto end;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun mutex_lock(&fec->hw->dev_lock);
360*4882a593Smuzhiyun ret = pm_runtime_get_sync(fec->hw->dev);
361*4882a593Smuzhiyun mutex_unlock(&fec->hw->dev_lock);
362*4882a593Smuzhiyun if (ret < 0)
363*4882a593Smuzhiyun v4l2_fh_release(file);
364*4882a593Smuzhiyun end:
365*4882a593Smuzhiyun v4l2_dbg(1, rkispp_debug, &fec->v4l2_dev,
366*4882a593Smuzhiyun "%s ret:%d\n", __func__, ret);
367*4882a593Smuzhiyun return (ret > 0) ? 0 : ret;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
fec_release(struct file * file)370*4882a593Smuzhiyun static int fec_release(struct file *file)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun struct rkispp_fec_dev *fec = video_drvdata(file);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun v4l2_dbg(1, rkispp_debug, &fec->v4l2_dev, "%s\n", __func__);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun v4l2_fh_release(file);
377*4882a593Smuzhiyun fec_buf_del(file, 0, true);
378*4882a593Smuzhiyun mutex_lock(&fec->hw->dev_lock);
379*4882a593Smuzhiyun pm_runtime_put_sync(fec->hw->dev);
380*4882a593Smuzhiyun mutex_unlock(&fec->hw->dev_lock);
381*4882a593Smuzhiyun return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun static const struct v4l2_file_operations fec_fops = {
385*4882a593Smuzhiyun .owner = THIS_MODULE,
386*4882a593Smuzhiyun .open = fec_open,
387*4882a593Smuzhiyun .release = fec_release,
388*4882a593Smuzhiyun .unlocked_ioctl = video_ioctl2,
389*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
390*4882a593Smuzhiyun .compat_ioctl32 = video_ioctl2,
391*4882a593Smuzhiyun #endif
392*4882a593Smuzhiyun };
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun static const struct video_device fec_videodev = {
395*4882a593Smuzhiyun .name = "rkispp_fec",
396*4882a593Smuzhiyun .vfl_dir = VFL_DIR_RX,
397*4882a593Smuzhiyun .fops = &fec_fops,
398*4882a593Smuzhiyun .ioctl_ops = &fec_ioctl_ops,
399*4882a593Smuzhiyun .minor = -1,
400*4882a593Smuzhiyun .release = video_device_release_empty,
401*4882a593Smuzhiyun };
402*4882a593Smuzhiyun
rkispp_fec_irq(struct rkispp_hw_dev * hw)403*4882a593Smuzhiyun void rkispp_fec_irq(struct rkispp_hw_dev *hw)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun v4l2_dbg(3, rkispp_debug, &hw->fec_dev.v4l2_dev,
406*4882a593Smuzhiyun "%s\n", __func__);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (!completion_done(&hw->fec_dev.cmpl))
409*4882a593Smuzhiyun complete(&hw->fec_dev.cmpl);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
rkispp_register_fec(struct rkispp_hw_dev * hw)412*4882a593Smuzhiyun int rkispp_register_fec(struct rkispp_hw_dev *hw)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun struct rkispp_fec_dev *fec = &hw->fec_dev;
415*4882a593Smuzhiyun struct v4l2_device *v4l2_dev;
416*4882a593Smuzhiyun struct video_device *vfd;
417*4882a593Smuzhiyun int ret;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_FEC))
420*4882a593Smuzhiyun return 0;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun fec->hw = hw;
423*4882a593Smuzhiyun hw->is_fec_ext = true;
424*4882a593Smuzhiyun v4l2_dev = &fec->v4l2_dev;
425*4882a593Smuzhiyun strlcpy(v4l2_dev->name, fec_videodev.name, sizeof(v4l2_dev->name));
426*4882a593Smuzhiyun ret = v4l2_device_register(hw->dev, v4l2_dev);
427*4882a593Smuzhiyun if (ret)
428*4882a593Smuzhiyun return ret;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun mutex_init(&fec->apilock);
431*4882a593Smuzhiyun fec->vfd = fec_videodev;
432*4882a593Smuzhiyun vfd = &fec->vfd;
433*4882a593Smuzhiyun vfd->device_caps = V4L2_CAP_STREAMING;
434*4882a593Smuzhiyun vfd->lock = &fec->apilock;
435*4882a593Smuzhiyun vfd->v4l2_dev = v4l2_dev;
436*4882a593Smuzhiyun ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
437*4882a593Smuzhiyun if (ret) {
438*4882a593Smuzhiyun v4l2_err(v4l2_dev, "Failed to register video device\n");
439*4882a593Smuzhiyun goto unreg_v4l2;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun video_set_drvdata(vfd, fec);
442*4882a593Smuzhiyun INIT_LIST_HEAD(&fec->list);
443*4882a593Smuzhiyun return 0;
444*4882a593Smuzhiyun unreg_v4l2:
445*4882a593Smuzhiyun mutex_destroy(&fec->apilock);
446*4882a593Smuzhiyun v4l2_device_unregister(v4l2_dev);
447*4882a593Smuzhiyun return ret;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
rkispp_unregister_fec(struct rkispp_hw_dev * hw)450*4882a593Smuzhiyun void rkispp_unregister_fec(struct rkispp_hw_dev *hw)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_FEC))
453*4882a593Smuzhiyun return;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun mutex_destroy(&hw->fec_dev.apilock);
456*4882a593Smuzhiyun video_unregister_device(&hw->fec_dev.vfd);
457*4882a593Smuzhiyun v4l2_device_unregister(&hw->fec_dev.v4l2_dev);
458*4882a593Smuzhiyun }
459