forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb
kernel/drivers/staging/media/imx/imx-media-csi.c
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * V4L2 Capture CSI Subdev for Freescale i.MX5/6 SOC
34 *
45 * Copyright (c) 2014-2017 Mentor Graphics Inc.
56 * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version.
117 */
128 #include <linux/delay.h>
139 #include <linux/gcd.h>
....@@ -37,11 +33,11 @@
3733 * has not requested planar formats, we should allow 8 pixel
3834 * alignment.
3935 */
40
-#define MIN_W 176
41
-#define MIN_H 144
36
+#define MIN_W 32
37
+#define MIN_H 32
4238 #define MAX_W 4096
4339 #define MAX_H 4096
44
-#define W_ALIGN 4 /* multiple of 16 pixels */
40
+#define W_ALIGN 1 /* multiple of 2 pixels */
4541 #define H_ALIGN 1 /* multiple of 2 lines */
4642 #define S_ALIGN 1 /* multiple of 2 */
4743
....@@ -60,9 +56,10 @@
6056 struct csi_priv {
6157 struct device *dev;
6258 struct ipu_soc *ipu;
63
- struct imx_media_dev *md;
6459 struct v4l2_subdev sd;
6560 struct media_pad pad[CSI_NUM_PADS];
61
+ struct v4l2_async_notifier notifier;
62
+
6663 /* the video device at IDMAC output pad */
6764 struct imx_media_video_dev *vdev;
6865 struct imx_media_fim *fim;
....@@ -114,6 +111,7 @@
114111 u32 frame_sequence; /* frame sequence counter */
115112 bool last_eof; /* waiting for last EOF at stream off */
116113 bool nfb4eof; /* NFB4EOF encountered during streaming */
114
+ bool interweave_swap; /* swap top/bottom lines when interweaving */
117115 struct completion last_eof_comp;
118116 };
119117
....@@ -122,9 +120,14 @@
122120 return container_of(sdev, struct csi_priv, sd);
123121 }
124122
123
+static inline struct csi_priv *notifier_to_dev(struct v4l2_async_notifier *n)
124
+{
125
+ return container_of(n, struct csi_priv, notifier);
126
+}
127
+
125128 static inline bool is_parallel_bus(struct v4l2_fwnode_endpoint *ep)
126129 {
127
- return ep->bus_type != V4L2_MBUS_CSI2;
130
+ return ep->bus_type != V4L2_MBUS_CSI2_DPHY;
128131 }
129132
130133 static inline bool is_parallel_16bit_bus(struct v4l2_fwnode_endpoint *ep)
....@@ -161,8 +164,7 @@
161164 static int csi_get_upstream_endpoint(struct csi_priv *priv,
162165 struct v4l2_fwnode_endpoint *ep)
163166 {
164
- struct device_node *endpoint, *port;
165
- struct media_entity *src;
167
+ struct fwnode_handle *endpoint;
166168 struct v4l2_subdev *sd;
167169 struct media_pad *pad;
168170
....@@ -173,50 +175,43 @@
173175 return -EPIPE;
174176
175177 sd = priv->src_sd;
176
- src = &sd->entity;
177178
178
- if (src->function == MEDIA_ENT_F_VID_MUX) {
179
+ switch (sd->grp_id) {
180
+ case IMX_MEDIA_GRP_ID_CSI_MUX:
179181 /*
180
- * CSI is connected directly to video mux, skip up to
182
+ * CSI is connected directly to CSI mux, skip up to
181183 * CSI-2 receiver if it is in the path, otherwise stay
182
- * with video mux.
184
+ * with the CSI mux.
183185 */
184
- sd = imx_media_find_upstream_subdev(priv->md, src,
185
- IMX_MEDIA_GRP_ID_CSI2);
186
- if (!IS_ERR(sd))
187
- src = &sd->entity;
186
+ sd = imx_media_pipeline_subdev(&sd->entity,
187
+ IMX_MEDIA_GRP_ID_CSI2,
188
+ true);
189
+ if (IS_ERR(sd))
190
+ sd = priv->src_sd;
191
+ break;
192
+ case IMX_MEDIA_GRP_ID_CSI2:
193
+ break;
194
+ default:
195
+ /*
196
+ * the source is neither the CSI mux nor the CSI-2 receiver,
197
+ * get the source pad directly upstream from CSI itself.
198
+ */
199
+ sd = &priv->sd;
200
+ break;
188201 }
189202
190
- /*
191
- * If the source is neither the video mux nor the CSI-2 receiver,
192
- * get the source pad directly upstream from CSI itself.
193
- */
194
- if (src->function != MEDIA_ENT_F_VID_MUX &&
195
- sd->grp_id != IMX_MEDIA_GRP_ID_CSI2)
196
- src = &priv->sd.entity;
197
-
198
- /* get source pad of entity directly upstream from src */
199
- pad = imx_media_find_upstream_pad(priv->md, src, 0);
200
- if (IS_ERR(pad))
201
- return PTR_ERR(pad);
202
-
203
- sd = media_entity_to_v4l2_subdev(pad->entity);
204
-
205
- /*
206
- * NOTE: this assumes an OF-graph port id is the same as a
207
- * media pad index.
208
- */
209
- port = of_graph_get_port_by_id(sd->dev->of_node, pad->index);
210
- if (!port)
203
+ /* get source pad of entity directly upstream from sd */
204
+ pad = imx_media_pipeline_pad(&sd->entity, 0, 0, true);
205
+ if (!pad)
211206 return -ENODEV;
212207
213
- endpoint = of_get_next_child(port, NULL);
214
- of_node_put(port);
215
- if (!endpoint)
216
- return -ENODEV;
208
+ endpoint = imx_media_get_pad_fwnode(pad);
209
+ if (IS_ERR(endpoint))
210
+ return PTR_ERR(endpoint);
217211
218
- v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), ep);
219
- of_node_put(endpoint);
212
+ v4l2_fwnode_endpoint_parse(endpoint, ep);
213
+
214
+ fwnode_handle_put(endpoint);
220215
221216 return 0;
222217 }
....@@ -295,6 +290,9 @@
295290
296291 if (ipu_idmac_buffer_is_ready(priv->idmac_ch, priv->ipu_buf_num))
297292 ipu_idmac_clear_buffer(priv->idmac_ch, priv->ipu_buf_num);
293
+
294
+ if (priv->interweave_swap)
295
+ phys += vdev->fmt.fmt.pix.bytesperline;
298296
299297 ipu_cpmem_set_buffer(priv->idmac_ch, priv->ipu_buf_num, phys);
300298 }
....@@ -408,23 +406,24 @@
408406 struct imx_media_video_dev *vdev = priv->vdev;
409407 const struct imx_media_pixfmt *incc;
410408 struct v4l2_mbus_framefmt *infmt;
409
+ struct v4l2_mbus_framefmt *outfmt;
410
+ bool passthrough, interweave;
411411 struct ipu_image image;
412412 u32 passthrough_bits;
413413 u32 passthrough_cycles;
414414 dma_addr_t phys[2];
415
- bool passthrough;
416415 u32 burst_size;
417416 int ret;
418417
419418 infmt = &priv->format_mbus[CSI_SINK_PAD];
420419 incc = priv->cc[CSI_SINK_PAD];
420
+ outfmt = &priv->format_mbus[CSI_SRC_PAD_IDMAC];
421421
422422 ipu_cpmem_zero(priv->idmac_ch);
423423
424424 memset(&image, 0, sizeof(image));
425425 image.pix = vdev->fmt.fmt.pix;
426
- image.rect.width = image.pix.width;
427
- image.rect.height = image.pix.height;
426
+ image.rect = vdev->compose;
428427
429428 csi_idmac_setup_vb2_buf(priv, phys);
430429
....@@ -433,6 +432,16 @@
433432
434433 passthrough = requires_passthrough(&priv->upstream_ep, infmt, incc);
435434 passthrough_cycles = 1;
435
+
436
+ /*
437
+ * If the field type at capture interface is interlaced, and
438
+ * the output IDMAC pad is sequential, enable interweave at
439
+ * the IDMAC output channel.
440
+ */
441
+ interweave = V4L2_FIELD_IS_INTERLACED(image.pix.field) &&
442
+ V4L2_FIELD_IS_SEQUENTIAL(outfmt->field);
443
+ priv->interweave_swap = interweave &&
444
+ image.pix.field == V4L2_FIELD_INTERLACED_BT;
436445
437446 switch (image.pix.pixelformat) {
438447 case V4L2_PIX_FMT_SBGGR8:
....@@ -447,18 +456,24 @@
447456 case V4L2_PIX_FMT_SGBRG16:
448457 case V4L2_PIX_FMT_SGRBG16:
449458 case V4L2_PIX_FMT_SRGGB16:
450
- case V4L2_PIX_FMT_Y16:
459
+ case V4L2_PIX_FMT_Y10:
460
+ case V4L2_PIX_FMT_Y12:
451461 burst_size = 8;
452462 passthrough_bits = 16;
453463 break;
454464 case V4L2_PIX_FMT_YUV420:
465
+ case V4L2_PIX_FMT_YVU420:
455466 case V4L2_PIX_FMT_NV12:
456467 burst_size = (image.pix.width & 0x3f) ?
457468 ((image.pix.width & 0x1f) ?
458469 ((image.pix.width & 0xf) ? 8 : 16) : 32) : 64;
459470 passthrough_bits = 16;
460
- /* Skip writing U and V components to odd rows */
461
- ipu_cpmem_skip_odd_chroma_rows(priv->idmac_ch);
471
+ /*
472
+ * Skip writing U and V components to odd rows (but not
473
+ * when enabling IDMAC interweaving, they are incompatible).
474
+ */
475
+ if (!interweave)
476
+ ipu_cpmem_skip_odd_chroma_rows(priv->idmac_ch);
462477 break;
463478 case V4L2_PIX_FMT_YUYV:
464479 case V4L2_PIX_FMT_UYVY:
....@@ -473,7 +488,7 @@
473488 passthrough_cycles = incc->cycles;
474489 break;
475490 }
476
- /* fallthrough - non-passthrough RGB565 (CSI-2 bus) */
491
+ fallthrough; /* non-passthrough RGB565 (CSI-2 bus) */
477492 default:
478493 burst_size = (image.pix.width & 0xf) ? 8 : 16;
479494 passthrough_bits = 16;
....@@ -481,6 +496,12 @@
481496 }
482497
483498 if (passthrough) {
499
+ if (priv->interweave_swap) {
500
+ /* start interweave scan at 1st top line (2nd line) */
501
+ image.phys0 += image.pix.bytesperline;
502
+ image.phys1 += image.pix.bytesperline;
503
+ }
504
+
484505 ipu_cpmem_set_resolution(priv->idmac_ch,
485506 image.rect.width * passthrough_cycles,
486507 image.rect.height);
....@@ -490,6 +511,11 @@
490511 ipu_cpmem_set_format_passthrough(priv->idmac_ch,
491512 passthrough_bits);
492513 } else {
514
+ if (priv->interweave_swap) {
515
+ /* start interweave scan at 1st top line (2nd line) */
516
+ image.rect.top = 1;
517
+ }
518
+
493519 ret = ipu_cpmem_set_image(priv->idmac_ch, &image);
494520 if (ret)
495521 goto unsetup_vb2;
....@@ -519,10 +545,12 @@
519545
520546 ipu_smfc_set_burstsize(priv->smfc, burst_size);
521547
522
- if (image.pix.field == V4L2_FIELD_NONE &&
523
- V4L2_FIELD_HAS_BOTH(infmt->field))
548
+ if (interweave)
524549 ipu_cpmem_interlaced_scan(priv->idmac_ch,
525
- image.pix.bytesperline);
550
+ priv->interweave_swap ?
551
+ -image.pix.bytesperline :
552
+ image.pix.bytesperline,
553
+ image.pix.pixelformat);
526554
527555 ipu_idmac_set_double_buffer(priv->idmac_ch, true);
528556
....@@ -579,7 +607,7 @@
579607
580608 outfmt = &vdev->fmt.fmt.pix;
581609
582
- ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf,
610
+ ret = imx_media_alloc_dma_buf(priv->dev, &priv->underrun_buf,
583611 outfmt->sizeimage);
584612 if (ret)
585613 goto out_put_ipu;
....@@ -599,8 +627,8 @@
599627 }
600628
601629 priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu,
602
- priv->idmac_ch,
603
- IPU_IRQ_NFB4EOF);
630
+ priv->idmac_ch,
631
+ IPU_IRQ_NFB4EOF);
604632 ret = devm_request_irq(priv->dev, priv->nfb4eof_irq,
605633 csi_idmac_nfb4eof_interrupt, 0,
606634 "imx-smfc-nfb4eof", priv);
....@@ -633,7 +661,7 @@
633661 out_unsetup:
634662 csi_idmac_unsetup(priv, VB2_BUF_STATE_QUEUED);
635663 out_free_dma_buf:
636
- imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
664
+ imx_media_free_dma_buf(priv->dev, &priv->underrun_buf);
637665 out_put_ipu:
638666 csi_idmac_put_ipu_resources(priv);
639667 return ret;
....@@ -665,7 +693,7 @@
665693
666694 csi_idmac_unsetup(priv, VB2_BUF_STATE_ERROR);
667695
668
- imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
696
+ imx_media_free_dma_buf(priv->dev, &priv->underrun_buf);
669697
670698 /* cancel the EOF timeout timer */
671699 del_timer_sync(&priv->eof_timeout_timer);
....@@ -692,12 +720,7 @@
692720 priv->upstream_ep.bus.parallel.flags :
693721 priv->upstream_ep.bus.mipi_csi2.flags;
694722
695
- /*
696
- * we need to pass input frame to CSI interface, but
697
- * with translated field type from output format
698
- */
699723 if_fmt = *infmt;
700
- if_fmt.field = outfmt->field;
701724 crop = priv->crop;
702725
703726 /*
....@@ -715,7 +738,7 @@
715738 priv->crop.width == 2 * priv->compose.width,
716739 priv->crop.height == 2 * priv->compose.height);
717740
718
- ipu_csi_init_interface(priv->csi, &mbus_cfg, &if_fmt);
741
+ ipu_csi_init_interface(priv->csi, &mbus_cfg, &if_fmt, outfmt);
719742
720743 ipu_csi_set_dest(priv->csi, priv->dest);
721744
....@@ -920,7 +943,10 @@
920943
921944 switch (fi->pad) {
922945 case CSI_SINK_PAD:
923
- /* No limits on input frame interval */
946
+ /* No limits on valid input frame intervals */
947
+ if (fi->interval.numerator == 0 ||
948
+ fi->interval.denominator == 0)
949
+ fi->interval = *input_fi;
924950 /* Reset output intervals and frame skipping ratio to 1:1 */
925951 priv->frame_interval[CSI_SRC_PAD_IDMAC] = fi->interval;
926952 priv->frame_interval[CSI_SRC_PAD_DIRECT] = fi->interval;
....@@ -1035,6 +1061,8 @@
10351061 v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
10361062 v4l2_ctrl_handler_init(&priv->ctrl_hdlr, 0);
10371063 priv->sink = NULL;
1064
+ /* do not apply IC burst alignment in csi_try_crop */
1065
+ priv->active_output_pad = CSI_SRC_PAD_IDMAC;
10381066 goto out;
10391067 }
10401068
....@@ -1063,10 +1091,10 @@
10631091
10641092 remote_sd = media_entity_to_v4l2_subdev(remote->entity);
10651093 switch (remote_sd->grp_id) {
1066
- case IMX_MEDIA_GRP_ID_VDIC:
1094
+ case IMX_MEDIA_GRP_ID_IPU_VDIC:
10671095 priv->dest = IPU_CSI_DEST_VDIC;
10681096 break;
1069
- case IMX_MEDIA_GRP_ID_IC_PRP:
1097
+ case IMX_MEDIA_GRP_ID_IPU_IC_PRP:
10701098 priv->dest = IPU_CSI_DEST_IC;
10711099 break;
10721100 default:
....@@ -1087,7 +1115,7 @@
10871115 struct v4l2_subdev_format *sink_fmt)
10881116 {
10891117 struct csi_priv *priv = v4l2_get_subdevdata(sd);
1090
- struct v4l2_fwnode_endpoint upstream_ep;
1118
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
10911119 bool is_csi2;
10921120 int ret;
10931121
....@@ -1117,8 +1145,7 @@
11171145 */
11181146 #if 0
11191147 mutex_unlock(&priv->lock);
1120
- vc_num = imx_media_find_mipi_csi2_channel(priv->md,
1121
- &priv->sd.entity);
1148
+ vc_num = imx_media_find_mipi_csi2_channel(&priv->sd.entity);
11221149 if (vc_num < 0)
11231150 return vc_num;
11241151 mutex_lock(&priv->lock);
....@@ -1171,12 +1198,21 @@
11711198 struct v4l2_mbus_framefmt *infmt,
11721199 struct v4l2_fwnode_endpoint *upstream_ep)
11731200 {
1201
+ u32 in_height;
1202
+
11741203 crop->width = min_t(__u32, infmt->width, crop->width);
11751204 if (crop->left + crop->width > infmt->width)
11761205 crop->left = infmt->width - crop->width;
11771206 /* adjust crop left/width to h/w alignment restrictions */
11781207 crop->left &= ~0x3;
1179
- crop->width &= ~0x7;
1208
+ if (priv->active_output_pad == CSI_SRC_PAD_DIRECT)
1209
+ crop->width &= ~0x7; /* multiple of 8 pixels (IC burst) */
1210
+ else
1211
+ crop->width &= ~0x1; /* multiple of 2 pixels */
1212
+
1213
+ in_height = infmt->height;
1214
+ if (infmt->field == V4L2_FIELD_ALTERNATE)
1215
+ in_height *= 2;
11801216
11811217 /*
11821218 * FIXME: not sure why yet, but on interlaced bt.656,
....@@ -1187,12 +1223,12 @@
11871223 if (upstream_ep->bus_type == V4L2_MBUS_BT656 &&
11881224 (V4L2_FIELD_HAS_BOTH(infmt->field) ||
11891225 infmt->field == V4L2_FIELD_ALTERNATE)) {
1190
- crop->height = infmt->height;
1191
- crop->top = (infmt->height == 480) ? 2 : 0;
1226
+ crop->height = in_height;
1227
+ crop->top = (in_height == 480) ? 2 : 0;
11921228 } else {
1193
- crop->height = min_t(__u32, infmt->height, crop->height);
1194
- if (crop->top + crop->height > infmt->height)
1195
- crop->top = infmt->height - crop->height;
1229
+ crop->height = min_t(__u32, in_height, crop->height);
1230
+ if (crop->top + crop->height > in_height)
1231
+ crop->top = in_height - crop->height;
11961232 }
11971233 }
11981234
....@@ -1201,7 +1237,7 @@
12011237 struct v4l2_subdev_mbus_code_enum *code)
12021238 {
12031239 struct csi_priv *priv = v4l2_get_subdevdata(sd);
1204
- struct v4l2_fwnode_endpoint upstream_ep;
1240
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
12051241 const struct imx_media_pixfmt *incc;
12061242 struct v4l2_mbus_framefmt *infmt;
12071243 int ret = 0;
....@@ -1209,12 +1245,12 @@
12091245 mutex_lock(&priv->lock);
12101246
12111247 infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, code->which);
1212
- incc = imx_media_find_mbus_format(infmt->code, CS_SEL_ANY, true);
1248
+ incc = imx_media_find_mbus_format(infmt->code, PIXFMT_SEL_ANY);
12131249
12141250 switch (code->pad) {
12151251 case CSI_SINK_PAD:
1216
- ret = imx_media_enum_mbus_format(&code->code, code->index,
1217
- CS_SEL_ANY, true);
1252
+ ret = imx_media_enum_mbus_formats(&code->code, code->index,
1253
+ PIXFMT_SEL_ANY);
12181254 break;
12191255 case CSI_SRC_PAD_DIRECT:
12201256 case CSI_SRC_PAD_IDMAC:
....@@ -1231,11 +1267,13 @@
12311267 }
12321268 code->code = infmt->code;
12331269 } else {
1234
- u32 cs_sel = (incc->cs == IPUV3_COLORSPACE_YUV) ?
1235
- CS_SEL_YUV : CS_SEL_RGB;
1236
- ret = imx_media_enum_ipu_format(&code->code,
1237
- code->index,
1238
- cs_sel);
1270
+ enum imx_pixfmt_sel fmt_sel =
1271
+ (incc->cs == IPUV3_COLORSPACE_YUV) ?
1272
+ PIXFMT_SEL_YUV : PIXFMT_SEL_RGB;
1273
+
1274
+ ret = imx_media_enum_ipu_formats(&code->code,
1275
+ code->index,
1276
+ fmt_sel);
12391277 }
12401278 break;
12411279 default:
....@@ -1342,6 +1380,55 @@
13421380 return ret;
13431381 }
13441382
1383
+static void csi_try_field(struct csi_priv *priv,
1384
+ struct v4l2_subdev_pad_config *cfg,
1385
+ struct v4l2_subdev_format *sdformat)
1386
+{
1387
+ struct v4l2_mbus_framefmt *infmt =
1388
+ __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which);
1389
+
1390
+ /*
1391
+ * no restrictions on sink pad field type except must
1392
+ * be initialized.
1393
+ */
1394
+ if (sdformat->pad == CSI_SINK_PAD) {
1395
+ if (sdformat->format.field == V4L2_FIELD_ANY)
1396
+ sdformat->format.field = V4L2_FIELD_NONE;
1397
+ return;
1398
+ }
1399
+
1400
+ switch (infmt->field) {
1401
+ case V4L2_FIELD_SEQ_TB:
1402
+ case V4L2_FIELD_SEQ_BT:
1403
+ /*
1404
+ * If the user requests sequential at the source pad,
1405
+ * allow it (along with possibly inverting field order).
1406
+ * Otherwise passthrough the field type.
1407
+ */
1408
+ if (!V4L2_FIELD_IS_SEQUENTIAL(sdformat->format.field))
1409
+ sdformat->format.field = infmt->field;
1410
+ break;
1411
+ case V4L2_FIELD_ALTERNATE:
1412
+ /*
1413
+ * This driver does not support alternate field mode, and
1414
+ * the CSI captures a whole frame, so the CSI never presents
1415
+ * alternate mode at its source pads. If user has not
1416
+ * already requested sequential, translate ALTERNATE at
1417
+ * sink pad to SEQ_TB or SEQ_BT at the source pad depending
1418
+ * on input height (assume NTSC BT order if 480 total active
1419
+ * frame lines, otherwise PAL TB order).
1420
+ */
1421
+ if (!V4L2_FIELD_IS_SEQUENTIAL(sdformat->format.field))
1422
+ sdformat->format.field = (infmt->height == 480 / 2) ?
1423
+ V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB;
1424
+ break;
1425
+ default:
1426
+ /* Passthrough for all other input field types */
1427
+ sdformat->format.field = infmt->field;
1428
+ break;
1429
+ }
1430
+}
1431
+
13451432 static void csi_try_fmt(struct csi_priv *priv,
13461433 struct v4l2_fwnode_endpoint *upstream_ep,
13471434 struct v4l2_subdev_pad_config *cfg,
....@@ -1359,8 +1446,7 @@
13591446 switch (sdformat->pad) {
13601447 case CSI_SRC_PAD_DIRECT:
13611448 case CSI_SRC_PAD_IDMAC:
1362
- incc = imx_media_find_mbus_format(infmt->code,
1363
- CS_SEL_ANY, true);
1449
+ incc = imx_media_find_mbus_format(infmt->code, PIXFMT_SEL_ANY);
13641450
13651451 sdformat->format.width = compose->width;
13661452 sdformat->format.height = compose->height;
....@@ -1369,69 +1455,63 @@
13691455 sdformat->format.code = infmt->code;
13701456 *cc = incc;
13711457 } else {
1372
- u32 cs_sel = (incc->cs == IPUV3_COLORSPACE_YUV) ?
1373
- CS_SEL_YUV : CS_SEL_RGB;
1458
+ enum imx_pixfmt_sel fmt_sel =
1459
+ (incc->cs == IPUV3_COLORSPACE_YUV) ?
1460
+ PIXFMT_SEL_YUV : PIXFMT_SEL_RGB;
13741461
13751462 *cc = imx_media_find_ipu_format(sdformat->format.code,
1376
- cs_sel);
1463
+ fmt_sel);
13771464 if (!*cc) {
1378
- imx_media_enum_ipu_format(&code, 0, cs_sel);
1379
- *cc = imx_media_find_ipu_format(code, cs_sel);
1465
+ imx_media_enum_ipu_formats(&code, 0, fmt_sel);
1466
+ *cc = imx_media_find_ipu_format(code, fmt_sel);
13801467 sdformat->format.code = (*cc)->codes[0];
13811468 }
13821469 }
13831470
1384
- if (sdformat->pad == CSI_SRC_PAD_DIRECT ||
1385
- sdformat->format.field != V4L2_FIELD_NONE)
1386
- sdformat->format.field = infmt->field;
1387
-
1388
- /*
1389
- * translate V4L2_FIELD_ALTERNATE to SEQ_TB or SEQ_BT
1390
- * depending on input height (assume NTSC top-bottom
1391
- * order if 480 lines, otherwise PAL bottom-top order).
1392
- */
1393
- if (sdformat->format.field == V4L2_FIELD_ALTERNATE) {
1394
- sdformat->format.field = (infmt->height == 480) ?
1395
- V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT;
1396
- }
1471
+ csi_try_field(priv, cfg, sdformat);
13971472
13981473 /* propagate colorimetry from sink */
13991474 sdformat->format.colorspace = infmt->colorspace;
14001475 sdformat->format.xfer_func = infmt->xfer_func;
14011476 sdformat->format.quantization = infmt->quantization;
14021477 sdformat->format.ycbcr_enc = infmt->ycbcr_enc;
1478
+
14031479 break;
14041480 case CSI_SINK_PAD:
14051481 v4l_bound_align_image(&sdformat->format.width, MIN_W, MAX_W,
14061482 W_ALIGN, &sdformat->format.height,
14071483 MIN_H, MAX_H, H_ALIGN, S_ALIGN);
14081484
1485
+ *cc = imx_media_find_mbus_format(sdformat->format.code,
1486
+ PIXFMT_SEL_ANY);
1487
+ if (!*cc) {
1488
+ imx_media_enum_mbus_formats(&code, 0,
1489
+ PIXFMT_SEL_YUV_RGB);
1490
+ *cc = imx_media_find_mbus_format(code,
1491
+ PIXFMT_SEL_YUV_RGB);
1492
+ sdformat->format.code = (*cc)->codes[0];
1493
+ }
1494
+
1495
+ csi_try_field(priv, cfg, sdformat);
1496
+
14091497 /* Reset crop and compose rectangles */
14101498 crop->left = 0;
14111499 crop->top = 0;
14121500 crop->width = sdformat->format.width;
14131501 crop->height = sdformat->format.height;
1502
+ if (sdformat->format.field == V4L2_FIELD_ALTERNATE)
1503
+ crop->height *= 2;
14141504 csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep);
14151505 compose->left = 0;
14161506 compose->top = 0;
14171507 compose->width = crop->width;
14181508 compose->height = crop->height;
14191509
1420
- *cc = imx_media_find_mbus_format(sdformat->format.code,
1421
- CS_SEL_ANY, true);
1422
- if (!*cc) {
1423
- imx_media_enum_mbus_format(&code, 0,
1424
- CS_SEL_ANY, false);
1425
- *cc = imx_media_find_mbus_format(code,
1426
- CS_SEL_ANY, false);
1427
- sdformat->format.code = (*cc)->codes[0];
1428
- }
1429
-
1430
- imx_media_fill_default_mbus_fields(
1431
- &sdformat->format, infmt,
1432
- priv->active_output_pad == CSI_SRC_PAD_DIRECT);
14331510 break;
14341511 }
1512
+
1513
+ imx_media_try_colorimetry(&sdformat->format,
1514
+ priv->active_output_pad == CSI_SRC_PAD_DIRECT);
14351515 }
14361516
14371517 static int csi_set_fmt(struct v4l2_subdev *sd,
....@@ -1439,10 +1519,8 @@
14391519 struct v4l2_subdev_format *sdformat)
14401520 {
14411521 struct csi_priv *priv = v4l2_get_subdevdata(sd);
1442
- struct imx_media_video_dev *vdev = priv->vdev;
1443
- struct v4l2_fwnode_endpoint upstream_ep;
1522
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
14441523 const struct imx_media_pixfmt *cc;
1445
- struct v4l2_pix_format vdev_fmt;
14461524 struct v4l2_mbus_framefmt *fmt;
14471525 struct v4l2_rect *crop, *compose;
14481526 int ret;
....@@ -1494,19 +1572,9 @@
14941572 }
14951573 }
14961574
1497
- if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
1498
- goto out;
1575
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
1576
+ priv->cc[sdformat->pad] = cc;
14991577
1500
- priv->cc[sdformat->pad] = cc;
1501
-
1502
- /* propagate IDMAC output pad format to capture device */
1503
- imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt,
1504
- &priv->format_mbus[CSI_SRC_PAD_IDMAC],
1505
- priv->cc[CSI_SRC_PAD_IDMAC]);
1506
- mutex_unlock(&priv->lock);
1507
- imx_media_capture_device_set_format(vdev, &vdev_fmt);
1508
-
1509
- return 0;
15101578 out:
15111579 mutex_unlock(&priv->lock);
15121580 return ret;
....@@ -1536,6 +1604,8 @@
15361604 sel->r.top = 0;
15371605 sel->r.width = infmt->width;
15381606 sel->r.height = infmt->height;
1607
+ if (infmt->field == V4L2_FIELD_ALTERNATE)
1608
+ sel->r.height *= 2;
15391609 break;
15401610 case V4L2_SEL_TGT_CROP:
15411611 sel->r = *crop;
....@@ -1579,7 +1649,7 @@
15791649 struct v4l2_subdev_selection *sel)
15801650 {
15811651 struct csi_priv *priv = v4l2_get_subdevdata(sd);
1582
- struct v4l2_fwnode_endpoint upstream_ep;
1652
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
15831653 struct v4l2_mbus_framefmt *infmt;
15841654 struct v4l2_rect *crop, *compose;
15851655 int pad, ret;
....@@ -1686,18 +1756,12 @@
16861756 return v4l2_event_unsubscribe(fh, sub);
16871757 }
16881758
1689
-/*
1690
- * retrieve our pads parsed from the OF graph by the media device
1691
- */
16921759 static int csi_registered(struct v4l2_subdev *sd)
16931760 {
16941761 struct csi_priv *priv = v4l2_get_subdevdata(sd);
16951762 struct ipu_csi *csi;
16961763 int i, ret;
16971764 u32 code;
1698
-
1699
- /* get media device */
1700
- priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
17011765
17021766 /* get handle to IPU CSI */
17031767 csi = ipu_csi_get(priv->ipu, priv->csi_id);
....@@ -1708,12 +1772,9 @@
17081772 priv->csi = csi;
17091773
17101774 for (i = 0; i < CSI_NUM_PADS; i++) {
1711
- priv->pad[i].flags = (i == CSI_SINK_PAD) ?
1712
- MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
1713
-
17141775 code = 0;
17151776 if (i != CSI_SINK_PAD)
1716
- imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV);
1777
+ imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV);
17171778
17181779 /* set a default mbus format */
17191780 ret = imx_media_init_mbus_fmt(&priv->format_mbus[i],
....@@ -1742,21 +1803,22 @@
17421803 goto put_csi;
17431804 }
17441805
1745
- ret = media_entity_pads_init(&sd->entity, CSI_NUM_PADS, priv->pad);
1746
- if (ret)
1806
+ priv->vdev = imx_media_capture_device_init(priv->sd.dev,
1807
+ &priv->sd,
1808
+ CSI_SRC_PAD_IDMAC);
1809
+ if (IS_ERR(priv->vdev)) {
1810
+ ret = PTR_ERR(priv->vdev);
17471811 goto free_fim;
1812
+ }
17481813
17491814 ret = imx_media_capture_device_register(priv->vdev);
17501815 if (ret)
1751
- goto free_fim;
1752
-
1753
- ret = imx_media_add_video_device(priv->md, priv->vdev);
1754
- if (ret)
1755
- goto unreg;
1816
+ goto remove_vdev;
17561817
17571818 return 0;
1758
-unreg:
1759
- imx_media_capture_device_unregister(priv->vdev);
1819
+
1820
+remove_vdev:
1821
+ imx_media_capture_device_remove(priv->vdev);
17601822 free_fim:
17611823 if (priv->fim)
17621824 imx_media_fim_free(priv->fim);
....@@ -1770,6 +1832,7 @@
17701832 struct csi_priv *priv = v4l2_get_subdevdata(sd);
17711833
17721834 imx_media_capture_device_unregister(priv->vdev);
1835
+ imx_media_capture_device_remove(priv->vdev);
17731836
17741837 if (priv->fim)
17751838 imx_media_fim_free(priv->fim);
....@@ -1778,9 +1841,32 @@
17781841 ipu_csi_put(priv->csi);
17791842 }
17801843
1844
+/*
1845
+ * The CSI has only one fwnode endpoint, at the sink pad. Verify the
1846
+ * endpoint belongs to us, and return CSI_SINK_PAD.
1847
+ */
1848
+static int csi_get_fwnode_pad(struct media_entity *entity,
1849
+ struct fwnode_endpoint *endpoint)
1850
+{
1851
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1852
+ struct csi_priv *priv = v4l2_get_subdevdata(sd);
1853
+ struct fwnode_handle *csi_port = dev_fwnode(priv->dev);
1854
+ struct fwnode_handle *csi_ep;
1855
+ int ret;
1856
+
1857
+ csi_ep = fwnode_get_next_child_node(csi_port, NULL);
1858
+
1859
+ ret = endpoint->local_fwnode == csi_ep ? CSI_SINK_PAD : -ENXIO;
1860
+
1861
+ fwnode_handle_put(csi_ep);
1862
+
1863
+ return ret;
1864
+}
1865
+
17811866 static const struct media_entity_operations csi_entity_ops = {
17821867 .link_setup = csi_link_setup,
17831868 .link_validate = v4l2_subdev_link_validate,
1869
+ .get_fwnode_pad = csi_get_fwnode_pad,
17841870 };
17851871
17861872 static const struct v4l2_subdev_core_ops csi_core_ops = {
....@@ -1817,12 +1903,74 @@
18171903 .unregistered = csi_unregistered,
18181904 };
18191905
1906
+static int imx_csi_notify_bound(struct v4l2_async_notifier *notifier,
1907
+ struct v4l2_subdev *sd,
1908
+ struct v4l2_async_subdev *asd)
1909
+{
1910
+ struct csi_priv *priv = notifier_to_dev(notifier);
1911
+ struct media_pad *sink = &priv->sd.entity.pads[CSI_SINK_PAD];
1912
+
1913
+ /*
1914
+ * If the subdev is a video mux, it must be one of the CSI
1915
+ * muxes. Mark it as such via its group id.
1916
+ */
1917
+ if (sd->entity.function == MEDIA_ENT_F_VID_MUX)
1918
+ sd->grp_id = IMX_MEDIA_GRP_ID_CSI_MUX;
1919
+
1920
+ return v4l2_create_fwnode_links_to_pad(sd, sink);
1921
+}
1922
+
1923
+static const struct v4l2_async_notifier_operations csi_notify_ops = {
1924
+ .bound = imx_csi_notify_bound,
1925
+};
1926
+
1927
+static int imx_csi_async_register(struct csi_priv *priv)
1928
+{
1929
+ struct v4l2_async_subdev *asd = NULL;
1930
+ struct fwnode_handle *ep;
1931
+ unsigned int port;
1932
+ int ret;
1933
+
1934
+ v4l2_async_notifier_init(&priv->notifier);
1935
+
1936
+ /* get this CSI's port id */
1937
+ ret = fwnode_property_read_u32(dev_fwnode(priv->dev), "reg", &port);
1938
+ if (ret < 0)
1939
+ return ret;
1940
+
1941
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev->parent),
1942
+ port, 0,
1943
+ FWNODE_GRAPH_ENDPOINT_NEXT);
1944
+ if (ep) {
1945
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
1946
+ &priv->notifier, ep, sizeof(*asd));
1947
+
1948
+ fwnode_handle_put(ep);
1949
+
1950
+ if (IS_ERR(asd)) {
1951
+ ret = PTR_ERR(asd);
1952
+ /* OK if asd already exists */
1953
+ if (ret != -EEXIST)
1954
+ return ret;
1955
+ }
1956
+ }
1957
+
1958
+ priv->notifier.ops = &csi_notify_ops;
1959
+
1960
+ ret = v4l2_async_subdev_notifier_register(&priv->sd,
1961
+ &priv->notifier);
1962
+ if (ret)
1963
+ return ret;
1964
+
1965
+ return v4l2_async_register_subdev(&priv->sd);
1966
+}
1967
+
18201968 static int imx_csi_probe(struct platform_device *pdev)
18211969 {
18221970 struct ipu_client_platformdata *pdata;
18231971 struct pinctrl *pinctrl;
18241972 struct csi_priv *priv;
1825
- int ret;
1973
+ int i, ret;
18261974
18271975 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
18281976 if (!priv)
....@@ -1843,6 +1991,8 @@
18431991 priv->csi_id = pdata->csi;
18441992 priv->smfc_id = (priv->csi_id == 0) ? 0 : 2;
18451993
1994
+ priv->active_output_pad = CSI_SRC_PAD_IDMAC;
1995
+
18461996 timer_setup(&priv->eof_timeout_timer, csi_idmac_eof_timeout, 0);
18471997 spin_lock_init(&priv->irqlock);
18481998
....@@ -1856,14 +2006,18 @@
18562006 priv->sd.owner = THIS_MODULE;
18572007 priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
18582008 priv->sd.grp_id = priv->csi_id ?
1859
- IMX_MEDIA_GRP_ID_CSI1 : IMX_MEDIA_GRP_ID_CSI0;
2009
+ IMX_MEDIA_GRP_ID_IPU_CSI1 : IMX_MEDIA_GRP_ID_IPU_CSI0;
18602010 imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
18612011 priv->sd.grp_id, ipu_get_num(priv->ipu));
18622012
1863
- priv->vdev = imx_media_capture_device_init(&priv->sd,
1864
- CSI_SRC_PAD_IDMAC);
1865
- if (IS_ERR(priv->vdev))
1866
- return PTR_ERR(priv->vdev);
2013
+ for (i = 0; i < CSI_NUM_PADS; i++)
2014
+ priv->pad[i].flags = (i == CSI_SINK_PAD) ?
2015
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
2016
+
2017
+ ret = media_entity_pads_init(&priv->sd.entity, CSI_NUM_PADS,
2018
+ priv->pad);
2019
+ if (ret)
2020
+ return ret;
18672021
18682022 mutex_init(&priv->lock);
18692023
....@@ -1886,15 +2040,18 @@
18862040 goto free;
18872041 }
18882042
1889
- ret = v4l2_async_register_subdev(&priv->sd);
2043
+ ret = imx_csi_async_register(priv);
18902044 if (ret)
1891
- goto free;
2045
+ goto cleanup;
18922046
18932047 return 0;
2048
+
2049
+cleanup:
2050
+ v4l2_async_notifier_unregister(&priv->notifier);
2051
+ v4l2_async_notifier_cleanup(&priv->notifier);
18942052 free:
18952053 v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
18962054 mutex_destroy(&priv->lock);
1897
- imx_media_capture_device_remove(priv->vdev);
18982055 return ret;
18992056 }
19002057
....@@ -1905,7 +2062,8 @@
19052062
19062063 v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
19072064 mutex_destroy(&priv->lock);
1908
- imx_media_capture_device_remove(priv->vdev);
2065
+ v4l2_async_notifier_unregister(&priv->notifier);
2066
+ v4l2_async_notifier_cleanup(&priv->notifier);
19092067 v4l2_async_unregister_subdev(sd);
19102068 media_entity_cleanup(&sd->entity);
19112069