1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * V4L2 Capture IC Preprocess Subdev for Freescale i.MX5/6 SOC
4 *
5 * This subdevice handles capture of video frames from the CSI or VDIC,
6 * which are routed directly to the Image Converter preprocess tasks,
7 * for resizing, colorspace conversion, and rotation.
8 *
9 * Copyright (c) 2012-2017 Mentor Graphics Inc.
10 */
11#include <linux/delay.h>
12#include <linux/interrupt.h>
13#include <linux/module.h>
14#include <linux/sched.h>
15#include <linux/slab.h>
16#include <linux/spinlock.h>
17#include <linux/timer.h>
18#include <media/v4l2-ctrls.h>
19#include <media/v4l2-device.h>
20#include <media/v4l2-ioctl.h>
21#include <media/v4l2-mc.h>
22#include <media/v4l2-subdev.h>
23#include <media/imx.h>
24#include "imx-media.h"
25#include "imx-ic.h"
26
27/*
28 * Min/Max supported width and heights.
29 *
30 * We allow planar output, so we have to align width at the source pad
31 * by 16 pixels to meet IDMAC alignment requirements for possible planar
32 * output.
33 *
34 * TODO: move this into pad format negotiation, if capture device
35 * has not requested a planar format, we should allow 8 pixel
36 * alignment at the source pad.
37 */
38#define MIN_W_SINK 32
39#define MIN_H_SINK 32
40#define MAX_W_SINK 4096
41#define MAX_H_SINK 4096
42#define W_ALIGN_SINK 3 /* multiple of 8 pixels */
43#define H_ALIGN_SINK 1 /* multiple of 2 lines */
44
45#define MAX_W_SRC 1024
46#define MAX_H_SRC 1024
47#define W_ALIGN_SRC 1 /* multiple of 2 pixels */
48#define H_ALIGN_SRC 1 /* multiple of 2 lines */
49
50#define S_ALIGN 1 /* multiple of 2 */
51
52struct prp_priv {
53 struct imx_ic_priv *ic_priv;
54 struct media_pad pad[PRPENCVF_NUM_PADS];
55 /* the video device at output pad */
56 struct imx_media_video_dev *vdev;
57
58 /* lock to protect all members below */
59 struct mutex lock;
60
61 /* IPU units we require */
62 struct ipu_ic *ic;
63 struct ipuv3_channel *out_ch;
64 struct ipuv3_channel *rot_in_ch;
65 struct ipuv3_channel *rot_out_ch;
66
67 /* active vb2 buffers to send to video dev sink */
68 struct imx_media_buffer *active_vb2_buf[2];
69 struct imx_media_dma_buf underrun_buf;
70
71 int ipu_buf_num; /* ipu double buffer index: 0-1 */
72
73 /* the sink for the captured frames */
74 struct media_entity *sink;
75 /* the source subdev */
76 struct v4l2_subdev *src_sd;
77
78 struct v4l2_mbus_framefmt format_mbus[PRPENCVF_NUM_PADS];
79 const struct imx_media_pixfmt *cc[PRPENCVF_NUM_PADS];
80 struct v4l2_fract frame_interval;
81
82 struct imx_media_dma_buf rot_buf[2];
83
84 /* controls */
85 struct v4l2_ctrl_handler ctrl_hdlr;
86 int rotation; /* degrees */
87 bool hflip;
88 bool vflip;
89
90 /* derived from rotation, hflip, vflip controls */
91 enum ipu_rotate_mode rot_mode;
92
93 spinlock_t irqlock; /* protect eof_irq handler */
94
95 struct timer_list eof_timeout_timer;
96 int eof_irq;
97 int nfb4eof_irq;
98
99 int stream_count;
100 u32 frame_sequence; /* frame sequence counter */
101 bool last_eof; /* waiting for last EOF at stream off */
102 bool nfb4eof; /* NFB4EOF encountered during streaming */
103 bool interweave_swap; /* swap top/bottom lines when interweaving */
104 struct completion last_eof_comp;
105};
106
107static const struct prp_channels {
108 u32 out_ch;
109 u32 rot_in_ch;
110 u32 rot_out_ch;
111} prp_channel[] = {
112 [IC_TASK_ENCODER] = {
113 .out_ch = IPUV3_CHANNEL_IC_PRP_ENC_MEM,
114 .rot_in_ch = IPUV3_CHANNEL_MEM_ROT_ENC,
115 .rot_out_ch = IPUV3_CHANNEL_ROT_ENC_MEM,
116 },
117 [IC_TASK_VIEWFINDER] = {
118 .out_ch = IPUV3_CHANNEL_IC_PRP_VF_MEM,
119 .rot_in_ch = IPUV3_CHANNEL_MEM_ROT_VF,
120 .rot_out_ch = IPUV3_CHANNEL_ROT_VF_MEM,
121 },
122};
123
124static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
125{
126 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
127
128 return ic_priv->task_priv;
129}
130
131static void prp_put_ipu_resources(struct prp_priv *priv)
132{
133 if (priv->ic)
134 ipu_ic_put(ic: priv->ic);
135 priv->ic = NULL;
136
137 if (priv->out_ch)
138 ipu_idmac_put(priv->out_ch);
139 priv->out_ch = NULL;
140
141 if (priv->rot_in_ch)
142 ipu_idmac_put(priv->rot_in_ch);
143 priv->rot_in_ch = NULL;
144
145 if (priv->rot_out_ch)
146 ipu_idmac_put(priv->rot_out_ch);
147 priv->rot_out_ch = NULL;
148}
149
150static int prp_get_ipu_resources(struct prp_priv *priv)
151{
152 struct imx_ic_priv *ic_priv = priv->ic_priv;
153 struct ipu_ic *ic;
154 struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch;
155 int ret, task = ic_priv->task_id;
156
157 ic = ipu_ic_get(ipu: ic_priv->ipu, task);
158 if (IS_ERR(ptr: ic)) {
159 v4l2_err(&ic_priv->sd, "failed to get IC\n");
160 ret = PTR_ERR(ptr: ic);
161 goto out;
162 }
163 priv->ic = ic;
164
165 out_ch = ipu_idmac_get(ipu: ic_priv->ipu, channel: prp_channel[task].out_ch);
166 if (IS_ERR(ptr: out_ch)) {
167 v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
168 prp_channel[task].out_ch);
169 ret = PTR_ERR(ptr: out_ch);
170 goto out;
171 }
172 priv->out_ch = out_ch;
173
174 rot_in_ch = ipu_idmac_get(ipu: ic_priv->ipu, channel: prp_channel[task].rot_in_ch);
175 if (IS_ERR(ptr: rot_in_ch)) {
176 v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
177 prp_channel[task].rot_in_ch);
178 ret = PTR_ERR(ptr: rot_in_ch);
179 goto out;
180 }
181 priv->rot_in_ch = rot_in_ch;
182
183 rot_out_ch = ipu_idmac_get(ipu: ic_priv->ipu, channel: prp_channel[task].rot_out_ch);
184 if (IS_ERR(ptr: rot_out_ch)) {
185 v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
186 prp_channel[task].rot_out_ch);
187 ret = PTR_ERR(ptr: rot_out_ch);
188 goto out;
189 }
190 priv->rot_out_ch = rot_out_ch;
191
192 return 0;
193out:
194 prp_put_ipu_resources(priv);
195 return ret;
196}
197
198static void prp_vb2_buf_done(struct prp_priv *priv, struct ipuv3_channel *ch)
199{
200 struct imx_media_video_dev *vdev = priv->vdev;
201 struct imx_media_buffer *done, *next;
202 struct vb2_buffer *vb;
203 dma_addr_t phys;
204
205 done = priv->active_vb2_buf[priv->ipu_buf_num];
206 if (done) {
207 done->vbuf.field = vdev->fmt.field;
208 done->vbuf.sequence = priv->frame_sequence;
209 vb = &done->vbuf.vb2_buf;
210 vb->timestamp = ktime_get_ns();
211 vb2_buffer_done(vb, state: priv->nfb4eof ?
212 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
213 }
214
215 priv->frame_sequence++;
216 priv->nfb4eof = false;
217
218 /* get next queued buffer */
219 next = imx_media_capture_device_next_buf(vdev);
220 if (next) {
221 phys = vb2_dma_contig_plane_dma_addr(vb: &next->vbuf.vb2_buf, plane_no: 0);
222 priv->active_vb2_buf[priv->ipu_buf_num] = next;
223 } else {
224 phys = priv->underrun_buf.phys;
225 priv->active_vb2_buf[priv->ipu_buf_num] = NULL;
226 }
227
228 if (ipu_idmac_buffer_is_ready(channel: ch, buf_num: priv->ipu_buf_num))
229 ipu_idmac_clear_buffer(channel: ch, buf_num: priv->ipu_buf_num);
230
231 if (priv->interweave_swap && ch == priv->out_ch)
232 phys += vdev->fmt.bytesperline;
233
234 ipu_cpmem_set_buffer(ch, bufnum: priv->ipu_buf_num, buf: phys);
235}
236
237static irqreturn_t prp_eof_interrupt(int irq, void *dev_id)
238{
239 struct prp_priv *priv = dev_id;
240 struct ipuv3_channel *channel;
241
242 spin_lock(lock: &priv->irqlock);
243
244 if (priv->last_eof) {
245 complete(&priv->last_eof_comp);
246 priv->last_eof = false;
247 goto unlock;
248 }
249
250 channel = (ipu_rot_mode_is_irt(priv->rot_mode)) ?
251 priv->rot_out_ch : priv->out_ch;
252
253 prp_vb2_buf_done(priv, ch: channel);
254
255 /* select new IPU buf */
256 ipu_idmac_select_buffer(channel, buf_num: priv->ipu_buf_num);
257 /* toggle IPU double-buffer index */
258 priv->ipu_buf_num ^= 1;
259
260 /* bump the EOF timeout timer */
261 mod_timer(timer: &priv->eof_timeout_timer,
262 expires: jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
263
264unlock:
265 spin_unlock(lock: &priv->irqlock);
266 return IRQ_HANDLED;
267}
268
269static irqreturn_t prp_nfb4eof_interrupt(int irq, void *dev_id)
270{
271 struct prp_priv *priv = dev_id;
272 struct imx_ic_priv *ic_priv = priv->ic_priv;
273
274 spin_lock(lock: &priv->irqlock);
275
276 /*
277 * this is not an unrecoverable error, just mark
278 * the next captured frame with vb2 error flag.
279 */
280 priv->nfb4eof = true;
281
282 v4l2_err(&ic_priv->sd, "NFB4EOF\n");
283
284 spin_unlock(lock: &priv->irqlock);
285
286 return IRQ_HANDLED;
287}
288
289/*
290 * EOF timeout timer function.
291 */
292/*
293 * EOF timeout timer function. This is an unrecoverable condition
294 * without a stream restart.
295 */
296static void prp_eof_timeout(struct timer_list *t)
297{
298 struct prp_priv *priv = from_timer(priv, t, eof_timeout_timer);
299 struct imx_media_video_dev *vdev = priv->vdev;
300 struct imx_ic_priv *ic_priv = priv->ic_priv;
301
302 v4l2_err(&ic_priv->sd, "EOF timeout\n");
303
304 /* signal a fatal error to capture device */
305 imx_media_capture_device_error(vdev);
306}
307
308static void prp_setup_vb2_buf(struct prp_priv *priv, dma_addr_t *phys)
309{
310 struct imx_media_video_dev *vdev = priv->vdev;
311 struct imx_media_buffer *buf;
312 int i;
313
314 for (i = 0; i < 2; i++) {
315 buf = imx_media_capture_device_next_buf(vdev);
316 if (buf) {
317 priv->active_vb2_buf[i] = buf;
318 phys[i] = vb2_dma_contig_plane_dma_addr(
319 vb: &buf->vbuf.vb2_buf, plane_no: 0);
320 } else {
321 priv->active_vb2_buf[i] = NULL;
322 phys[i] = priv->underrun_buf.phys;
323 }
324 }
325}
326
327static void prp_unsetup_vb2_buf(struct prp_priv *priv,
328 enum vb2_buffer_state return_status)
329{
330 struct imx_media_buffer *buf;
331 int i;
332
333 /* return any remaining active frames with return_status */
334 for (i = 0; i < 2; i++) {
335 buf = priv->active_vb2_buf[i];
336 if (buf) {
337 struct vb2_buffer *vb = &buf->vbuf.vb2_buf;
338
339 vb->timestamp = ktime_get_ns();
340 vb2_buffer_done(vb, state: return_status);
341 }
342 }
343}
344
345static int prp_setup_channel(struct prp_priv *priv,
346 struct ipuv3_channel *channel,
347 enum ipu_rotate_mode rot_mode,
348 dma_addr_t addr0, dma_addr_t addr1,
349 bool rot_swap_width_height)
350{
351 struct imx_media_video_dev *vdev = priv->vdev;
352 const struct imx_media_pixfmt *outcc;
353 struct v4l2_mbus_framefmt *outfmt;
354 unsigned int burst_size;
355 struct ipu_image image;
356 bool interweave;
357 int ret;
358
359 outfmt = &priv->format_mbus[PRPENCVF_SRC_PAD];
360 outcc = vdev->cc;
361
362 ipu_cpmem_zero(ch: channel);
363
364 memset(&image, 0, sizeof(image));
365 image.pix = vdev->fmt;
366 image.rect = vdev->compose;
367
368 /*
369 * If the field type at capture interface is interlaced, and
370 * the output IDMAC pad is sequential, enable interweave at
371 * the IDMAC output channel.
372 */
373 interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) &&
374 V4L2_FIELD_IS_SEQUENTIAL(outfmt->field);
375 priv->interweave_swap = interweave &&
376 image.pix.field == V4L2_FIELD_INTERLACED_BT;
377
378 if (rot_swap_width_height) {
379 swap(image.pix.width, image.pix.height);
380 swap(image.rect.width, image.rect.height);
381 /* recalc stride using swapped width */
382 image.pix.bytesperline = outcc->planar ?
383 image.pix.width :
384 (image.pix.width * outcc->bpp) >> 3;
385 }
386
387 if (priv->interweave_swap && channel == priv->out_ch) {
388 /* start interweave scan at 1st top line (2nd line) */
389 image.rect.top = 1;
390 }
391
392 image.phys0 = addr0;
393 image.phys1 = addr1;
394
395 /*
396 * Skip writing U and V components to odd rows in the output
397 * channels for planar 4:2:0 (but not when enabling IDMAC
398 * interweaving, they are incompatible).
399 */
400 if ((channel == priv->out_ch && !interweave) ||
401 channel == priv->rot_out_ch) {
402 switch (image.pix.pixelformat) {
403 case V4L2_PIX_FMT_YUV420:
404 case V4L2_PIX_FMT_YVU420:
405 case V4L2_PIX_FMT_NV12:
406 ipu_cpmem_skip_odd_chroma_rows(ch: channel);
407 break;
408 }
409 }
410
411 ret = ipu_cpmem_set_image(ch: channel, image: &image);
412 if (ret)
413 return ret;
414
415 if (channel == priv->rot_in_ch ||
416 channel == priv->rot_out_ch) {
417 burst_size = 8;
418 ipu_cpmem_set_block_mode(ch: channel);
419 } else {
420 burst_size = (image.pix.width & 0xf) ? 8 : 16;
421 }
422
423 ipu_cpmem_set_burstsize(ch: channel, burstsize: burst_size);
424
425 if (rot_mode)
426 ipu_cpmem_set_rotation(ch: channel, rot: rot_mode);
427
428 if (interweave && channel == priv->out_ch)
429 ipu_cpmem_interlaced_scan(ch: channel,
430 stride: priv->interweave_swap ?
431 -image.pix.bytesperline :
432 image.pix.bytesperline,
433 pixelformat: image.pix.pixelformat);
434
435 ret = ipu_ic_task_idma_init(ic: priv->ic, channel,
436 width: image.pix.width, height: image.pix.height,
437 burst_size, rot: rot_mode);
438 if (ret)
439 return ret;
440
441 ipu_cpmem_set_axi_id(ch: channel, id: 1);
442
443 ipu_idmac_set_double_buffer(channel, doublebuffer: true);
444
445 return 0;
446}
447
448static int prp_setup_rotation(struct prp_priv *priv)
449{
450 struct imx_media_video_dev *vdev = priv->vdev;
451 struct imx_ic_priv *ic_priv = priv->ic_priv;
452 const struct imx_media_pixfmt *outcc, *incc;
453 struct v4l2_mbus_framefmt *infmt;
454 struct v4l2_pix_format *outfmt;
455 struct ipu_ic_csc csc;
456 dma_addr_t phys[2];
457 int ret;
458
459 infmt = &priv->format_mbus[PRPENCVF_SINK_PAD];
460 outfmt = &vdev->fmt;
461 incc = priv->cc[PRPENCVF_SINK_PAD];
462 outcc = vdev->cc;
463
464 ret = ipu_ic_calc_csc(csc: &csc,
465 in_enc: infmt->ycbcr_enc, in_quant: infmt->quantization,
466 in_cs: incc->cs,
467 out_enc: outfmt->ycbcr_enc, out_quant: outfmt->quantization,
468 out_cs: outcc->cs);
469 if (ret) {
470 v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n",
471 ret);
472 return ret;
473 }
474
475 ret = imx_media_alloc_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->rot_buf[0],
476 size: outfmt->sizeimage);
477 if (ret) {
478 v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[0], %d\n", ret);
479 return ret;
480 }
481 ret = imx_media_alloc_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->rot_buf[1],
482 size: outfmt->sizeimage);
483 if (ret) {
484 v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[1], %d\n", ret);
485 goto free_rot0;
486 }
487
488 ret = ipu_ic_task_init(ic: priv->ic, csc: &csc,
489 in_width: infmt->width, in_height: infmt->height,
490 out_width: outfmt->height, out_height: outfmt->width);
491 if (ret) {
492 v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret);
493 goto free_rot1;
494 }
495
496 /* init the IC-PRP-->MEM IDMAC channel */
497 ret = prp_setup_channel(priv, channel: priv->out_ch, rot_mode: IPU_ROTATE_NONE,
498 addr0: priv->rot_buf[0].phys, addr1: priv->rot_buf[1].phys,
499 rot_swap_width_height: true);
500 if (ret) {
501 v4l2_err(&ic_priv->sd,
502 "prp_setup_channel(out_ch) failed, %d\n", ret);
503 goto free_rot1;
504 }
505
506 /* init the MEM-->IC-PRP ROT IDMAC channel */
507 ret = prp_setup_channel(priv, channel: priv->rot_in_ch, rot_mode: priv->rot_mode,
508 addr0: priv->rot_buf[0].phys, addr1: priv->rot_buf[1].phys,
509 rot_swap_width_height: true);
510 if (ret) {
511 v4l2_err(&ic_priv->sd,
512 "prp_setup_channel(rot_in_ch) failed, %d\n", ret);
513 goto free_rot1;
514 }
515
516 prp_setup_vb2_buf(priv, phys);
517
518 /* init the destination IC-PRP ROT-->MEM IDMAC channel */
519 ret = prp_setup_channel(priv, channel: priv->rot_out_ch, rot_mode: IPU_ROTATE_NONE,
520 addr0: phys[0], addr1: phys[1],
521 rot_swap_width_height: false);
522 if (ret) {
523 v4l2_err(&ic_priv->sd,
524 "prp_setup_channel(rot_out_ch) failed, %d\n", ret);
525 goto unsetup_vb2;
526 }
527
528 /* now link IC-PRP-->MEM to MEM-->IC-PRP ROT */
529 ipu_idmac_link(src: priv->out_ch, sink: priv->rot_in_ch);
530
531 /* enable the IC */
532 ipu_ic_enable(ic: priv->ic);
533
534 /* set buffers ready */
535 ipu_idmac_select_buffer(channel: priv->out_ch, buf_num: 0);
536 ipu_idmac_select_buffer(channel: priv->out_ch, buf_num: 1);
537 ipu_idmac_select_buffer(channel: priv->rot_out_ch, buf_num: 0);
538 ipu_idmac_select_buffer(channel: priv->rot_out_ch, buf_num: 1);
539
540 /* enable the channels */
541 ipu_idmac_enable_channel(channel: priv->out_ch);
542 ipu_idmac_enable_channel(channel: priv->rot_in_ch);
543 ipu_idmac_enable_channel(channel: priv->rot_out_ch);
544
545 /* and finally enable the IC PRP task */
546 ipu_ic_task_enable(ic: priv->ic);
547
548 return 0;
549
550unsetup_vb2:
551 prp_unsetup_vb2_buf(priv, return_status: VB2_BUF_STATE_QUEUED);
552free_rot1:
553 imx_media_free_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->rot_buf[1]);
554free_rot0:
555 imx_media_free_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->rot_buf[0]);
556 return ret;
557}
558
559static void prp_unsetup_rotation(struct prp_priv *priv)
560{
561 struct imx_ic_priv *ic_priv = priv->ic_priv;
562
563 ipu_ic_task_disable(ic: priv->ic);
564
565 ipu_idmac_disable_channel(channel: priv->out_ch);
566 ipu_idmac_disable_channel(channel: priv->rot_in_ch);
567 ipu_idmac_disable_channel(channel: priv->rot_out_ch);
568
569 ipu_idmac_unlink(src: priv->out_ch, sink: priv->rot_in_ch);
570
571 ipu_ic_disable(ic: priv->ic);
572
573 imx_media_free_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->rot_buf[0]);
574 imx_media_free_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->rot_buf[1]);
575}
576
577static int prp_setup_norotation(struct prp_priv *priv)
578{
579 struct imx_media_video_dev *vdev = priv->vdev;
580 struct imx_ic_priv *ic_priv = priv->ic_priv;
581 const struct imx_media_pixfmt *outcc, *incc;
582 struct v4l2_mbus_framefmt *infmt;
583 struct v4l2_pix_format *outfmt;
584 struct ipu_ic_csc csc;
585 dma_addr_t phys[2];
586 int ret;
587
588 infmt = &priv->format_mbus[PRPENCVF_SINK_PAD];
589 outfmt = &vdev->fmt;
590 incc = priv->cc[PRPENCVF_SINK_PAD];
591 outcc = vdev->cc;
592
593 ret = ipu_ic_calc_csc(csc: &csc,
594 in_enc: infmt->ycbcr_enc, in_quant: infmt->quantization,
595 in_cs: incc->cs,
596 out_enc: outfmt->ycbcr_enc, out_quant: outfmt->quantization,
597 out_cs: outcc->cs);
598 if (ret) {
599 v4l2_err(&ic_priv->sd, "ipu_ic_calc_csc failed, %d\n",
600 ret);
601 return ret;
602 }
603
604 ret = ipu_ic_task_init(ic: priv->ic, csc: &csc,
605 in_width: infmt->width, in_height: infmt->height,
606 out_width: outfmt->width, out_height: outfmt->height);
607 if (ret) {
608 v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret);
609 return ret;
610 }
611
612 prp_setup_vb2_buf(priv, phys);
613
614 /* init the IC PRP-->MEM IDMAC channel */
615 ret = prp_setup_channel(priv, channel: priv->out_ch, rot_mode: priv->rot_mode,
616 addr0: phys[0], addr1: phys[1], rot_swap_width_height: false);
617 if (ret) {
618 v4l2_err(&ic_priv->sd,
619 "prp_setup_channel(out_ch) failed, %d\n", ret);
620 goto unsetup_vb2;
621 }
622
623 ipu_cpmem_dump(ch: priv->out_ch);
624 ipu_ic_dump(ic: priv->ic);
625 ipu_dump(ipu: ic_priv->ipu);
626
627 ipu_ic_enable(ic: priv->ic);
628
629 /* set buffers ready */
630 ipu_idmac_select_buffer(channel: priv->out_ch, buf_num: 0);
631 ipu_idmac_select_buffer(channel: priv->out_ch, buf_num: 1);
632
633 /* enable the channels */
634 ipu_idmac_enable_channel(channel: priv->out_ch);
635
636 /* enable the IC task */
637 ipu_ic_task_enable(ic: priv->ic);
638
639 return 0;
640
641unsetup_vb2:
642 prp_unsetup_vb2_buf(priv, return_status: VB2_BUF_STATE_QUEUED);
643 return ret;
644}
645
646static void prp_unsetup_norotation(struct prp_priv *priv)
647{
648 ipu_ic_task_disable(ic: priv->ic);
649 ipu_idmac_disable_channel(channel: priv->out_ch);
650 ipu_ic_disable(ic: priv->ic);
651}
652
653static void prp_unsetup(struct prp_priv *priv,
654 enum vb2_buffer_state state)
655{
656 if (ipu_rot_mode_is_irt(priv->rot_mode))
657 prp_unsetup_rotation(priv);
658 else
659 prp_unsetup_norotation(priv);
660
661 prp_unsetup_vb2_buf(priv, return_status: state);
662}
663
664static int prp_start(struct prp_priv *priv)
665{
666 struct imx_ic_priv *ic_priv = priv->ic_priv;
667 struct imx_media_video_dev *vdev = priv->vdev;
668 int ret;
669
670 ret = prp_get_ipu_resources(priv);
671 if (ret)
672 return ret;
673
674 ret = imx_media_alloc_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->underrun_buf,
675 size: vdev->fmt.sizeimage);
676 if (ret)
677 goto out_put_ipu;
678
679 priv->ipu_buf_num = 0;
680
681 /* init EOF completion waitq */
682 init_completion(x: &priv->last_eof_comp);
683 priv->frame_sequence = 0;
684 priv->last_eof = false;
685 priv->nfb4eof = false;
686
687 if (ipu_rot_mode_is_irt(priv->rot_mode))
688 ret = prp_setup_rotation(priv);
689 else
690 ret = prp_setup_norotation(priv);
691 if (ret)
692 goto out_free_underrun;
693
694 priv->nfb4eof_irq = ipu_idmac_channel_irq(ipu: ic_priv->ipu,
695 channel: priv->out_ch,
696 irq: IPU_IRQ_NFB4EOF);
697 ret = devm_request_irq(dev: ic_priv->ipu_dev, irq: priv->nfb4eof_irq,
698 handler: prp_nfb4eof_interrupt, irqflags: 0,
699 devname: "imx-ic-prp-nfb4eof", dev_id: priv);
700 if (ret) {
701 v4l2_err(&ic_priv->sd,
702 "Error registering NFB4EOF irq: %d\n", ret);
703 goto out_unsetup;
704 }
705
706 if (ipu_rot_mode_is_irt(priv->rot_mode))
707 priv->eof_irq = ipu_idmac_channel_irq(
708 ipu: ic_priv->ipu, channel: priv->rot_out_ch, irq: IPU_IRQ_EOF);
709 else
710 priv->eof_irq = ipu_idmac_channel_irq(
711 ipu: ic_priv->ipu, channel: priv->out_ch, irq: IPU_IRQ_EOF);
712
713 ret = devm_request_irq(dev: ic_priv->ipu_dev, irq: priv->eof_irq,
714 handler: prp_eof_interrupt, irqflags: 0,
715 devname: "imx-ic-prp-eof", dev_id: priv);
716 if (ret) {
717 v4l2_err(&ic_priv->sd,
718 "Error registering eof irq: %d\n", ret);
719 goto out_free_nfb4eof_irq;
720 }
721
722 /* start upstream */
723 ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1);
724 ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
725 if (ret) {
726 v4l2_err(&ic_priv->sd,
727 "upstream stream on failed: %d\n", ret);
728 goto out_free_eof_irq;
729 }
730
731 /* start the EOF timeout timer */
732 mod_timer(timer: &priv->eof_timeout_timer,
733 expires: jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
734
735 return 0;
736
737out_free_eof_irq:
738 devm_free_irq(dev: ic_priv->ipu_dev, irq: priv->eof_irq, dev_id: priv);
739out_free_nfb4eof_irq:
740 devm_free_irq(dev: ic_priv->ipu_dev, irq: priv->nfb4eof_irq, dev_id: priv);
741out_unsetup:
742 prp_unsetup(priv, state: VB2_BUF_STATE_QUEUED);
743out_free_underrun:
744 imx_media_free_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->underrun_buf);
745out_put_ipu:
746 prp_put_ipu_resources(priv);
747 return ret;
748}
749
750static void prp_stop(struct prp_priv *priv)
751{
752 struct imx_ic_priv *ic_priv = priv->ic_priv;
753 unsigned long flags;
754 int ret;
755
756 /* mark next EOF interrupt as the last before stream off */
757 spin_lock_irqsave(&priv->irqlock, flags);
758 priv->last_eof = true;
759 spin_unlock_irqrestore(lock: &priv->irqlock, flags);
760
761 /*
762 * and then wait for interrupt handler to mark completion.
763 */
764 ret = wait_for_completion_timeout(
765 x: &priv->last_eof_comp,
766 timeout: msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
767 if (ret == 0)
768 v4l2_warn(&ic_priv->sd, "wait last EOF timeout\n");
769
770 /* stop upstream */
771 ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 0);
772 if (ret && ret != -ENOIOCTLCMD)
773 v4l2_warn(&ic_priv->sd,
774 "upstream stream off failed: %d\n", ret);
775
776 devm_free_irq(dev: ic_priv->ipu_dev, irq: priv->eof_irq, dev_id: priv);
777 devm_free_irq(dev: ic_priv->ipu_dev, irq: priv->nfb4eof_irq, dev_id: priv);
778
779 prp_unsetup(priv, state: VB2_BUF_STATE_ERROR);
780
781 imx_media_free_dma_buf(dev: ic_priv->ipu_dev, buf: &priv->underrun_buf);
782
783 /* cancel the EOF timeout timer */
784 del_timer_sync(timer: &priv->eof_timeout_timer);
785
786 prp_put_ipu_resources(priv);
787}
788
789static struct v4l2_mbus_framefmt *
790__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
791 unsigned int pad, enum v4l2_subdev_format_whence which)
792{
793 if (which == V4L2_SUBDEV_FORMAT_TRY)
794 return v4l2_subdev_state_get_format(sd_state, pad);
795 else
796 return &priv->format_mbus[pad];
797}
798
799/*
800 * Applies IC resizer and IDMAC alignment restrictions to output
801 * rectangle given the input rectangle, and depending on given
802 * rotation mode.
803 *
804 * The IC resizer cannot downsize more than 4:1. Note also that
805 * for 90 or 270 rotation, _both_ output width and height must
806 * be aligned by W_ALIGN_SRC, because the intermediate rotation
807 * buffer swaps output width/height, and the final output buffer
808 * does not.
809 *
810 * Returns true if the output rectangle was modified.
811 */
812static bool prp_bound_align_output(struct v4l2_mbus_framefmt *outfmt,
813 struct v4l2_mbus_framefmt *infmt,
814 enum ipu_rotate_mode rot_mode)
815{
816 u32 orig_width = outfmt->width;
817 u32 orig_height = outfmt->height;
818
819 if (ipu_rot_mode_is_irt(rot_mode))
820 v4l_bound_align_image(width: &outfmt->width,
821 wmin: infmt->height / 4, MAX_H_SRC,
822 W_ALIGN_SRC,
823 height: &outfmt->height,
824 hmin: infmt->width / 4, MAX_W_SRC,
825 W_ALIGN_SRC, S_ALIGN);
826 else
827 v4l_bound_align_image(width: &outfmt->width,
828 wmin: infmt->width / 4, MAX_W_SRC,
829 W_ALIGN_SRC,
830 height: &outfmt->height,
831 hmin: infmt->height / 4, MAX_H_SRC,
832 H_ALIGN_SRC, S_ALIGN);
833
834 return outfmt->width != orig_width || outfmt->height != orig_height;
835}
836
837/*
838 * V4L2 subdev operations.
839 */
840
841static int prp_enum_mbus_code(struct v4l2_subdev *sd,
842 struct v4l2_subdev_state *sd_state,
843 struct v4l2_subdev_mbus_code_enum *code)
844{
845 if (code->pad >= PRPENCVF_NUM_PADS)
846 return -EINVAL;
847
848 return imx_media_enum_ipu_formats(code: &code->code, index: code->index,
849 fmt_sel: PIXFMT_SEL_YUV_RGB);
850}
851
852static int prp_get_fmt(struct v4l2_subdev *sd,
853 struct v4l2_subdev_state *sd_state,
854 struct v4l2_subdev_format *sdformat)
855{
856 struct prp_priv *priv = sd_to_priv(sd);
857 struct v4l2_mbus_framefmt *fmt;
858 int ret = 0;
859
860 if (sdformat->pad >= PRPENCVF_NUM_PADS)
861 return -EINVAL;
862
863 mutex_lock(&priv->lock);
864
865 fmt = __prp_get_fmt(priv, sd_state, pad: sdformat->pad, which: sdformat->which);
866 if (!fmt) {
867 ret = -EINVAL;
868 goto out;
869 }
870
871 sdformat->format = *fmt;
872out:
873 mutex_unlock(lock: &priv->lock);
874 return ret;
875}
876
877static void prp_try_fmt(struct prp_priv *priv,
878 struct v4l2_subdev_state *sd_state,
879 struct v4l2_subdev_format *sdformat,
880 const struct imx_media_pixfmt **cc)
881{
882 struct v4l2_mbus_framefmt *infmt;
883
884 *cc = imx_media_find_ipu_format(code: sdformat->format.code,
885 fmt_sel: PIXFMT_SEL_YUV_RGB);
886 if (!*cc) {
887 u32 code;
888
889 imx_media_enum_ipu_formats(code: &code, index: 0, fmt_sel: PIXFMT_SEL_YUV_RGB);
890 *cc = imx_media_find_ipu_format(code, fmt_sel: PIXFMT_SEL_YUV_RGB);
891
892 sdformat->format.code = (*cc)->codes[0];
893 }
894
895 infmt = __prp_get_fmt(priv, sd_state, pad: PRPENCVF_SINK_PAD,
896 which: sdformat->which);
897
898 if (sdformat->pad == PRPENCVF_SRC_PAD) {
899 sdformat->format.field = infmt->field;
900
901 prp_bound_align_output(outfmt: &sdformat->format, infmt,
902 rot_mode: priv->rot_mode);
903
904 /* propagate colorimetry from sink */
905 sdformat->format.colorspace = infmt->colorspace;
906 sdformat->format.xfer_func = infmt->xfer_func;
907 } else {
908 v4l_bound_align_image(width: &sdformat->format.width,
909 MIN_W_SINK, MAX_W_SINK, W_ALIGN_SINK,
910 height: &sdformat->format.height,
911 MIN_H_SINK, MAX_H_SINK, H_ALIGN_SINK,
912 S_ALIGN);
913
914 if (sdformat->format.field == V4L2_FIELD_ANY)
915 sdformat->format.field = V4L2_FIELD_NONE;
916 }
917
918 imx_media_try_colorimetry(tryfmt: &sdformat->format, ic_route: true);
919}
920
921static int prp_set_fmt(struct v4l2_subdev *sd,
922 struct v4l2_subdev_state *sd_state,
923 struct v4l2_subdev_format *sdformat)
924{
925 struct prp_priv *priv = sd_to_priv(sd);
926 const struct imx_media_pixfmt *cc;
927 struct v4l2_mbus_framefmt *fmt;
928 int ret = 0;
929
930 if (sdformat->pad >= PRPENCVF_NUM_PADS)
931 return -EINVAL;
932
933 mutex_lock(&priv->lock);
934
935 if (priv->stream_count > 0) {
936 ret = -EBUSY;
937 goto out;
938 }
939
940 prp_try_fmt(priv, sd_state, sdformat, cc: &cc);
941
942 fmt = __prp_get_fmt(priv, sd_state, pad: sdformat->pad, which: sdformat->which);
943 *fmt = sdformat->format;
944
945 /* propagate a default format to source pad */
946 if (sdformat->pad == PRPENCVF_SINK_PAD) {
947 const struct imx_media_pixfmt *outcc;
948 struct v4l2_mbus_framefmt *outfmt;
949 struct v4l2_subdev_format format;
950
951 format.pad = PRPENCVF_SRC_PAD;
952 format.which = sdformat->which;
953 format.format = sdformat->format;
954 prp_try_fmt(priv, sd_state, sdformat: &format, cc: &outcc);
955
956 outfmt = __prp_get_fmt(priv, sd_state, pad: PRPENCVF_SRC_PAD,
957 which: sdformat->which);
958 *outfmt = format.format;
959 if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
960 priv->cc[PRPENCVF_SRC_PAD] = outcc;
961 }
962
963 if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
964 priv->cc[sdformat->pad] = cc;
965
966out:
967 mutex_unlock(lock: &priv->lock);
968 return ret;
969}
970
971static int prp_enum_frame_size(struct v4l2_subdev *sd,
972 struct v4l2_subdev_state *sd_state,
973 struct v4l2_subdev_frame_size_enum *fse)
974{
975 struct prp_priv *priv = sd_to_priv(sd);
976 struct v4l2_subdev_format format = {};
977 const struct imx_media_pixfmt *cc;
978 int ret = 0;
979
980 if (fse->pad >= PRPENCVF_NUM_PADS || fse->index != 0)
981 return -EINVAL;
982
983 mutex_lock(&priv->lock);
984
985 format.pad = fse->pad;
986 format.which = fse->which;
987 format.format.code = fse->code;
988 format.format.width = 1;
989 format.format.height = 1;
990 prp_try_fmt(priv, sd_state, sdformat: &format, cc: &cc);
991 fse->min_width = format.format.width;
992 fse->min_height = format.format.height;
993
994 if (format.format.code != fse->code) {
995 ret = -EINVAL;
996 goto out;
997 }
998
999 format.format.code = fse->code;
1000 format.format.width = -1;
1001 format.format.height = -1;
1002 prp_try_fmt(priv, sd_state, sdformat: &format, cc: &cc);
1003 fse->max_width = format.format.width;
1004 fse->max_height = format.format.height;
1005out:
1006 mutex_unlock(lock: &priv->lock);
1007 return ret;
1008}
1009
1010static int prp_link_setup(struct media_entity *entity,
1011 const struct media_pad *local,
1012 const struct media_pad *remote, u32 flags)
1013{
1014 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1015 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
1016 struct prp_priv *priv = ic_priv->task_priv;
1017 struct v4l2_subdev *remote_sd;
1018 int ret = 0;
1019
1020 dev_dbg(ic_priv->ipu_dev, "%s: link setup %s -> %s",
1021 ic_priv->sd.name, remote->entity->name, local->entity->name);
1022
1023 mutex_lock(&priv->lock);
1024
1025 if (local->flags & MEDIA_PAD_FL_SINK) {
1026 if (!is_media_entity_v4l2_subdev(entity: remote->entity)) {
1027 ret = -EINVAL;
1028 goto out;
1029 }
1030
1031 remote_sd = media_entity_to_v4l2_subdev(remote->entity);
1032
1033 if (flags & MEDIA_LNK_FL_ENABLED) {
1034 if (priv->src_sd) {
1035 ret = -EBUSY;
1036 goto out;
1037 }
1038 priv->src_sd = remote_sd;
1039 } else {
1040 priv->src_sd = NULL;
1041 }
1042
1043 goto out;
1044 }
1045
1046 /* this is the source pad */
1047
1048 /* the remote must be the device node */
1049 if (!is_media_entity_v4l2_video_device(entity: remote->entity)) {
1050 ret = -EINVAL;
1051 goto out;
1052 }
1053
1054 if (flags & MEDIA_LNK_FL_ENABLED) {
1055 if (priv->sink) {
1056 ret = -EBUSY;
1057 goto out;
1058 }
1059 } else {
1060 priv->sink = NULL;
1061 goto out;
1062 }
1063
1064 priv->sink = remote->entity;
1065out:
1066 mutex_unlock(lock: &priv->lock);
1067 return ret;
1068}
1069
1070static int prp_s_ctrl(struct v4l2_ctrl *ctrl)
1071{
1072 struct prp_priv *priv = container_of(ctrl->handler,
1073 struct prp_priv, ctrl_hdlr);
1074 struct imx_ic_priv *ic_priv = priv->ic_priv;
1075 enum ipu_rotate_mode rot_mode;
1076 int rotation, ret = 0;
1077 bool hflip, vflip;
1078
1079 mutex_lock(&priv->lock);
1080
1081 rotation = priv->rotation;
1082 hflip = priv->hflip;
1083 vflip = priv->vflip;
1084
1085 switch (ctrl->id) {
1086 case V4L2_CID_HFLIP:
1087 hflip = (ctrl->val == 1);
1088 break;
1089 case V4L2_CID_VFLIP:
1090 vflip = (ctrl->val == 1);
1091 break;
1092 case V4L2_CID_ROTATE:
1093 rotation = ctrl->val;
1094 break;
1095 default:
1096 v4l2_err(&ic_priv->sd, "Invalid control\n");
1097 ret = -EINVAL;
1098 goto out;
1099 }
1100
1101 ret = ipu_degrees_to_rot_mode(mode: &rot_mode, degrees: rotation, hflip, vflip);
1102 if (ret)
1103 goto out;
1104
1105 if (rot_mode != priv->rot_mode) {
1106 struct v4l2_mbus_framefmt outfmt, infmt;
1107
1108 /* can't change rotation mid-streaming */
1109 if (priv->stream_count > 0) {
1110 ret = -EBUSY;
1111 goto out;
1112 }
1113
1114 outfmt = priv->format_mbus[PRPENCVF_SRC_PAD];
1115 infmt = priv->format_mbus[PRPENCVF_SINK_PAD];
1116
1117 if (prp_bound_align_output(outfmt: &outfmt, infmt: &infmt, rot_mode)) {
1118 ret = -EINVAL;
1119 goto out;
1120 }
1121
1122 priv->rot_mode = rot_mode;
1123 priv->rotation = rotation;
1124 priv->hflip = hflip;
1125 priv->vflip = vflip;
1126 }
1127
1128out:
1129 mutex_unlock(lock: &priv->lock);
1130 return ret;
1131}
1132
1133static const struct v4l2_ctrl_ops prp_ctrl_ops = {
1134 .s_ctrl = prp_s_ctrl,
1135};
1136
1137static int prp_init_controls(struct prp_priv *priv)
1138{
1139 struct imx_ic_priv *ic_priv = priv->ic_priv;
1140 struct v4l2_ctrl_handler *hdlr = &priv->ctrl_hdlr;
1141 int ret;
1142
1143 v4l2_ctrl_handler_init(hdlr, 3);
1144
1145 v4l2_ctrl_new_std(hdl: hdlr, ops: &prp_ctrl_ops, V4L2_CID_HFLIP,
1146 min: 0, max: 1, step: 1, def: 0);
1147 v4l2_ctrl_new_std(hdl: hdlr, ops: &prp_ctrl_ops, V4L2_CID_VFLIP,
1148 min: 0, max: 1, step: 1, def: 0);
1149 v4l2_ctrl_new_std(hdl: hdlr, ops: &prp_ctrl_ops, V4L2_CID_ROTATE,
1150 min: 0, max: 270, step: 90, def: 0);
1151
1152 ic_priv->sd.ctrl_handler = hdlr;
1153
1154 if (hdlr->error) {
1155 ret = hdlr->error;
1156 goto out_free;
1157 }
1158
1159 v4l2_ctrl_handler_setup(hdl: hdlr);
1160 return 0;
1161
1162out_free:
1163 v4l2_ctrl_handler_free(hdl: hdlr);
1164 return ret;
1165}
1166
1167static int prp_s_stream(struct v4l2_subdev *sd, int enable)
1168{
1169 struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
1170 struct prp_priv *priv = ic_priv->task_priv;
1171 int ret = 0;
1172
1173 mutex_lock(&priv->lock);
1174
1175 if (!priv->src_sd || !priv->sink) {
1176 ret = -EPIPE;
1177 goto out;
1178 }
1179
1180 /*
1181 * enable/disable streaming only if stream_count is
1182 * going from 0 to 1 / 1 to 0.
1183 */
1184 if (priv->stream_count != !enable)
1185 goto update_count;
1186
1187 dev_dbg(ic_priv->ipu_dev, "%s: stream %s\n", sd->name,
1188 enable ? "ON" : "OFF");
1189
1190 if (enable)
1191 ret = prp_start(priv);
1192 else
1193 prp_stop(priv);
1194 if (ret)
1195 goto out;
1196
1197update_count:
1198 priv->stream_count += enable ? 1 : -1;
1199 if (priv->stream_count < 0)
1200 priv->stream_count = 0;
1201out:
1202 mutex_unlock(lock: &priv->lock);
1203 return ret;
1204}
1205
1206static int prp_get_frame_interval(struct v4l2_subdev *sd,
1207 struct v4l2_subdev_state *sd_state,
1208 struct v4l2_subdev_frame_interval *fi)
1209{
1210 struct prp_priv *priv = sd_to_priv(sd);
1211
1212 /*
1213 * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
1214 * subdev active state API.
1215 */
1216 if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
1217 return -EINVAL;
1218
1219 if (fi->pad >= PRPENCVF_NUM_PADS)
1220 return -EINVAL;
1221
1222 mutex_lock(&priv->lock);
1223 fi->interval = priv->frame_interval;
1224 mutex_unlock(lock: &priv->lock);
1225
1226 return 0;
1227}
1228
1229static int prp_set_frame_interval(struct v4l2_subdev *sd,
1230 struct v4l2_subdev_state *sd_state,
1231 struct v4l2_subdev_frame_interval *fi)
1232{
1233 struct prp_priv *priv = sd_to_priv(sd);
1234
1235 /*
1236 * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
1237 * subdev active state API.
1238 */
1239 if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
1240 return -EINVAL;
1241
1242 if (fi->pad >= PRPENCVF_NUM_PADS)
1243 return -EINVAL;
1244
1245 mutex_lock(&priv->lock);
1246
1247 /* No limits on valid frame intervals */
1248 if (fi->interval.numerator == 0 || fi->interval.denominator == 0)
1249 fi->interval = priv->frame_interval;
1250 else
1251 priv->frame_interval = fi->interval;
1252
1253 mutex_unlock(lock: &priv->lock);
1254
1255 return 0;
1256}
1257
1258static int prp_registered(struct v4l2_subdev *sd)
1259{
1260 struct prp_priv *priv = sd_to_priv(sd);
1261 struct imx_ic_priv *ic_priv = priv->ic_priv;
1262 int i, ret;
1263 u32 code;
1264
1265 /* set a default mbus format */
1266 imx_media_enum_ipu_formats(code: &code, index: 0, fmt_sel: PIXFMT_SEL_YUV);
1267
1268 for (i = 0; i < PRPENCVF_NUM_PADS; i++) {
1269 ret = imx_media_init_mbus_fmt(mbus: &priv->format_mbus[i],
1270 IMX_MEDIA_DEF_PIX_WIDTH,
1271 IMX_MEDIA_DEF_PIX_HEIGHT, code,
1272 field: V4L2_FIELD_NONE, cc: &priv->cc[i]);
1273 if (ret)
1274 return ret;
1275 }
1276
1277 /* init default frame interval */
1278 priv->frame_interval.numerator = 1;
1279 priv->frame_interval.denominator = 30;
1280
1281 priv->vdev = imx_media_capture_device_init(dev: ic_priv->ipu_dev,
1282 src_sd: &ic_priv->sd,
1283 pad: PRPENCVF_SRC_PAD, legacy_api: true);
1284 if (IS_ERR(ptr: priv->vdev))
1285 return PTR_ERR(ptr: priv->vdev);
1286
1287 ret = imx_media_capture_device_register(vdev: priv->vdev, link_flags: 0);
1288 if (ret)
1289 goto remove_vdev;
1290
1291 ret = prp_init_controls(priv);
1292 if (ret)
1293 goto unreg_vdev;
1294
1295 return 0;
1296
1297unreg_vdev:
1298 imx_media_capture_device_unregister(vdev: priv->vdev);
1299remove_vdev:
1300 imx_media_capture_device_remove(vdev: priv->vdev);
1301 return ret;
1302}
1303
1304static void prp_unregistered(struct v4l2_subdev *sd)
1305{
1306 struct prp_priv *priv = sd_to_priv(sd);
1307
1308 imx_media_capture_device_unregister(vdev: priv->vdev);
1309 imx_media_capture_device_remove(vdev: priv->vdev);
1310
1311 v4l2_ctrl_handler_free(hdl: &priv->ctrl_hdlr);
1312}
1313
1314static const struct v4l2_subdev_pad_ops prp_pad_ops = {
1315 .enum_mbus_code = prp_enum_mbus_code,
1316 .enum_frame_size = prp_enum_frame_size,
1317 .get_fmt = prp_get_fmt,
1318 .set_fmt = prp_set_fmt,
1319 .get_frame_interval = prp_get_frame_interval,
1320 .set_frame_interval = prp_set_frame_interval,
1321};
1322
1323static const struct v4l2_subdev_video_ops prp_video_ops = {
1324 .s_stream = prp_s_stream,
1325};
1326
1327static const struct media_entity_operations prp_entity_ops = {
1328 .link_setup = prp_link_setup,
1329 .link_validate = v4l2_subdev_link_validate,
1330};
1331
1332static const struct v4l2_subdev_ops prp_subdev_ops = {
1333 .video = &prp_video_ops,
1334 .pad = &prp_pad_ops,
1335};
1336
1337static const struct v4l2_subdev_internal_ops prp_internal_ops = {
1338 .init_state = imx_media_init_state,
1339 .registered = prp_registered,
1340 .unregistered = prp_unregistered,
1341};
1342
1343static int prp_init(struct imx_ic_priv *ic_priv)
1344{
1345 struct prp_priv *priv;
1346 int i, ret;
1347
1348 priv = devm_kzalloc(dev: ic_priv->ipu_dev, size: sizeof(*priv), GFP_KERNEL);
1349 if (!priv)
1350 return -ENOMEM;
1351
1352 ic_priv->task_priv = priv;
1353 priv->ic_priv = ic_priv;
1354
1355 spin_lock_init(&priv->irqlock);
1356 timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0);
1357
1358 mutex_init(&priv->lock);
1359
1360 for (i = 0; i < PRPENCVF_NUM_PADS; i++) {
1361 priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ?
1362 MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
1363 }
1364
1365 ret = media_entity_pads_init(entity: &ic_priv->sd.entity, num_pads: PRPENCVF_NUM_PADS,
1366 pads: priv->pad);
1367 if (ret)
1368 mutex_destroy(lock: &priv->lock);
1369
1370 return ret;
1371}
1372
1373static void prp_remove(struct imx_ic_priv *ic_priv)
1374{
1375 struct prp_priv *priv = ic_priv->task_priv;
1376
1377 mutex_destroy(lock: &priv->lock);
1378}
1379
1380struct imx_ic_ops imx_ic_prpencvf_ops = {
1381 .subdev_ops = &prp_subdev_ops,
1382 .internal_ops = &prp_internal_ops,
1383 .entity_ops = &prp_entity_ops,
1384 .init = prp_init,
1385 .remove = prp_remove,
1386};
1387

source code of linux/drivers/staging/media/imx/imx-ic-prpencvf.c