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