• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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