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