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