Lines Matching +full:sync +full:- +full:update +full:- +full:mask
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013--2024 Intel Corporation
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>
22 #include "ipu6-bus.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"
54 * Strings corresponding to CSI-2 receiver errors are here.
65 { "Frame sync error", false },
66 { "Line sync error", false },
70 { "Inter-frame short packet discarded", true },
71 { "Inter-frame long packet discarded", true },
76 { "SOT sync error", false },
85 return -EINVAL; in ipu6_isys_csi2_get_link_freq()
87 src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity); in ipu6_isys_csi2_get_link_freq()
89 dev_err(&csi2->isys->adev->auxdev.dev, in ipu6_isys_csi2_get_link_freq()
91 csi2->asd.sd.name, PTR_ERR(src_pad)); in ipu6_isys_csi2_get_link_freq()
103 struct device *dev = &csi2->isys->adev->auxdev.dev; in csi2_subscribe_event()
106 sub->type, sub->id); in csi2_subscribe_event()
108 switch (sub->type) { in csi2_subscribe_event()
114 return -EINVAL; in csi2_subscribe_event()
140 * reg_rx_csi_dly_cnt_settle_clane 95 -8 300 -16
143 * reg_rx_csi_dly_cnt_settle_dlane0 85 -2 145 -6
145 * reg_rx_csi_dly_cnt_settle_dlane1 85 -2 145 -6
147 * reg_rx_csi_dly_cnt_settle_dlane2 85 -2 145 -6
149 * reg_rx_csi_dly_cnt_settle_dlane3 85 -2 145 -6
167 struct device *dev = &csi2->isys->adev->auxdev.dev; in ipu6_isys_csi2_calc_timing()
174 timing->ctermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A, in ipu6_isys_csi2_calc_timing()
177 timing->csettle = calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_A, in ipu6_isys_csi2_calc_timing()
180 timing->dtermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_A, in ipu6_isys_csi2_calc_timing()
183 timing->dsettle = calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_A, in ipu6_isys_csi2_calc_timing()
188 timing->ctermen, timing->csettle, in ipu6_isys_csi2_calc_timing()
189 timing->dtermen, timing->dsettle); in ipu6_isys_csi2_calc_timing()
196 u32 irq = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_register_errors()
198 struct ipu6_isys *isys = csi2->isys; in ipu6_isys_register_errors()
199 u32 mask; in ipu6_isys_register_errors() local
201 mask = isys->pdata->ipdata->csi2.irq_mask; in ipu6_isys_register_errors()
202 writel(irq & mask, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_register_errors()
204 csi2->receiver_errors |= irq & mask; in ipu6_isys_register_errors()
209 struct device *dev = &csi2->isys->adev->auxdev.dev; in ipu6_isys_csi2_error()
216 status = csi2->receiver_errors; in ipu6_isys_csi2_error()
217 csi2->receiver_errors = 0; in ipu6_isys_csi2_error()
222 dev_err_ratelimited(dev, "csi2-%i error: %s\n", in ipu6_isys_csi2_error()
223 csi2->port, errors[i].error_string); in ipu6_isys_csi2_error()
233 struct ipu6_isys *isys = csi2->isys; in ipu6_isys_csi2_set_stream()
234 struct device *dev = &isys->adev->auxdev.dev; in ipu6_isys_csi2_set_stream()
238 u32 mask = 0; in ipu6_isys_csi2_set_stream() local
241 dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off", in ipu6_isys_csi2_set_stream()
242 csi2->port, nlanes); in ipu6_isys_csi2_set_stream()
244 cfg.port = csi2->port; in ipu6_isys_csi2_set_stream()
247 mask = isys->pdata->ipdata->csi2.irq_mask; in ipu6_isys_csi2_set_stream()
248 nports = isys->pdata->ipdata->csi2.nports; in ipu6_isys_csi2_set_stream()
251 writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE); in ipu6_isys_csi2_set_stream()
252 writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE); in ipu6_isys_csi2_set_stream()
255 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
257 writel(mask, in ipu6_isys_csi2_set_stream()
258 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
261 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
264 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
267 isys->phy_set_power(isys, &cfg, timing, false); in ipu6_isys_csi2_set_stream()
269 writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT in ipu6_isys_csi2_set_stream()
270 (isys->pdata->ipdata->csi2.fw_access_port_ofs, in ipu6_isys_csi2_set_stream()
271 csi2->port)); in ipu6_isys_csi2_set_stream()
272 writel(0, isys->pdata->base + in ipu6_isys_csi2_set_stream()
273 CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port)); in ipu6_isys_csi2_set_stream()
279 writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST); in ipu6_isys_csi2_set_stream()
281 writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST); in ipu6_isys_csi2_set_stream()
285 writel(1, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(i)); in ipu6_isys_csi2_set_stream()
286 writel(1, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT in ipu6_isys_csi2_set_stream()
287 (isys->pdata->ipdata->csi2.fw_access_port_ofs, i)); in ipu6_isys_csi2_set_stream()
291 writel(mask, in ipu6_isys_csi2_set_stream()
292 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
294 writel(mask, in ipu6_isys_csi2_set_stream()
295 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
297 writel(mask, in ipu6_isys_csi2_set_stream()
298 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
300 writel(mask, in ipu6_isys_csi2_set_stream()
301 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
303 writel(mask, in ipu6_isys_csi2_set_stream()
304 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI + in ipu6_isys_csi2_set_stream()
308 * Using event from firmware instead of irq to handle CSI2 sync event in ipu6_isys_csi2_set_stream()
309 * which can reduce system wakeups. If CSI2 sync irq enabled, we need in ipu6_isys_csi2_set_stream()
310 * disable the firmware CSI2 sync event to avoid duplicate handling. in ipu6_isys_csi2_set_stream()
312 writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
314 writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
316 writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
318 writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
320 writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC + in ipu6_isys_csi2_set_stream()
324 writel(0, csi2->base + CSI_REG_CSI_FE_MODE); in ipu6_isys_csi2_set_stream()
325 writel(CSI_SENSOR_INPUT, csi2->base + CSI_REG_CSI_FE_MUX_CTRL); in ipu6_isys_csi2_set_stream()
327 csi2->base + CSI_REG_CSI_FE_SYNC_CNTR_SEL); in ipu6_isys_csi2_set_stream()
328 writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK, nlanes - 1), in ipu6_isys_csi2_set_stream()
329 csi2->base + CSI_REG_PPI2CSI_CONFIG_PPI_INTF); in ipu6_isys_csi2_set_stream()
331 writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE); in ipu6_isys_csi2_set_stream()
332 writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE); in ipu6_isys_csi2_set_stream()
334 ret = isys->phy_set_power(isys, &cfg, timing, true); in ipu6_isys_csi2_set_stream()
336 dev_err(dev, "csi-%d phy power up failed %d\n", csi2->port, in ipu6_isys_csi2_set_stream()
354 remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); in ipu6_isys_csi2_enable_streams()
355 remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); in ipu6_isys_csi2_enable_streams()
365 ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true); in ipu6_isys_csi2_enable_streams()
369 ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, in ipu6_isys_csi2_enable_streams()
391 remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); in ipu6_isys_csi2_disable_streams()
392 remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); in ipu6_isys_csi2_disable_streams()
396 v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams); in ipu6_isys_csi2_disable_streams()
406 struct device *dev = &asd->isys->adev->auxdev.dev; in ipu6_isys_csi2_set_sel()
411 if (sel->pad == CSI2_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) in ipu6_isys_csi2_set_sel()
412 return -EINVAL; in ipu6_isys_csi2_set_sel()
415 sel->pad, in ipu6_isys_csi2_set_sel()
416 sel->stream); in ipu6_isys_csi2_set_sel()
418 return -EINVAL; in ipu6_isys_csi2_set_sel()
420 src_ffmt = v4l2_subdev_state_get_format(state, sel->pad, sel->stream); in ipu6_isys_csi2_set_sel()
422 return -EINVAL; in ipu6_isys_csi2_set_sel()
424 crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); in ipu6_isys_csi2_set_sel()
426 return -EINVAL; in ipu6_isys_csi2_set_sel()
429 sel->r.left = 0; in ipu6_isys_csi2_set_sel()
430 sel->r.width = sink_ffmt->width; in ipu6_isys_csi2_set_sel()
431 /* Non-bayer formats can't be single line cropped */ in ipu6_isys_csi2_set_sel()
432 if (!ipu6_isys_is_bayer_format(sink_ffmt->code)) in ipu6_isys_csi2_set_sel()
433 sel->r.top &= ~1; in ipu6_isys_csi2_set_sel()
434 sel->r.height = clamp(sel->r.height & ~1, IPU6_ISYS_MIN_HEIGHT, in ipu6_isys_csi2_set_sel()
435 sink_ffmt->height - sel->r.top); in ipu6_isys_csi2_set_sel()
436 *crop = sel->r; in ipu6_isys_csi2_set_sel()
438 /* update source pad format */ in ipu6_isys_csi2_set_sel()
439 src_ffmt->width = sel->r.width; in ipu6_isys_csi2_set_sel()
440 src_ffmt->height = sel->r.height; in ipu6_isys_csi2_set_sel()
441 if (ipu6_isys_is_bayer_format(sink_ffmt->code)) in ipu6_isys_csi2_set_sel()
442 src_ffmt->code = ipu6_isys_convert_bayer_order(sink_ffmt->code, in ipu6_isys_csi2_set_sel()
443 sel->r.left, in ipu6_isys_csi2_set_sel()
444 sel->r.top); in ipu6_isys_csi2_set_sel()
446 sd->name, sel->r.left, sel->r.top, sel->r.width, sel->r.height, in ipu6_isys_csi2_set_sel()
447 src_ffmt->code); in ipu6_isys_csi2_set_sel()
460 if (sd->entity.pads[sel->pad].flags & MEDIA_PAD_FL_SINK) in ipu6_isys_csi2_get_sel()
461 return -EINVAL; in ipu6_isys_csi2_get_sel()
464 sel->pad, in ipu6_isys_csi2_get_sel()
465 sel->stream); in ipu6_isys_csi2_get_sel()
467 return -EINVAL; in ipu6_isys_csi2_get_sel()
469 crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); in ipu6_isys_csi2_get_sel()
471 return -EINVAL; in ipu6_isys_csi2_get_sel()
473 switch (sel->target) { in ipu6_isys_csi2_get_sel()
476 sel->r.left = 0; in ipu6_isys_csi2_get_sel()
477 sel->r.top = 0; in ipu6_isys_csi2_get_sel()
478 sel->r.width = sink_ffmt->width; in ipu6_isys_csi2_get_sel()
479 sel->r.height = sink_ffmt->height; in ipu6_isys_csi2_get_sel()
482 sel->r = *crop; in ipu6_isys_csi2_get_sel()
485 ret = -EINVAL; in ipu6_isys_csi2_get_sel()
514 if (!csi2->isys) in ipu6_isys_csi2_cleanup()
517 v4l2_device_unregister_subdev(&csi2->asd.sd); in ipu6_isys_csi2_cleanup()
518 v4l2_subdev_cleanup(&csi2->asd.sd); in ipu6_isys_csi2_cleanup()
519 ipu6_isys_subdev_cleanup(&csi2->asd); in ipu6_isys_csi2_cleanup()
520 csi2->isys = NULL; in ipu6_isys_csi2_cleanup()
527 struct device *dev = &isys->adev->auxdev.dev; in ipu6_isys_csi2_init()
530 csi2->isys = isys; in ipu6_isys_csi2_init()
531 csi2->base = base; in ipu6_isys_csi2_init()
532 csi2->port = index; in ipu6_isys_csi2_init()
534 csi2->asd.sd.entity.ops = &csi2_entity_ops; in ipu6_isys_csi2_init()
535 csi2->asd.isys = isys; in ipu6_isys_csi2_init()
536 ret = ipu6_isys_subdev_init(&csi2->asd, &csi2_sd_ops, 0, in ipu6_isys_csi2_init()
541 csi2->asd.source = IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT0 + index; in ipu6_isys_csi2_init()
542 csi2->asd.supported_codes = csi2_supported_codes; in ipu6_isys_csi2_init()
543 snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name), in ipu6_isys_csi2_init()
545 v4l2_set_subdevdata(&csi2->asd.sd, &csi2->asd); in ipu6_isys_csi2_init()
546 ret = v4l2_subdev_init_finalize(&csi2->asd.sd); in ipu6_isys_csi2_init()
552 ret = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2->asd.sd); in ipu6_isys_csi2_init()
568 struct video_device *vdev = stream->asd->sd.devnode; in ipu6_isys_csi2_sof_event_by_stream()
569 struct device *dev = &stream->isys->adev->auxdev.dev; in ipu6_isys_csi2_sof_event_by_stream()
570 struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd); in ipu6_isys_csi2_sof_event_by_stream()
575 ev.u.frame_sync.frame_sequence = atomic_fetch_inc(&stream->sequence); in ipu6_isys_csi2_sof_event_by_stream()
578 dev_dbg(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n", in ipu6_isys_csi2_sof_event_by_stream()
579 csi2->port, ev.u.frame_sync.frame_sequence, stream->vc); in ipu6_isys_csi2_sof_event_by_stream()
584 struct device *dev = &stream->isys->adev->auxdev.dev; in ipu6_isys_csi2_eof_event_by_stream()
585 struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd); in ipu6_isys_csi2_eof_event_by_stream()
586 u32 frame_sequence = atomic_read(&stream->sequence); in ipu6_isys_csi2_eof_event_by_stream()
588 dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n", in ipu6_isys_csi2_eof_event_by_stream()
589 csi2->port, frame_sequence); in ipu6_isys_csi2_eof_event_by_stream()
598 struct device *dev = &csi2->isys->adev->auxdev.dev; in ipu6_isys_csi2_get_remote_desc()
607 return -EPIPE; in ipu6_isys_csi2_get_remote_desc()
609 pad = media_pad_remote_pad_first(&csi2->asd.pad[CSI2_PAD_SINK]); in ipu6_isys_csi2_get_remote_desc()
611 return -EPIPE; in ipu6_isys_csi2_get_remote_desc()
613 ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc); in ipu6_isys_csi2_get_remote_desc()
619 return -EINVAL; in ipu6_isys_csi2_get_remote_desc()
632 return -EINVAL; in ipu6_isys_csi2_get_remote_desc()
635 if (desc_entry->bus.csi2.vc >= NR_OF_CSI2_VC) { in ipu6_isys_csi2_get_remote_desc()
636 dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc); in ipu6_isys_csi2_get_remote_desc()
637 return -EINVAL; in ipu6_isys_csi2_get_remote_desc()