13
13
#include <linux/gcd.h>
14
14
#include <linux/interrupt.h>
15
15
#include <linux/module.h>
16
+ #include <linux/of_graph.h>
16
17
#include <linux/pinctrl/consumer.h>
17
18
#include <linux/platform_device.h>
18
19
#include <media/v4l2-ctrls.h>
@@ -99,8 +100,8 @@ struct csi_priv {
99
100
/* the mipi virtual channel number at link validate */
100
101
int vc_num ;
101
102
102
- /* the attached sensor at stream on */
103
- struct imx_media_subdev * sensor ;
103
+ /* the upstream endpoint CSI is receiving from */
104
+ struct v4l2_fwnode_endpoint upstream_ep ;
104
105
105
106
spinlock_t irqlock ; /* protect eof_irq handler */
106
107
struct timer_list eof_timeout_timer ;
@@ -120,6 +121,71 @@ static inline struct csi_priv *sd_to_dev(struct v4l2_subdev *sdev)
120
121
return container_of (sdev , struct csi_priv , sd );
121
122
}
122
123
124
+ static inline bool is_parallel_16bit_bus (struct v4l2_fwnode_endpoint * ep )
125
+ {
126
+ return ep -> bus_type != V4L2_MBUS_CSI2 &&
127
+ ep -> bus .parallel .bus_width >= 16 ;
128
+ }
129
+
130
+ /*
131
+ * Parses the fwnode endpoint from the source pad of the entity
132
+ * connected to this CSI. This will either be the entity directly
133
+ * upstream from the CSI-2 receiver, or directly upstream from the
134
+ * video mux. The endpoint is needed to determine the bus type and
135
+ * bus config coming into the CSI.
136
+ */
137
+ static int csi_get_upstream_endpoint (struct csi_priv * priv ,
138
+ struct v4l2_fwnode_endpoint * ep )
139
+ {
140
+ struct device_node * endpoint , * port ;
141
+ struct imx_media_subdev * imxsd ;
142
+ struct media_entity * src ;
143
+ struct v4l2_subdev * sd ;
144
+ struct media_pad * pad ;
145
+
146
+ if (!priv -> src_sd )
147
+ return - EPIPE ;
148
+
149
+ src = & priv -> src_sd -> entity ;
150
+
151
+ if (src -> function == MEDIA_ENT_F_VID_MUX ) {
152
+ /*
153
+ * CSI is connected directly to video mux, skip up to
154
+ * CSI-2 receiver if it is in the path, otherwise stay
155
+ * with video mux.
156
+ */
157
+ imxsd = imx_media_find_upstream_subdev (priv -> md , src ,
158
+ IMX_MEDIA_GRP_ID_CSI2 );
159
+ if (!IS_ERR (imxsd ))
160
+ src = & imxsd -> sd -> entity ;
161
+ }
162
+
163
+ /* get source pad of entity directly upstream from src */
164
+ pad = imx_media_find_upstream_pad (priv -> md , src , 0 );
165
+ if (IS_ERR (pad ))
166
+ return PTR_ERR (pad );
167
+
168
+ sd = media_entity_to_v4l2_subdev (pad -> entity );
169
+
170
+ /*
171
+ * NOTE: this assumes an OF-graph port id is the same as a
172
+ * media pad index.
173
+ */
174
+ port = of_graph_get_port_by_id (sd -> dev -> of_node , pad -> index );
175
+ if (!port )
176
+ return - ENODEV ;
177
+
178
+ endpoint = of_get_next_child (port , NULL );
179
+ of_node_put (port );
180
+ if (!endpoint )
181
+ return - ENODEV ;
182
+
183
+ v4l2_fwnode_endpoint_parse (of_fwnode_handle (endpoint ), ep );
184
+ of_node_put (endpoint );
185
+
186
+ return 0 ;
187
+ }
188
+
123
189
static void csi_idmac_put_ipu_resources (struct csi_priv * priv )
124
190
{
125
191
if (priv -> idmac_ch )
@@ -302,7 +368,6 @@ static void csi_idmac_unsetup_vb2_buf(struct csi_priv *priv,
302
368
static int csi_idmac_setup_channel (struct csi_priv * priv )
303
369
{
304
370
struct imx_media_video_dev * vdev = priv -> vdev ;
305
- struct v4l2_fwnode_endpoint * sensor_ep ;
306
371
struct v4l2_mbus_framefmt * infmt ;
307
372
struct ipu_image image ;
308
373
u32 passthrough_bits ;
@@ -312,7 +377,6 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
312
377
int ret ;
313
378
314
379
infmt = & priv -> format_mbus [CSI_SINK_PAD ];
315
- sensor_ep = & priv -> sensor -> sensor_ep ;
316
380
317
381
ipu_cpmem_zero (priv -> idmac_ch );
318
382
@@ -330,7 +394,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
330
394
* Check for conditions that require the IPU to handle the
331
395
* data internally as generic data, aka passthrough mode:
332
396
* - raw bayer formats
333
- * - the sensor bus is 16-bit parallel
397
+ * - the CSI is receiving from a 16-bit parallel bus
334
398
*/
335
399
switch (image .pix .pixelformat ) {
336
400
case V4L2_PIX_FMT_SBGGR8 :
@@ -354,8 +418,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
354
418
burst_size = (image .pix .width & 0x3f ) ?
355
419
((image .pix .width & 0x1f ) ?
356
420
((image .pix .width & 0xf ) ? 8 : 16 ) : 32 ) : 64 ;
357
- passthrough = (sensor_ep -> bus_type != V4L2_MBUS_CSI2 &&
358
- sensor_ep -> bus .parallel .bus_width >= 16 );
421
+ passthrough = is_parallel_16bit_bus (& priv -> upstream_ep );
359
422
passthrough_bits = 16 ;
360
423
/* Skip writing U and V components to odd rows */
361
424
ipu_cpmem_skip_odd_chroma_rows (priv -> idmac_ch );
@@ -364,14 +427,12 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
364
427
case V4L2_PIX_FMT_UYVY :
365
428
burst_size = (image .pix .width & 0x1f ) ?
366
429
((image .pix .width & 0xf ) ? 8 : 16 ) : 32 ;
367
- passthrough = (sensor_ep -> bus_type != V4L2_MBUS_CSI2 &&
368
- sensor_ep -> bus .parallel .bus_width >= 16 );
430
+ passthrough = is_parallel_16bit_bus (& priv -> upstream_ep );
369
431
passthrough_bits = 16 ;
370
432
break ;
371
433
default :
372
434
burst_size = (image .pix .width & 0xf ) ? 8 : 16 ;
373
- passthrough = (sensor_ep -> bus_type != V4L2_MBUS_CSI2 &&
374
- sensor_ep -> bus .parallel .bus_width >= 16 );
435
+ passthrough = is_parallel_16bit_bus (& priv -> upstream_ep );
375
436
passthrough_bits = 16 ;
376
437
break ;
377
438
}
@@ -568,22 +629,20 @@ static void csi_idmac_stop(struct csi_priv *priv)
568
629
static int csi_setup (struct csi_priv * priv )
569
630
{
570
631
struct v4l2_mbus_framefmt * infmt , * outfmt ;
571
- struct v4l2_mbus_config sensor_mbus_cfg ;
572
- struct v4l2_fwnode_endpoint * sensor_ep ;
632
+ struct v4l2_mbus_config mbus_cfg ;
573
633
struct v4l2_mbus_framefmt if_fmt ;
574
634
575
635
infmt = & priv -> format_mbus [CSI_SINK_PAD ];
576
636
outfmt = & priv -> format_mbus [priv -> active_output_pad ];
577
- sensor_ep = & priv -> sensor -> sensor_ep ;
578
637
579
- /* compose mbus_config from sensor endpoint */
580
- sensor_mbus_cfg .type = sensor_ep -> bus_type ;
581
- sensor_mbus_cfg .flags = (sensor_ep -> bus_type == V4L2_MBUS_CSI2 ) ?
582
- sensor_ep -> bus .mipi_csi2 .flags :
583
- sensor_ep -> bus .parallel .flags ;
638
+ /* compose mbus_config from the upstream endpoint */
639
+ mbus_cfg .type = priv -> upstream_ep . bus_type ;
640
+ mbus_cfg .flags = (priv -> upstream_ep . bus_type == V4L2_MBUS_CSI2 ) ?
641
+ priv -> upstream_ep . bus .mipi_csi2 .flags :
642
+ priv -> upstream_ep . bus .parallel .flags ;
584
643
585
644
/*
586
- * we need to pass input sensor frame to CSI interface, but
645
+ * we need to pass input frame to CSI interface, but
587
646
* with translated field type from output format
588
647
*/
589
648
if_fmt = * infmt ;
@@ -595,7 +654,7 @@ static int csi_setup(struct csi_priv *priv)
595
654
priv -> crop .width == 2 * priv -> compose .width ,
596
655
priv -> crop .height == 2 * priv -> compose .height );
597
656
598
- ipu_csi_init_interface (priv -> csi , & sensor_mbus_cfg , & if_fmt );
657
+ ipu_csi_init_interface (priv -> csi , & mbus_cfg , & if_fmt );
599
658
600
659
ipu_csi_set_dest (priv -> csi , priv -> dest );
601
660
@@ -611,35 +670,11 @@ static int csi_setup(struct csi_priv *priv)
611
670
static int csi_start (struct csi_priv * priv )
612
671
{
613
672
struct v4l2_fract * output_fi , * input_fi ;
614
- u32 bad_frames = 0 ;
615
673
int ret ;
616
674
617
- if (!priv -> sensor ) {
618
- v4l2_err (& priv -> sd , "no sensor attached\n" );
619
- return - EINVAL ;
620
- }
621
-
622
675
output_fi = & priv -> frame_interval [priv -> active_output_pad ];
623
676
input_fi = & priv -> frame_interval [CSI_SINK_PAD ];
624
677
625
- ret = v4l2_subdev_call (priv -> sensor -> sd , sensor ,
626
- g_skip_frames , & bad_frames );
627
- if (!ret && bad_frames ) {
628
- u32 delay_usec ;
629
-
630
- /*
631
- * This sensor has bad frames when it is turned on,
632
- * add a delay to avoid them before enabling the CSI
633
- * hardware. Especially for sensors with a bt.656 interface,
634
- * any shifts in the SAV/EAV sync codes will cause the CSI
635
- * to lose vert/horiz sync.
636
- */
637
- delay_usec = DIV_ROUND_UP_ULL (
638
- (u64 )USEC_PER_SEC * input_fi -> numerator * bad_frames ,
639
- input_fi -> denominator );
640
- usleep_range (delay_usec , delay_usec + 1000 );
641
- }
642
-
643
678
if (priv -> dest == IPU_CSI_DEST_IDMAC ) {
644
679
ret = csi_idmac_start (priv );
645
680
if (ret )
@@ -971,9 +1006,8 @@ static int csi_link_validate(struct v4l2_subdev *sd,
971
1006
struct v4l2_subdev_format * sink_fmt )
972
1007
{
973
1008
struct csi_priv * priv = v4l2_get_subdevdata (sd );
974
- struct v4l2_fwnode_endpoint * sensor_ep ;
1009
+ struct v4l2_fwnode_endpoint upstream_ep ;
975
1010
const struct imx_media_pixfmt * incc ;
976
- struct imx_media_subdev * sensor ;
977
1011
bool is_csi2 ;
978
1012
int ret ;
979
1013
@@ -982,22 +1016,20 @@ static int csi_link_validate(struct v4l2_subdev *sd,
982
1016
if (ret )
983
1017
return ret ;
984
1018
985
- sensor = __imx_media_find_sensor (priv -> md , & priv -> sd . entity );
986
- if (IS_ERR ( sensor ) ) {
987
- v4l2_err (& priv -> sd , "no sensor attached \n" );
988
- return PTR_ERR ( sensor ) ;
1019
+ ret = csi_get_upstream_endpoint (priv , & upstream_ep );
1020
+ if (ret ) {
1021
+ v4l2_err (& priv -> sd , "failed to find upstream endpoint \n" );
1022
+ return ret ;
989
1023
}
990
1024
991
1025
mutex_lock (& priv -> lock );
992
1026
993
- priv -> sensor = sensor ;
994
- sensor_ep = & priv -> sensor -> sensor_ep ;
995
- is_csi2 = (sensor_ep -> bus_type == V4L2_MBUS_CSI2 );
1027
+ priv -> upstream_ep = upstream_ep ;
1028
+ is_csi2 = (upstream_ep .bus_type == V4L2_MBUS_CSI2 );
996
1029
incc = priv -> cc [CSI_SINK_PAD ];
997
1030
998
1031
if (priv -> dest != IPU_CSI_DEST_IDMAC &&
999
- (incc -> bayer || (!is_csi2 &&
1000
- sensor_ep -> bus .parallel .bus_width >= 16 ))) {
1032
+ (incc -> bayer || is_parallel_16bit_bus (& upstream_ep ))) {
1001
1033
v4l2_err (& priv -> sd ,
1002
1034
"bayer/16-bit parallel buses must go to IDMAC pad\n" );
1003
1035
ret = - EINVAL ;
@@ -1067,12 +1099,8 @@ static void csi_try_crop(struct csi_priv *priv,
1067
1099
struct v4l2_rect * crop ,
1068
1100
struct v4l2_subdev_pad_config * cfg ,
1069
1101
struct v4l2_mbus_framefmt * infmt ,
1070
- struct imx_media_subdev * sensor )
1102
+ struct v4l2_fwnode_endpoint * upstream_ep )
1071
1103
{
1072
- struct v4l2_fwnode_endpoint * sensor_ep ;
1073
-
1074
- sensor_ep = & sensor -> sensor_ep ;
1075
-
1076
1104
crop -> width = min_t (__u32 , infmt -> width , crop -> width );
1077
1105
if (crop -> left + crop -> width > infmt -> width )
1078
1106
crop -> left = infmt -> width - crop -> width ;
@@ -1086,7 +1114,7 @@ static void csi_try_crop(struct csi_priv *priv,
1086
1114
* sync, so fix it to NTSC/PAL active lines. NTSC contains
1087
1115
* 2 extra lines of active video that need to be cropped.
1088
1116
*/
1089
- if (sensor_ep -> bus_type == V4L2_MBUS_BT656 &&
1117
+ if (upstream_ep -> bus_type == V4L2_MBUS_BT656 &&
1090
1118
(V4L2_FIELD_HAS_BOTH (infmt -> field ) ||
1091
1119
infmt -> field == V4L2_FIELD_ALTERNATE )) {
1092
1120
crop -> height = infmt -> height ;
@@ -1236,7 +1264,7 @@ static int csi_get_fmt(struct v4l2_subdev *sd,
1236
1264
}
1237
1265
1238
1266
static void csi_try_fmt (struct csi_priv * priv ,
1239
- struct imx_media_subdev * sensor ,
1267
+ struct v4l2_fwnode_endpoint * upstream_ep ,
1240
1268
struct v4l2_subdev_pad_config * cfg ,
1241
1269
struct v4l2_subdev_format * sdformat ,
1242
1270
struct v4l2_rect * crop ,
@@ -1304,7 +1332,7 @@ static void csi_try_fmt(struct csi_priv *priv,
1304
1332
crop -> top = 0 ;
1305
1333
crop -> width = sdformat -> format .width ;
1306
1334
crop -> height = sdformat -> format .height ;
1307
- csi_try_crop (priv , crop , cfg , & sdformat -> format , sensor );
1335
+ csi_try_crop (priv , crop , cfg , & sdformat -> format , upstream_ep );
1308
1336
compose -> left = 0 ;
1309
1337
compose -> top = 0 ;
1310
1338
compose -> width = crop -> width ;
@@ -1333,20 +1361,20 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
1333
1361
{
1334
1362
struct csi_priv * priv = v4l2_get_subdevdata (sd );
1335
1363
struct imx_media_video_dev * vdev = priv -> vdev ;
1364
+ struct v4l2_fwnode_endpoint upstream_ep ;
1336
1365
const struct imx_media_pixfmt * cc ;
1337
- struct imx_media_subdev * sensor ;
1338
1366
struct v4l2_pix_format vdev_fmt ;
1339
1367
struct v4l2_mbus_framefmt * fmt ;
1340
1368
struct v4l2_rect * crop , * compose ;
1341
- int ret = 0 ;
1369
+ int ret ;
1342
1370
1343
1371
if (sdformat -> pad >= CSI_NUM_PADS )
1344
1372
return - EINVAL ;
1345
1373
1346
- sensor = imx_media_find_sensor (priv -> md , & priv -> sd . entity );
1347
- if (IS_ERR ( sensor ) ) {
1348
- v4l2_err (& priv -> sd , "no sensor attached \n" );
1349
- return PTR_ERR ( sensor ) ;
1374
+ ret = csi_get_upstream_endpoint (priv , & upstream_ep );
1375
+ if (ret ) {
1376
+ v4l2_err (& priv -> sd , "failed to find upstream endpoint \n" );
1377
+ return ret ;
1350
1378
}
1351
1379
1352
1380
mutex_lock (& priv -> lock );
@@ -1359,7 +1387,7 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
1359
1387
crop = __csi_get_crop (priv , cfg , sdformat -> which );
1360
1388
compose = __csi_get_compose (priv , cfg , sdformat -> which );
1361
1389
1362
- csi_try_fmt (priv , sensor , cfg , sdformat , crop , compose , & cc );
1390
+ csi_try_fmt (priv , & upstream_ep , cfg , sdformat , crop , compose , & cc );
1363
1391
1364
1392
fmt = __csi_get_fmt (priv , cfg , sdformat -> pad , sdformat -> which );
1365
1393
* fmt = sdformat -> format ;
@@ -1376,8 +1404,8 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
1376
1404
format .pad = pad ;
1377
1405
format .which = sdformat -> which ;
1378
1406
format .format = sdformat -> format ;
1379
- csi_try_fmt (priv , sensor , cfg , & format , NULL , compose ,
1380
- & outcc );
1407
+ csi_try_fmt (priv , & upstream_ep , cfg , & format ,
1408
+ NULL , compose , & outcc );
1381
1409
1382
1410
outfmt = __csi_get_fmt (priv , cfg , pad , sdformat -> which );
1383
1411
* outfmt = format .format ;
@@ -1472,18 +1500,18 @@ static int csi_set_selection(struct v4l2_subdev *sd,
1472
1500
struct v4l2_subdev_selection * sel )
1473
1501
{
1474
1502
struct csi_priv * priv = v4l2_get_subdevdata (sd );
1503
+ struct v4l2_fwnode_endpoint upstream_ep ;
1475
1504
struct v4l2_mbus_framefmt * infmt ;
1476
1505
struct v4l2_rect * crop , * compose ;
1477
- struct imx_media_subdev * sensor ;
1478
- int pad , ret = 0 ;
1506
+ int pad , ret ;
1479
1507
1480
1508
if (sel -> pad != CSI_SINK_PAD )
1481
1509
return - EINVAL ;
1482
1510
1483
- sensor = imx_media_find_sensor (priv -> md , & priv -> sd . entity );
1484
- if (IS_ERR ( sensor ) ) {
1485
- v4l2_err (& priv -> sd , "no sensor attached \n" );
1486
- return PTR_ERR ( sensor ) ;
1511
+ ret = csi_get_upstream_endpoint (priv , & upstream_ep );
1512
+ if (ret ) {
1513
+ v4l2_err (& priv -> sd , "failed to find upstream endpoint \n" );
1514
+ return ret ;
1487
1515
}
1488
1516
1489
1517
mutex_lock (& priv -> lock );
@@ -1511,7 +1539,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
1511
1539
goto out ;
1512
1540
}
1513
1541
1514
- csi_try_crop (priv , & sel -> r , cfg , infmt , sensor );
1542
+ csi_try_crop (priv , & sel -> r , cfg , infmt , & upstream_ep );
1515
1543
1516
1544
* crop = sel -> r ;
1517
1545
0 commit comments