1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
3
4 #include <linux/compat.h>
5 #include <linux/delay.h>
6 #include <linux/interrupt.h>
7 #include <linux/iommu.h>
8 #include <linux/pm_runtime.h>
9 #include <linux/videodev2.h>
10 #include <media/media-entity.h>
11 #include <media/videobuf2-dma-contig.h>
12 #include <media/v4l2-event.h>
13
14 #include "dev.h"
15 #include "regs.h"
16
cal_fec_mesh(u32 width,u32 height,u32 mode)17 u32 cal_fec_mesh(u32 width, u32 height, u32 mode)
18 {
19 u32 mesh_size, mesh_left_height;
20 u32 w = ALIGN(width, 32);
21 u32 h = ALIGN(height, 32);
22 u32 spb_num = (h + 127) >> 7;
23 u32 left_height = h & 127;
24 u32 mesh_width = mode ? (w / 32 + 1) : (w / 16 + 1);
25 u32 mesh_height = mode ? 9 : 17;
26
27 if (!left_height)
28 left_height = 128;
29 mesh_left_height = mode ? (left_height / 16 + 1) :
30 (left_height / 8 + 1);
31 mesh_size = (spb_num - 1) * mesh_width * mesh_height +
32 mesh_width * mesh_left_height;
33
34 return mesh_size;
35 }
36
37 static const struct isppsd_fmt rkispp_formats[] = {
38 {
39 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
40 .fourcc = V4L2_PIX_FMT_NV16,
41 .wr_fmt = FMT_YUV422,
42 },
43 };
44
find_fmt(u32 mbus_code)45 static const struct isppsd_fmt *find_fmt(u32 mbus_code)
46 {
47 const struct isppsd_fmt *fmt;
48 int i, array_size = ARRAY_SIZE(rkispp_formats);
49
50 for (i = 0; i < array_size; i++) {
51 fmt = &rkispp_formats[i];
52 if (fmt->mbus_code == mbus_code)
53 return fmt;
54 }
55
56 return NULL;
57 }
58
rkispp_subdev_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)59 static int rkispp_subdev_link_setup(struct media_entity *entity,
60 const struct media_pad *local,
61 const struct media_pad *remote,
62 u32 flags)
63 {
64 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
65 struct rkispp_subdev *ispp_sdev;
66 struct rkispp_device *dev;
67 struct rkispp_stream_vdev *vdev;
68 struct rkispp_stream *stream = NULL;
69
70 if (local->index != RKISPP_PAD_SINK &&
71 local->index != RKISPP_PAD_SOURCE)
72 return 0;
73
74 if (!sd)
75 return -ENODEV;
76 ispp_sdev = v4l2_get_subdevdata(sd);
77 dev = ispp_sdev->dev;
78 vdev = &dev->stream_vdev;
79
80 if (!strcmp(remote->entity->name, II_VDEV_NAME)) {
81 stream = &vdev->stream[STREAM_II];
82 if (ispp_sdev->state & ISPP_START)
83 return -EBUSY;
84 if (flags & MEDIA_LNK_FL_ENABLED)
85 dev->inp = INP_DDR;
86 else if (ispp_sdev->remote_sd)
87 dev->inp = INP_ISP;
88 else
89 dev->inp = INP_INVAL;
90 stream->linked = flags & MEDIA_LNK_FL_ENABLED;
91 v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
92 "input:%d\n", dev->inp);
93 } else if (!strcmp(remote->entity->name, MB_VDEV_NAME)) {
94 stream = &vdev->stream[STREAM_MB];
95 } else if (!strcmp(remote->entity->name, S0_VDEV_NAME)) {
96 stream = &vdev->stream[STREAM_S0];
97 } else if (!strcmp(remote->entity->name, S1_VDEV_NAME)) {
98 stream = &vdev->stream[STREAM_S1];
99 } else if (!strcmp(remote->entity->name, S2_VDEV_NAME)) {
100 stream = &vdev->stream[STREAM_S2];
101 }
102 if (stream && dev->stream_sync) {
103 stream->linked = flags & MEDIA_LNK_FL_ENABLED;
104 v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
105 "stream:%d linked:%d\n",
106 stream->id, stream->linked);
107 }
108 return 0;
109 }
110
rkispp_sd_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)111 static int rkispp_sd_get_fmt(struct v4l2_subdev *sd,
112 struct v4l2_subdev_pad_config *cfg,
113 struct v4l2_subdev_format *fmt)
114 {
115 struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
116 struct v4l2_mbus_framefmt *mf;
117 const struct isppsd_fmt *ispp_fmt;
118 int ret = 0;
119
120 if (!fmt)
121 goto err;
122
123 if (fmt->pad != RKISPP_PAD_SINK &&
124 fmt->pad != RKISPP_PAD_SOURCE)
125 goto err;
126
127 mf = &fmt->format;
128 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
129 if (!cfg)
130 goto err;
131 mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
132 }
133
134 *mf = ispp_sdev->in_fmt;
135 if (fmt->pad == RKISPP_PAD_SINK && ispp_sdev->dev->inp == INP_ISP) {
136 ret = v4l2_subdev_call(ispp_sdev->remote_sd,
137 pad, get_fmt, cfg, fmt);
138 if (!ret) {
139 ispp_fmt = find_fmt(fmt->format.code);
140 if (!ispp_fmt)
141 goto err;
142 if (ispp_sdev->in_fmt.width != mf->width ||
143 ispp_sdev->in_fmt.height != mf->height) {
144 ispp_sdev->out_fmt = *ispp_fmt;
145 ispp_sdev->out_fmt.width = mf->width;
146 ispp_sdev->out_fmt.height = mf->height;
147 }
148 ispp_sdev->in_fmt = *mf;
149 }
150 } else {
151 *mf = ispp_sdev->in_fmt;
152 mf->width = ispp_sdev->out_fmt.width;
153 mf->height = ispp_sdev->out_fmt.height;
154 }
155 return ret;
156 err:
157 return -EINVAL;
158 }
159
rkispp_sd_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)160 static int rkispp_sd_set_fmt(struct v4l2_subdev *sd,
161 struct v4l2_subdev_pad_config *cfg,
162 struct v4l2_subdev_format *fmt)
163 {
164 struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
165 struct v4l2_mbus_framefmt *mf;
166
167 if (!fmt)
168 return -EINVAL;
169
170 /* format from isp output */
171 if (fmt->pad == RKISPP_PAD_SINK && ispp_sdev->dev->inp == INP_ISP)
172 return 0;
173
174 mf = &fmt->format;
175 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
176 if (!cfg)
177 return -EINVAL;
178 mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
179 }
180
181 if (fmt->pad == RKISPP_PAD_SINK) {
182 ispp_sdev->in_fmt = *mf;
183 } else {
184 ispp_sdev->out_fmt.width = mf->width;
185 ispp_sdev->out_fmt.height = mf->height;
186 }
187
188 return 0;
189 }
190
rkispp_sd_s_stream(struct v4l2_subdev * sd,int on)191 static int rkispp_sd_s_stream(struct v4l2_subdev *sd, int on)
192 {
193 struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
194 struct rkispp_device *dev = ispp_sdev->dev;
195 int ret = 0;
196
197 v4l2_dbg(1, rkispp_debug, &ispp_sdev->dev->v4l2_dev,
198 "s_stream on:%d\n", on);
199
200 if (on) {
201 ispp_sdev->state = ISPP_START;
202 ispp_sdev->frm_sync_seq = -1;
203 ispp_sdev->frame_timestamp = 0;
204 rkispp_event_handle(dev, CMD_STREAM, &ispp_sdev->state);
205 }
206
207 if (dev->inp == INP_ISP)
208 ret = v4l2_subdev_call(ispp_sdev->remote_sd, video, s_stream, on);
209
210 if ((on && ret) || (!on && !ret)) {
211 ispp_sdev->state = ISPP_STOP;
212 if (dev->stream_vdev.monitor.is_en) {
213 dev->stream_vdev.monitor.is_en = false;
214 if (!completion_done(&dev->stream_vdev.monitor.cmpl))
215 complete(&dev->stream_vdev.monitor.cmpl);
216 if (!completion_done(&dev->stream_vdev.monitor.tnr.cmpl))
217 complete(&dev->stream_vdev.monitor.tnr.cmpl);
218 if (!completion_done(&dev->stream_vdev.monitor.nr.cmpl))
219 complete(&dev->stream_vdev.monitor.nr.cmpl);
220 if (!completion_done(&dev->stream_vdev.monitor.fec.cmpl))
221 complete(&dev->stream_vdev.monitor.fec.cmpl);
222 }
223 rkispp_event_handle(dev, CMD_STREAM, &ispp_sdev->state);
224 }
225 return ret;
226 }
227
rkispp_sd_s_rx_buffer(struct v4l2_subdev * sd,void * buf,unsigned int * size)228 static int rkispp_sd_s_rx_buffer(struct v4l2_subdev *sd,
229 void *buf, unsigned int *size)
230 {
231 struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
232 struct rkispp_device *dev = ispp_sdev->dev;
233 u32 cmd = CMD_INIT_POOL;
234
235 /* size isn't using now */
236 if (!buf)
237 return -EINVAL;
238
239 if (ispp_sdev->state == ISPP_START) {
240 struct rkisp_ispp_buf *dbufs = buf;
241 struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
242 u64 ns = ktime_get_ns();
243
244 vdev->dbg.interval = ns - vdev->dbg.timestamp;
245 vdev->dbg.timestamp = ns;
246 vdev->dbg.delay = ns - dbufs->frame_timestamp;
247 vdev->dbg.id = dbufs->frame_id;
248 cmd = CMD_QUEUE_DMABUF;
249 }
250
251 return rkispp_event_handle(dev, cmd, buf);
252 }
253
rkispp_sd_s_power(struct v4l2_subdev * sd,int on)254 static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
255 {
256 struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
257 struct rkispp_device *ispp_dev = ispp_sdev->dev;
258 int ret;
259
260 v4l2_dbg(1, rkispp_debug, &ispp_dev->v4l2_dev,
261 "s_power on:%d\n", on);
262 if (on) {
263 if (ispp_dev->inp == INP_ISP) {
264 struct v4l2_subdev_format fmt;
265
266 /* update format, if ispp input change */
267 fmt.pad = RKISPP_PAD_SINK;
268 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
269 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
270 if (ret) {
271 v4l2_err(&ispp_dev->v4l2_dev,
272 "%s get format fail:%d\n",
273 __func__, ret);
274 return ret;
275 }
276
277 ret = v4l2_subdev_call(ispp_sdev->remote_sd,
278 core, s_power, 1);
279 if (ret < 0) {
280 v4l2_err(&ispp_dev->v4l2_dev,
281 "%s set isp power on fail:%d\n",
282 __func__, ret);
283 return ret;
284 }
285 }
286 ret = pm_runtime_get_sync(ispp_dev->dev);
287 if (ret < 0) {
288 v4l2_err(&ispp_dev->v4l2_dev,
289 "%s runtime get failed:%d\n",
290 __func__, ret);
291 if (ispp_dev->inp == INP_ISP)
292 v4l2_subdev_call(ispp_sdev->remote_sd,
293 core, s_power, 0);
294 return ret;
295 }
296 } else {
297 if (ispp_dev->inp == INP_ISP)
298 v4l2_subdev_call(ispp_sdev->remote_sd, core, s_power, 0);
299 ret = pm_runtime_put_sync(ispp_dev->dev);
300 if (ret < 0)
301 v4l2_err(&ispp_dev->v4l2_dev,
302 "%s runtime put failed:%d\n",
303 __func__, ret);
304 }
305
306 return ret;
307 }
308
rkispp_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)309 static long rkispp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
310 {
311 struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
312 struct rkispp_device *ispp_dev = ispp_sdev->dev;
313 struct rkispp_fecbuf_info *fecbuf;
314 struct rkispp_fecbuf_size *fecsize;
315 struct rkisp_ispp_reg **reg_buf;
316 bool *rkispp_reg_withstream;
317 long ret = 0;
318
319 if (!arg)
320 return -EINVAL;
321
322 switch (cmd) {
323 case RKISPP_CMD_SET_INIT_MODULE:
324 ispp_dev->stream_vdev.module_ens = *((int *)arg);
325 if (ispp_dev->hw_dev->is_fec_ext)
326 ispp_dev->stream_vdev.module_ens &= ~ISPP_MODULE_FEC_ST;
327 break;
328 case RKISPP_CMD_GET_FECBUF_INFO:
329 fecbuf = (struct rkispp_fecbuf_info *)arg;
330 rkispp_params_get_fecbuf_inf(&ispp_dev->params_vdev[PARAM_VDEV_FEC], fecbuf);
331 break;
332 case RKISPP_CMD_SET_FECBUF_SIZE:
333 fecsize = (struct rkispp_fecbuf_size *)arg;
334 rkispp_params_set_fecbuf_size(&ispp_dev->params_vdev[PARAM_VDEV_FEC], fecsize);
335 break;
336 case RKISP_ISPP_CMD_REQUEST_REGBUF:
337 reg_buf = (struct rkisp_ispp_reg **)arg;
338 rkispp_request_regbuf(ispp_dev, reg_buf);
339 break;
340 case RKISP_ISPP_CMD_GET_REG_WITHSTREAM:
341 rkispp_reg_withstream = arg;
342 *rkispp_reg_withstream = rkispp_is_reg_withstream_global();
343 break;
344 #if IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_VERSION_V10)
345 case RKISPP_CMD_GET_TNRBUF_FD:
346 ret = rkispp_get_tnrbuf_fd(ispp_dev, (struct rkispp_buf_idxfd *)arg);
347 break;
348 case RKISPP_CMD_GET_NRBUF_FD:
349 ret = rkispp_get_nrbuf_fd(ispp_dev, (struct rkispp_buf_idxfd *)arg);
350 break;
351 case RKISPP_CMD_TRIGGER_MODE:
352 rkispp_set_trigger_mode(ispp_dev, (struct rkispp_trigger_mode *)arg);
353 break;
354 #endif
355 default:
356 ret = -ENOIOCTLCMD;
357 }
358
359 return ret;
360 }
361
362 #ifdef CONFIG_COMPAT
rkispp_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)363 static long rkispp_compat_ioctl32(struct v4l2_subdev *sd,
364 unsigned int cmd, unsigned long arg)
365 {
366 void __user *up = compat_ptr(arg);
367 struct rkispp_fecbuf_info fecbuf;
368 struct rkispp_fecbuf_size fecsize;
369 struct rkispp_buf_idxfd idxfd;
370 struct rkispp_trigger_mode t_mode;
371 long ret = 0;
372
373 if (!up)
374 return -EINVAL;
375
376 switch (cmd) {
377 case RKISPP_CMD_GET_FECBUF_INFO:
378 ret = rkispp_ioctl(sd, cmd, &fecbuf);
379 if (!ret && copy_to_user(up, &fecbuf, sizeof(fecbuf)))
380 ret = -EFAULT;
381 break;
382 case RKISPP_CMD_SET_FECBUF_SIZE:
383 if (copy_from_user(&fecsize, up, sizeof(fecsize)))
384 return -EFAULT;
385 ret = rkispp_ioctl(sd, cmd, &fecsize);
386 break;
387 case RKISPP_CMD_GET_TNRBUF_FD:
388 case RKISPP_CMD_GET_NRBUF_FD:
389 ret = rkispp_ioctl(sd, cmd, &idxfd);
390 if (!ret && copy_to_user(up, &idxfd, sizeof(idxfd)))
391 ret = -EFAULT;
392 break;
393 case RKISPP_CMD_TRIGGER_MODE:
394 if (copy_from_user(&t_mode, up, sizeof(t_mode)))
395 return -EFAULT;
396 ret = rkispp_ioctl(sd, cmd, &t_mode);
397 break;
398 default:
399 ret = -ENOIOCTLCMD;
400 }
401
402 return ret;
403 }
404 #endif
405
rkispp_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)406 static int rkispp_subscribe_event(struct v4l2_subdev *sd,
407 struct v4l2_fh *fh,
408 struct v4l2_event_subscription *sub)
409 {
410 switch (sub->type) {
411 case RKISPP_V4L2_EVENT_TNR_COMPLETE:
412 return v4l2_event_subscribe(fh, sub, RKISPP_BUF_MAX, NULL);
413 default:
414 return -EINVAL;
415 }
416 }
417
418 static const struct media_entity_operations rkispp_sd_media_ops = {
419 .link_setup = rkispp_subdev_link_setup,
420 .link_validate = v4l2_subdev_link_validate,
421 };
422
423 static const struct v4l2_subdev_pad_ops rkispp_sd_pad_ops = {
424 .get_fmt = rkispp_sd_get_fmt,
425 .set_fmt = rkispp_sd_set_fmt,
426 };
427
428 static const struct v4l2_subdev_video_ops rkispp_sd_video_ops = {
429 .s_stream = rkispp_sd_s_stream,
430 .s_rx_buffer = rkispp_sd_s_rx_buffer,
431 };
432
433 static const struct v4l2_subdev_core_ops rkispp_sd_core_ops = {
434 .s_power = rkispp_sd_s_power,
435 .ioctl = rkispp_ioctl,
436 #ifdef CONFIG_COMPAT
437 .compat_ioctl32 = rkispp_compat_ioctl32,
438 #endif
439 .subscribe_event = rkispp_subscribe_event,
440 .unsubscribe_event = v4l2_event_subdev_unsubscribe,
441 };
442
443 static struct v4l2_subdev_ops rkispp_sd_ops = {
444 .core = &rkispp_sd_core_ops,
445 .video = &rkispp_sd_video_ops,
446 .pad = &rkispp_sd_pad_ops,
447 };
448
rkispp_register_subdev(struct rkispp_device * dev,struct v4l2_device * v4l2_dev)449 int rkispp_register_subdev(struct rkispp_device *dev,
450 struct v4l2_device *v4l2_dev)
451 {
452 struct rkispp_subdev *ispp_sdev = &dev->ispp_sdev;
453 struct v4l2_subdev *sd;
454 int ret;
455
456 memset(ispp_sdev, 0, sizeof(*ispp_sdev));
457 ispp_sdev->dev = dev;
458 sd = &ispp_sdev->sd;
459 ispp_sdev->state = ISPP_STOP;
460 v4l2_subdev_init(sd, &rkispp_sd_ops);
461 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
462 sd->entity.ops = &rkispp_sd_media_ops;
463 snprintf(sd->name, sizeof(sd->name), "rkispp-subdev");
464 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_COMPOSER;
465 ispp_sdev->pads[RKISPP_PAD_SINK].flags =
466 MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
467 ispp_sdev->pads[RKISPP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK;
468 ispp_sdev->pads[RKISPP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
469 ispp_sdev->pads[RKISPP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE;
470
471 ret = media_entity_pads_init(&sd->entity, RKISPP_PAD_MAX,
472 ispp_sdev->pads);
473 if (ret < 0)
474 return ret;
475 sd->owner = THIS_MODULE;
476 v4l2_set_subdevdata(sd, ispp_sdev);
477 sd->grp_id = GRP_ID_ISPP;
478 ret = v4l2_device_register_subdev(v4l2_dev, sd);
479 if (ret < 0)
480 goto free_media;
481
482 ret = v4l2_device_register_subdev_nodes(v4l2_dev);
483 if (ret < 0)
484 goto free_subdev;
485 return ret;
486 free_subdev:
487 v4l2_device_unregister_subdev(sd);
488 free_media:
489 media_entity_cleanup(&sd->entity);
490 v4l2_err(sd, "Failed to register subdev, ret:%d\n", ret);
491 return ret;
492 }
493
rkispp_unregister_subdev(struct rkispp_device * dev)494 void rkispp_unregister_subdev(struct rkispp_device *dev)
495 {
496 struct v4l2_subdev *sd = &dev->ispp_sdev.sd;
497
498 v4l2_device_unregister_subdev(sd);
499 media_entity_cleanup(&sd->entity);
500 }
501