1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013--2024 Intel Corporation
6 #include <linux/atomic.h>
7 #include <linux/bitfield.h>
8 #include <linux/bits.h>
9 #include <linux/delay.h>
10 #include <linux/device.h>
11 #include <linux/err.h>
13 #include <linux/minmax.h>
14 #include <linux/sprintf.h>
16 #include <media/media-entity.h>
17 #include <media/v4l2-ctrls.h>
18 #include <media/v4l2-device.h>
19 #include <media/v4l2-event.h>
20 #include <media/v4l2-subdev.h>
23 #include "ipu6-isys.h"
24 #include "ipu6-isys-csi2.h"
25 #include "ipu6-isys-subdev.h"
26 #include "ipu6-platform-isys-csi2-reg.h"
28 static const u32 csi2_supported_codes
[] = {
29 MEDIA_BUS_FMT_RGB565_1X16
,
30 MEDIA_BUS_FMT_RGB888_1X24
,
31 MEDIA_BUS_FMT_UYVY8_1X16
,
32 MEDIA_BUS_FMT_YUYV8_1X16
,
33 MEDIA_BUS_FMT_SBGGR10_1X10
,
34 MEDIA_BUS_FMT_SGBRG10_1X10
,
35 MEDIA_BUS_FMT_SGRBG10_1X10
,
36 MEDIA_BUS_FMT_SRGGB10_1X10
,
37 MEDIA_BUS_FMT_SBGGR12_1X12
,
38 MEDIA_BUS_FMT_SGBRG12_1X12
,
39 MEDIA_BUS_FMT_SGRBG12_1X12
,
40 MEDIA_BUS_FMT_SRGGB12_1X12
,
41 MEDIA_BUS_FMT_SBGGR8_1X8
,
42 MEDIA_BUS_FMT_SGBRG8_1X8
,
43 MEDIA_BUS_FMT_SGRBG8_1X8
,
44 MEDIA_BUS_FMT_SRGGB8_1X8
,
46 MEDIA_BUS_FMT_META_10
,
47 MEDIA_BUS_FMT_META_12
,
48 MEDIA_BUS_FMT_META_16
,
49 MEDIA_BUS_FMT_META_24
,
54 * Strings corresponding to CSI-2 receiver errors are here.
55 * Corresponding macros are defined in the header file.
57 static const struct ipu6_csi2_error dphy_rx_errors
[] = {
58 { "Single packet header error corrected", true },
59 { "Multiple packet header errors detected", true },
60 { "Payload checksum (CRC) error", true },
61 { "Transfer FIFO overflow", false },
62 { "Reserved short packet data type detected", true },
63 { "Reserved long packet data type detected", true },
64 { "Incomplete long packet detected", false },
65 { "Frame sync error", false },
66 { "Line sync error", false },
67 { "DPHY recoverable synchronization error", true },
68 { "DPHY fatal error", false },
69 { "DPHY elastic FIFO overflow", false },
70 { "Inter-frame short packet discarded", true },
71 { "Inter-frame long packet discarded", true },
72 { "MIPI pktgen overflow", false },
73 { "MIPI pktgen data loss", false },
74 { "FIFO overflow", false },
75 { "Lane deskew", false },
76 { "SOT sync error", false },
77 { "HSIDLE detected", false }
80 s64
ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2
*csi2
)
82 struct media_pad
*src_pad
;
83 struct v4l2_subdev
*ext_sd
;
89 dev
= &csi2
->isys
->adev
->auxdev
.dev
;
90 src_pad
= media_entity_remote_source_pad_unique(&csi2
->asd
.sd
.entity
);
91 if (IS_ERR(src_pad
)) {
92 dev_err(dev
, "can't get source pad of %s (%ld)\n",
93 csi2
->asd
.sd
.name
, PTR_ERR(src_pad
));
94 return PTR_ERR(src_pad
);
97 ext_sd
= media_entity_to_v4l2_subdev(src_pad
->entity
);
98 if (WARN(!ext_sd
, "Failed to get subdev for %s\n", csi2
->asd
.sd
.name
))
101 return v4l2_get_link_freq(ext_sd
->ctrl_handler
, 0, 0);
104 static int csi2_subscribe_event(struct v4l2_subdev
*sd
, struct v4l2_fh
*fh
,
105 struct v4l2_event_subscription
*sub
)
107 struct ipu6_isys_subdev
*asd
= to_ipu6_isys_subdev(sd
);
108 struct ipu6_isys_csi2
*csi2
= to_ipu6_isys_csi2(asd
);
109 struct device
*dev
= &csi2
->isys
->adev
->auxdev
.dev
;
111 dev_dbg(dev
, "csi2 subscribe event(type %u id %u)\n",
115 case V4L2_EVENT_FRAME_SYNC
:
116 return v4l2_event_subscribe(fh
, sub
, 10, NULL
);
117 case V4L2_EVENT_CTRL
:
118 return v4l2_ctrl_subscribe_event(fh
, sub
);
124 static const struct v4l2_subdev_core_ops csi2_sd_core_ops
= {
125 .subscribe_event
= csi2_subscribe_event
,
126 .unsubscribe_event
= v4l2_event_subdev_unsubscribe
,
130 * The input system CSI2+ receiver has several
131 * parameters affecting the receiver timings. These depend
132 * on the MIPI bus frequency F in Hz (sensor transmitter rate)
134 * register value = (A/1e9 + B * UI) / COUNT_ACC
136 * UI = 1 / (2 * F) in seconds
137 * COUNT_ACC = counter accuracy in seconds
138 * COUNT_ACC = 0.125 ns = 1 / 8 ns, ACCINV = 8.
140 * A and B are coefficients from the table below,
141 * depending whether the register minimum or maximum value is
145 * reg_rx_csi_dly_cnt_termen_clane 0 0 38 0
146 * reg_rx_csi_dly_cnt_settle_clane 95 -8 300 -16
148 * reg_rx_csi_dly_cnt_termen_dlane0 0 0 35 4
149 * reg_rx_csi_dly_cnt_settle_dlane0 85 -2 145 -6
150 * reg_rx_csi_dly_cnt_termen_dlane1 0 0 35 4
151 * reg_rx_csi_dly_cnt_settle_dlane1 85 -2 145 -6
152 * reg_rx_csi_dly_cnt_termen_dlane2 0 0 35 4
153 * reg_rx_csi_dly_cnt_settle_dlane2 85 -2 145 -6
154 * reg_rx_csi_dly_cnt_termen_dlane3 0 0 35 4
155 * reg_rx_csi_dly_cnt_settle_dlane3 85 -2 145 -6
157 * We use the minimum values of both A and B.
161 #define CSI2_ACCINV 8
163 static u32
calc_timing(s32 a
, s32 b
, s64 link_freq
, s32 accinv
)
165 return accinv
* a
+ (accinv
* b
* (500000000 >> DIV_SHIFT
)
166 / (s32
)(link_freq
>> DIV_SHIFT
));
170 ipu6_isys_csi2_calc_timing(struct ipu6_isys_csi2
*csi2
,
171 struct ipu6_isys_csi2_timing
*timing
, s32 accinv
)
173 struct device
*dev
= &csi2
->isys
->adev
->auxdev
.dev
;
176 link_freq
= ipu6_isys_csi2_get_link_freq(csi2
);
180 timing
->ctermen
= calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A
,
181 CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_B
,
183 timing
->csettle
= calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_A
,
184 CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_B
,
186 timing
->dtermen
= calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_A
,
187 CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_B
,
189 timing
->dsettle
= calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_A
,
190 CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_B
,
193 dev_dbg(dev
, "ctermen %u csettle %u dtermen %u dsettle %u\n",
194 timing
->ctermen
, timing
->csettle
,
195 timing
->dtermen
, timing
->dsettle
);
200 void ipu6_isys_register_errors(struct ipu6_isys_csi2
*csi2
)
202 u32 irq
= readl(csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
203 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET
);
204 struct ipu6_isys
*isys
= csi2
->isys
;
207 mask
= isys
->pdata
->ipdata
->csi2
.irq_mask
;
208 writel(irq
& mask
, csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
209 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET
);
210 csi2
->receiver_errors
|= irq
& mask
;
213 void ipu6_isys_csi2_error(struct ipu6_isys_csi2
*csi2
)
215 struct device
*dev
= &csi2
->isys
->adev
->auxdev
.dev
;
216 const struct ipu6_csi2_error
*errors
;
220 /* register errors once more in case of interrupts are disabled */
221 ipu6_isys_register_errors(csi2
);
222 status
= csi2
->receiver_errors
;
223 csi2
->receiver_errors
= 0;
224 errors
= dphy_rx_errors
;
226 for (i
= 0; i
< CSI_RX_NUM_ERRORS_IN_IRQ
; i
++) {
228 dev_err_ratelimited(dev
, "csi2-%i error: %s\n",
229 csi2
->port
, errors
[i
].error_string
);
233 static int ipu6_isys_csi2_set_stream(struct v4l2_subdev
*sd
,
234 const struct ipu6_isys_csi2_timing
*timing
,
235 unsigned int nlanes
, int enable
)
237 struct ipu6_isys_subdev
*asd
= to_ipu6_isys_subdev(sd
);
238 struct ipu6_isys_csi2
*csi2
= to_ipu6_isys_csi2(asd
);
239 struct ipu6_isys
*isys
= csi2
->isys
;
240 struct device
*dev
= &isys
->adev
->auxdev
.dev
;
241 struct ipu6_isys_csi2_config cfg
;
247 dev_dbg(dev
, "stream %s CSI2-%u with %u lanes\n", enable
? "on" : "off",
250 cfg
.port
= csi2
->port
;
253 mask
= isys
->pdata
->ipdata
->csi2
.irq_mask
;
254 nports
= isys
->pdata
->ipdata
->csi2
.nports
;
257 writel(0, csi2
->base
+ CSI_REG_CSI_FE_ENABLE
);
258 writel(0, csi2
->base
+ CSI_REG_PPI2CSI_ENABLE
);
261 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
262 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET
);
264 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
265 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET
);
267 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
268 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET
);
270 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
271 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET
);
273 isys
->phy_set_power(isys
, &cfg
, timing
, false);
275 writel(0, isys
->pdata
->base
+ CSI_REG_HUB_FW_ACCESS_PORT
276 (isys
->pdata
->ipdata
->csi2
.fw_access_port_ofs
,
278 writel(0, isys
->pdata
->base
+
279 CSI_REG_HUB_DRV_ACCESS_PORT(csi2
->port
));
284 /* reset port reset */
285 writel(0x1, csi2
->base
+ CSI_REG_PORT_GPREG_SRST
);
286 usleep_range(100, 200);
287 writel(0x0, csi2
->base
+ CSI_REG_PORT_GPREG_SRST
);
289 /* enable port clock */
290 for (i
= 0; i
< nports
; i
++) {
291 writel(1, isys
->pdata
->base
+ CSI_REG_HUB_DRV_ACCESS_PORT(i
));
292 writel(1, isys
->pdata
->base
+ CSI_REG_HUB_FW_ACCESS_PORT
293 (isys
->pdata
->ipdata
->csi2
.fw_access_port_ofs
, i
));
296 /* enable all error related irq */
298 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
299 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET
);
301 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
302 CSI_PORT_REG_BASE_IRQ_MASK_OFFSET
);
304 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
305 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET
);
307 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
308 CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET
);
310 csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI
+
311 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET
);
314 * Using event from firmware instead of irq to handle CSI2 sync event
315 * which can reduce system wakeups. If CSI2 sync irq enabled, we need
316 * disable the firmware CSI2 sync event to avoid duplicate handling.
318 writel(0xffffffff, csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
319 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET
);
320 writel(0, csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
321 CSI_PORT_REG_BASE_IRQ_MASK_OFFSET
);
322 writel(0xffffffff, csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
323 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET
);
324 writel(0, csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
325 CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET
);
326 writel(0xffffffff, csi2
->base
+ CSI_PORT_REG_BASE_IRQ_CSI_SYNC
+
327 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET
);
329 /* configure to enable FE and PPI2CSI */
330 writel(0, csi2
->base
+ CSI_REG_CSI_FE_MODE
);
331 writel(CSI_SENSOR_INPUT
, csi2
->base
+ CSI_REG_CSI_FE_MUX_CTRL
);
332 writel(CSI_CNTR_SENSOR_LINE_ID
| CSI_CNTR_SENSOR_FRAME_ID
,
333 csi2
->base
+ CSI_REG_CSI_FE_SYNC_CNTR_SEL
);
334 writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK
, nlanes
- 1),
335 csi2
->base
+ CSI_REG_PPI2CSI_CONFIG_PPI_INTF
);
337 writel(1, csi2
->base
+ CSI_REG_PPI2CSI_ENABLE
);
338 writel(1, csi2
->base
+ CSI_REG_CSI_FE_ENABLE
);
340 ret
= isys
->phy_set_power(isys
, &cfg
, timing
, true);
342 dev_err(dev
, "csi-%d phy power up failed %d\n", csi2
->port
,
348 static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev
*sd
,
349 struct v4l2_subdev_state
*state
,
350 u32 pad
, u64 streams_mask
)
352 struct ipu6_isys_subdev
*asd
= to_ipu6_isys_subdev(sd
);
353 struct ipu6_isys_csi2
*csi2
= to_ipu6_isys_csi2(asd
);
354 struct ipu6_isys_csi2_timing timing
= { };
355 struct v4l2_subdev
*remote_sd
;
356 struct media_pad
*remote_pad
;
360 remote_pad
= media_pad_remote_pad_first(&sd
->entity
.pads
[CSI2_PAD_SINK
]);
361 remote_sd
= media_entity_to_v4l2_subdev(remote_pad
->entity
);
363 sink_streams
= v4l2_subdev_state_xlate_streams(state
, CSI2_PAD_SRC
,
367 ret
= ipu6_isys_csi2_calc_timing(csi2
, &timing
, CSI2_ACCINV
);
371 ret
= ipu6_isys_csi2_set_stream(sd
, &timing
, csi2
->nlanes
, true);
375 ret
= v4l2_subdev_enable_streams(remote_sd
, remote_pad
->index
,
378 ipu6_isys_csi2_set_stream(sd
, NULL
, 0, false);
385 static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev
*sd
,
386 struct v4l2_subdev_state
*state
,
387 u32 pad
, u64 streams_mask
)
389 struct v4l2_subdev
*remote_sd
;
390 struct media_pad
*remote_pad
;
393 sink_streams
= v4l2_subdev_state_xlate_streams(state
, CSI2_PAD_SRC
,
397 remote_pad
= media_pad_remote_pad_first(&sd
->entity
.pads
[CSI2_PAD_SINK
]);
398 remote_sd
= media_entity_to_v4l2_subdev(remote_pad
->entity
);
400 ipu6_isys_csi2_set_stream(sd
, NULL
, 0, false);
402 v4l2_subdev_disable_streams(remote_sd
, remote_pad
->index
, sink_streams
);
407 static int ipu6_isys_csi2_set_sel(struct v4l2_subdev
*sd
,
408 struct v4l2_subdev_state
*state
,
409 struct v4l2_subdev_selection
*sel
)
411 struct ipu6_isys_subdev
*asd
= to_ipu6_isys_subdev(sd
);
412 struct device
*dev
= &asd
->isys
->adev
->auxdev
.dev
;
413 struct v4l2_mbus_framefmt
*sink_ffmt
;
414 struct v4l2_mbus_framefmt
*src_ffmt
;
415 struct v4l2_rect
*crop
;
417 if (sel
->pad
== CSI2_PAD_SINK
|| sel
->target
!= V4L2_SEL_TGT_CROP
)
420 sink_ffmt
= v4l2_subdev_state_get_opposite_stream_format(state
,
426 src_ffmt
= v4l2_subdev_state_get_format(state
, sel
->pad
, sel
->stream
);
430 crop
= v4l2_subdev_state_get_crop(state
, sel
->pad
, sel
->stream
);
434 /* Only vertical cropping is supported */
436 sel
->r
.width
= sink_ffmt
->width
;
437 /* Non-bayer formats can't be single line cropped */
438 if (!ipu6_isys_is_bayer_format(sink_ffmt
->code
))
440 sel
->r
.height
= clamp(sel
->r
.height
& ~1, IPU6_ISYS_MIN_HEIGHT
,
441 sink_ffmt
->height
- sel
->r
.top
);
444 /* update source pad format */
445 src_ffmt
->width
= sel
->r
.width
;
446 src_ffmt
->height
= sel
->r
.height
;
447 if (ipu6_isys_is_bayer_format(sink_ffmt
->code
))
448 src_ffmt
->code
= ipu6_isys_convert_bayer_order(sink_ffmt
->code
,
451 dev_dbg(dev
, "set crop for %s sel: %d,%d,%d,%d code: 0x%x\n",
452 sd
->name
, sel
->r
.left
, sel
->r
.top
, sel
->r
.width
, sel
->r
.height
,
458 static int ipu6_isys_csi2_get_sel(struct v4l2_subdev
*sd
,
459 struct v4l2_subdev_state
*state
,
460 struct v4l2_subdev_selection
*sel
)
462 struct v4l2_mbus_framefmt
*sink_ffmt
;
463 struct v4l2_rect
*crop
;
466 if (sd
->entity
.pads
[sel
->pad
].flags
& MEDIA_PAD_FL_SINK
)
469 sink_ffmt
= v4l2_subdev_state_get_opposite_stream_format(state
,
475 crop
= v4l2_subdev_state_get_crop(state
, sel
->pad
, sel
->stream
);
479 switch (sel
->target
) {
480 case V4L2_SEL_TGT_CROP_DEFAULT
:
481 case V4L2_SEL_TGT_CROP_BOUNDS
:
484 sel
->r
.width
= sink_ffmt
->width
;
485 sel
->r
.height
= sink_ffmt
->height
;
487 case V4L2_SEL_TGT_CROP
:
497 static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops
= {
498 .get_fmt
= v4l2_subdev_get_fmt
,
499 .set_fmt
= ipu6_isys_subdev_set_fmt
,
500 .get_selection
= ipu6_isys_csi2_get_sel
,
501 .set_selection
= ipu6_isys_csi2_set_sel
,
502 .enum_mbus_code
= ipu6_isys_subdev_enum_mbus_code
,
503 .set_routing
= ipu6_isys_subdev_set_routing
,
504 .enable_streams
= ipu6_isys_csi2_enable_streams
,
505 .disable_streams
= ipu6_isys_csi2_disable_streams
,
508 static const struct v4l2_subdev_ops csi2_sd_ops
= {
509 .core
= &csi2_sd_core_ops
,
510 .pad
= &csi2_sd_pad_ops
,
513 static const struct media_entity_operations csi2_entity_ops
= {
514 .link_validate
= v4l2_subdev_link_validate
,
515 .has_pad_interdep
= v4l2_subdev_has_pad_interdep
,
518 void ipu6_isys_csi2_cleanup(struct ipu6_isys_csi2
*csi2
)
523 v4l2_device_unregister_subdev(&csi2
->asd
.sd
);
524 v4l2_subdev_cleanup(&csi2
->asd
.sd
);
525 ipu6_isys_subdev_cleanup(&csi2
->asd
);
529 int ipu6_isys_csi2_init(struct ipu6_isys_csi2
*csi2
,
530 struct ipu6_isys
*isys
,
531 void __iomem
*base
, unsigned int index
)
533 struct device
*dev
= &isys
->adev
->auxdev
.dev
;
540 csi2
->asd
.sd
.entity
.ops
= &csi2_entity_ops
;
541 csi2
->asd
.isys
= isys
;
542 ret
= ipu6_isys_subdev_init(&csi2
->asd
, &csi2_sd_ops
, 0,
543 NR_OF_CSI2_SINK_PADS
, NR_OF_CSI2_SRC_PADS
);
547 csi2
->asd
.source
= IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT0
+ index
;
548 csi2
->asd
.supported_codes
= csi2_supported_codes
;
549 snprintf(csi2
->asd
.sd
.name
, sizeof(csi2
->asd
.sd
.name
),
550 IPU6_ISYS_ENTITY_PREFIX
" CSI2 %u", index
);
551 v4l2_set_subdevdata(&csi2
->asd
.sd
, &csi2
->asd
);
552 ret
= v4l2_subdev_init_finalize(&csi2
->asd
.sd
);
554 dev_err(dev
, "failed to init v4l2 subdev\n");
558 ret
= v4l2_device_register_subdev(&isys
->v4l2_dev
, &csi2
->asd
.sd
);
560 dev_err(dev
, "failed to register v4l2 subdev\n");
567 ipu6_isys_csi2_cleanup(csi2
);
572 void ipu6_isys_csi2_sof_event_by_stream(struct ipu6_isys_stream
*stream
)
574 struct video_device
*vdev
= stream
->asd
->sd
.devnode
;
575 struct device
*dev
= &stream
->isys
->adev
->auxdev
.dev
;
576 struct ipu6_isys_csi2
*csi2
= ipu6_isys_subdev_to_csi2(stream
->asd
);
577 struct v4l2_event ev
= {
578 .type
= V4L2_EVENT_FRAME_SYNC
,
581 ev
.u
.frame_sync
.frame_sequence
= atomic_fetch_inc(&stream
->sequence
);
582 v4l2_event_queue(vdev
, &ev
);
584 dev_dbg(dev
, "sof_event::csi2-%i sequence: %i, vc: %d\n",
585 csi2
->port
, ev
.u
.frame_sync
.frame_sequence
, stream
->vc
);
588 void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream
*stream
)
590 struct device
*dev
= &stream
->isys
->adev
->auxdev
.dev
;
591 struct ipu6_isys_csi2
*csi2
= ipu6_isys_subdev_to_csi2(stream
->asd
);
592 u32 frame_sequence
= atomic_read(&stream
->sequence
);
594 dev_dbg(dev
, "eof_event::csi2-%i sequence: %i\n",
595 csi2
->port
, frame_sequence
);
598 int ipu6_isys_csi2_get_remote_desc(u32 source_stream
,
599 struct ipu6_isys_csi2
*csi2
,
600 struct media_entity
*source_entity
,
601 struct v4l2_mbus_frame_desc_entry
*entry
)
603 struct v4l2_mbus_frame_desc_entry
*desc_entry
= NULL
;
604 struct device
*dev
= &csi2
->isys
->adev
->auxdev
.dev
;
605 struct v4l2_mbus_frame_desc desc
;
606 struct v4l2_subdev
*source
;
607 struct media_pad
*pad
;
611 source
= media_entity_to_v4l2_subdev(source_entity
);
615 pad
= media_pad_remote_pad_first(&csi2
->asd
.pad
[CSI2_PAD_SINK
]);
619 ret
= v4l2_subdev_call(source
, pad
, get_frame_desc
, pad
->index
, &desc
);
623 if (desc
.type
!= V4L2_MBUS_FRAME_DESC_TYPE_CSI2
) {
624 dev_err(dev
, "Unsupported frame descriptor type\n");
628 for (i
= 0; i
< desc
.num_entries
; i
++) {
629 if (source_stream
== desc
.entry
[i
].stream
) {
630 desc_entry
= &desc
.entry
[i
];
636 dev_err(dev
, "Failed to find stream %u from remote subdev\n",
641 if (desc_entry
->bus
.csi2
.vc
>= NR_OF_CSI2_VC
) {
642 dev_err(dev
, "invalid vc %d\n", desc_entry
->bus
.csi2
.vc
);
646 *entry
= *desc_entry
;