Lines Matching +full:no +full:- +full:sd

1 // SPDX-License-Identifier: GPL-2.0
22 #include <media/media-entity.h>
23 #include <media/v4l2-subdev.h>
24 #include <media/videobuf2-v4l2.h>
26 #include "imx8-isi-core.h"
27 #include "imx8-isi-regs.h"
30 * While the ISI receives data from the gasket on a 3x12-bit bus, the pipeline
202 if (info->mbus_code == code && info->pads & BIT(pad)) in mxc_isi_bus_format_by_code()
218 if (!(info->pads & BIT(pad))) in mxc_isi_bus_format_by_index()
224 index--; in mxc_isi_bus_format_by_index()
230 static inline struct mxc_isi_pipe *to_isi_pipe(struct v4l2_subdev *sd) in to_isi_pipe() argument
232 return container_of(sd, struct mxc_isi_pipe, sd); in to_isi_pipe()
237 struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar; in mxc_isi_pipe_enable()
244 struct v4l2_subdev *sd = &pipe->sd; in mxc_isi_pipe_enable() local
254 state = v4l2_subdev_lock_and_get_active_state(&xbar->sd); in mxc_isi_pipe_enable()
255 ret = v4l2_subdev_routing_find_opposite_end(&state->routing, in mxc_isi_pipe_enable()
256 xbar->num_sinks + pipe->id, in mxc_isi_pipe_enable()
261 return -EPIPE; in mxc_isi_pipe_enable()
264 state = v4l2_subdev_lock_and_get_active_state(sd); in mxc_isi_pipe_enable()
271 sink_info = mxc_isi_bus_format_by_code(sink_fmt->code, in mxc_isi_pipe_enable()
273 src_info = mxc_isi_bus_format_by_code(src_fmt->code, in mxc_isi_pipe_enable()
276 in_size.width = sink_fmt->width; in mxc_isi_pipe_enable()
277 in_size.height = sink_fmt->height; in mxc_isi_pipe_enable()
278 scale.width = compose->width; in mxc_isi_pipe_enable()
279 scale.height = compose->height; in mxc_isi_pipe_enable()
285 sink_info->encoding, src_info->encoding); in mxc_isi_pipe_enable()
290 ret = v4l2_subdev_enable_streams(&xbar->sd, xbar->num_sinks + pipe->id, in mxc_isi_pipe_enable()
294 dev_err(pipe->isi->dev, "Failed to enable pipe %u\n", in mxc_isi_pipe_enable()
295 pipe->id); in mxc_isi_pipe_enable()
304 struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar; in mxc_isi_pipe_disable()
307 ret = v4l2_subdev_disable_streams(&xbar->sd, xbar->num_sinks + pipe->id, in mxc_isi_pipe_disable()
310 dev_err(pipe->isi->dev, "Failed to disable pipe %u\n", in mxc_isi_pipe_disable()
311 pipe->id); in mxc_isi_pipe_disable()
316 /* -----------------------------------------------------------------------------
344 static int mxc_isi_pipe_init_state(struct v4l2_subdev *sd, in mxc_isi_pipe_init_state() argument
347 struct mxc_isi_pipe *pipe = to_isi_pipe(sd); in mxc_isi_pipe_init_state()
358 fmt_sink->width = MXC_ISI_DEF_WIDTH; in mxc_isi_pipe_init_state()
359 fmt_sink->height = MXC_ISI_DEF_HEIGHT; in mxc_isi_pipe_init_state()
360 fmt_sink->code = MXC_ISI_DEF_MBUS_CODE_SINK; in mxc_isi_pipe_init_state()
361 fmt_sink->field = V4L2_FIELD_NONE; in mxc_isi_pipe_init_state()
362 fmt_sink->colorspace = V4L2_COLORSPACE_JPEG; in mxc_isi_pipe_init_state()
363 fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace); in mxc_isi_pipe_init_state()
364 fmt_sink->quantization = in mxc_isi_pipe_init_state()
365 V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, in mxc_isi_pipe_init_state()
366 fmt_sink->ycbcr_enc); in mxc_isi_pipe_init_state()
367 fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace); in mxc_isi_pipe_init_state()
370 fmt_source->code = MXC_ISI_DEF_MBUS_CODE_SOURCE; in mxc_isi_pipe_init_state()
376 compose->left = 0; in mxc_isi_pipe_init_state()
377 compose->top = 0; in mxc_isi_pipe_init_state()
378 compose->width = MXC_ISI_DEF_WIDTH; in mxc_isi_pipe_init_state()
379 compose->height = MXC_ISI_DEF_HEIGHT; in mxc_isi_pipe_init_state()
386 static int mxc_isi_pipe_enum_mbus_code(struct v4l2_subdev *sd, in mxc_isi_pipe_enum_mbus_code() argument
394 struct mxc_isi_pipe *pipe = to_isi_pipe(sd); in mxc_isi_pipe_enum_mbus_code()
399 if (code->pad == MXC_ISI_PIPE_PAD_SOURCE) { in mxc_isi_pipe_enum_mbus_code()
404 info = mxc_isi_bus_format_by_code(format->code, in mxc_isi_pipe_enum_mbus_code()
407 if (info->encoding == MXC_ISI_ENC_RAW) { in mxc_isi_pipe_enum_mbus_code()
412 if (code->index) in mxc_isi_pipe_enum_mbus_code()
413 return -EINVAL; in mxc_isi_pipe_enum_mbus_code()
415 code->code = info->output; in mxc_isi_pipe_enum_mbus_code()
422 if (code->index > 1) in mxc_isi_pipe_enum_mbus_code()
423 return -EINVAL; in mxc_isi_pipe_enum_mbus_code()
425 code->code = output_codes[code->index]; in mxc_isi_pipe_enum_mbus_code()
431 index = code->index; in mxc_isi_pipe_enum_mbus_code()
436 if (!(info->pads & BIT(MXC_ISI_PIPE_PAD_SINK))) in mxc_isi_pipe_enum_mbus_code()
440 code->code = info->mbus_code; in mxc_isi_pipe_enum_mbus_code()
444 index--; in mxc_isi_pipe_enum_mbus_code()
447 return -EINVAL; in mxc_isi_pipe_enum_mbus_code()
450 static int mxc_isi_pipe_set_fmt(struct v4l2_subdev *sd, in mxc_isi_pipe_set_fmt() argument
454 struct mxc_isi_pipe *pipe = to_isi_pipe(sd); in mxc_isi_pipe_set_fmt()
455 struct v4l2_mbus_framefmt *mf = &fmt->format; in mxc_isi_pipe_set_fmt()
460 if (vb2_is_busy(&pipe->video.vb2_q)) in mxc_isi_pipe_set_fmt()
461 return -EBUSY; in mxc_isi_pipe_set_fmt()
463 if (fmt->pad == MXC_ISI_PIPE_PAD_SINK) { in mxc_isi_pipe_set_fmt()
466 info = mxc_isi_bus_format_by_code(mf->code, in mxc_isi_pipe_set_fmt()
473 * Limit the max line length if there's no adjacent pipe to in mxc_isi_pipe_set_fmt()
476 max_width = pipe->id == pipe->isi->pdata->num_channels - 1 in mxc_isi_pipe_set_fmt()
480 mf->code = info->mbus_code; in mxc_isi_pipe_set_fmt()
481 mf->width = clamp(mf->width, MXC_ISI_MIN_WIDTH, max_width); in mxc_isi_pipe_set_fmt()
482 mf->height = clamp(mf->height, MXC_ISI_MIN_HEIGHT, in mxc_isi_pipe_set_fmt()
488 rect->width = mf->width; in mxc_isi_pipe_set_fmt()
489 rect->height = mf->height; in mxc_isi_pipe_set_fmt()
493 rect->left = 0; in mxc_isi_pipe_set_fmt()
494 rect->top = 0; in mxc_isi_pipe_set_fmt()
495 rect->width = mf->width; in mxc_isi_pipe_set_fmt()
496 rect->height = mf->height; in mxc_isi_pipe_set_fmt()
500 format->code = info->output; in mxc_isi_pipe_set_fmt()
501 format->width = mf->width; in mxc_isi_pipe_set_fmt()
502 format->height = mf->height; in mxc_isi_pipe_set_fmt()
505 * For RGB or YUV formats, the ISI supports RGB <-> YUV format in mxc_isi_pipe_set_fmt()
511 info = mxc_isi_bus_format_by_code(format->code, in mxc_isi_pipe_set_fmt()
514 if (info->encoding != MXC_ISI_ENC_RAW) { in mxc_isi_pipe_set_fmt()
515 if (mf->code != MEDIA_BUS_FMT_YUV8_1X24 && in mxc_isi_pipe_set_fmt()
516 mf->code != MEDIA_BUS_FMT_RGB888_1X24) in mxc_isi_pipe_set_fmt()
517 mf->code = info->output; in mxc_isi_pipe_set_fmt()
519 info = mxc_isi_bus_format_by_code(mf->code, in mxc_isi_pipe_set_fmt()
523 mf->code = info->output; in mxc_isi_pipe_set_fmt()
532 mf->width = rect->width; in mxc_isi_pipe_set_fmt()
533 mf->height = rect->height; in mxc_isi_pipe_set_fmt()
536 format = mxc_isi_pipe_get_pad_format(pipe, state, fmt->pad); in mxc_isi_pipe_set_fmt()
539 dev_dbg(pipe->isi->dev, "pad%u: code: 0x%04x, %ux%u", in mxc_isi_pipe_set_fmt()
540 fmt->pad, mf->code, mf->width, mf->height); in mxc_isi_pipe_set_fmt()
545 static int mxc_isi_pipe_get_selection(struct v4l2_subdev *sd, in mxc_isi_pipe_get_selection() argument
549 struct mxc_isi_pipe *pipe = to_isi_pipe(sd); in mxc_isi_pipe_get_selection()
553 switch (sel->target) { in mxc_isi_pipe_get_selection()
555 if (sel->pad != MXC_ISI_PIPE_PAD_SINK) in mxc_isi_pipe_get_selection()
556 /* No compose rectangle on source pad. */ in mxc_isi_pipe_get_selection()
557 return -EINVAL; in mxc_isi_pipe_get_selection()
562 sel->r.left = 0; in mxc_isi_pipe_get_selection()
563 sel->r.top = 0; in mxc_isi_pipe_get_selection()
564 sel->r.width = format->width; in mxc_isi_pipe_get_selection()
565 sel->r.height = format->height; in mxc_isi_pipe_get_selection()
569 if (sel->pad != MXC_ISI_PIPE_PAD_SOURCE) in mxc_isi_pipe_get_selection()
570 /* No crop rectangle on sink pad. */ in mxc_isi_pipe_get_selection()
571 return -EINVAL; in mxc_isi_pipe_get_selection()
576 sel->r = *rect; in mxc_isi_pipe_get_selection()
580 if (sel->pad != MXC_ISI_PIPE_PAD_SOURCE) in mxc_isi_pipe_get_selection()
581 /* No crop rectangle on sink pad. */ in mxc_isi_pipe_get_selection()
582 return -EINVAL; in mxc_isi_pipe_get_selection()
584 rect = mxc_isi_pipe_get_pad_crop(pipe, state, sel->pad); in mxc_isi_pipe_get_selection()
585 sel->r = *rect; in mxc_isi_pipe_get_selection()
589 if (sel->pad != MXC_ISI_PIPE_PAD_SINK) in mxc_isi_pipe_get_selection()
590 /* No compose rectangle on source pad. */ in mxc_isi_pipe_get_selection()
591 return -EINVAL; in mxc_isi_pipe_get_selection()
593 rect = mxc_isi_pipe_get_pad_compose(pipe, state, sel->pad); in mxc_isi_pipe_get_selection()
594 sel->r = *rect; in mxc_isi_pipe_get_selection()
598 return -EINVAL; in mxc_isi_pipe_get_selection()
604 static int mxc_isi_pipe_set_selection(struct v4l2_subdev *sd, in mxc_isi_pipe_set_selection() argument
608 struct mxc_isi_pipe *pipe = to_isi_pipe(sd); in mxc_isi_pipe_set_selection()
612 switch (sel->target) { in mxc_isi_pipe_set_selection()
614 if (sel->pad != MXC_ISI_PIPE_PAD_SOURCE) in mxc_isi_pipe_set_selection()
616 return -EINVAL; in mxc_isi_pipe_set_selection()
621 sel->r.left = clamp_t(s32, sel->r.left, 0, rect->width - 1); in mxc_isi_pipe_set_selection()
622 sel->r.top = clamp_t(s32, sel->r.top, 0, rect->height - 1); in mxc_isi_pipe_set_selection()
623 sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH, in mxc_isi_pipe_set_selection()
624 rect->width - sel->r.left); in mxc_isi_pipe_set_selection()
625 sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT, in mxc_isi_pipe_set_selection()
626 rect->height - sel->r.top); in mxc_isi_pipe_set_selection()
630 *rect = sel->r; in mxc_isi_pipe_set_selection()
635 format->width = sel->r.width; in mxc_isi_pipe_set_selection()
636 format->height = sel->r.height; in mxc_isi_pipe_set_selection()
640 if (sel->pad != MXC_ISI_PIPE_PAD_SINK) in mxc_isi_pipe_set_selection()
642 return -EINVAL; in mxc_isi_pipe_set_selection()
648 sel->r.left = 0; in mxc_isi_pipe_set_selection()
649 sel->r.top = 0; in mxc_isi_pipe_set_selection()
650 sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH, in mxc_isi_pipe_set_selection()
651 format->width); in mxc_isi_pipe_set_selection()
652 sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT, in mxc_isi_pipe_set_selection()
653 format->height); in mxc_isi_pipe_set_selection()
657 *rect = sel->r; in mxc_isi_pipe_set_selection()
662 rect->left = 0; in mxc_isi_pipe_set_selection()
663 rect->top = 0; in mxc_isi_pipe_set_selection()
664 rect->width = sel->r.width; in mxc_isi_pipe_set_selection()
665 rect->height = sel->r.height; in mxc_isi_pipe_set_selection()
669 format->width = sel->r.width; in mxc_isi_pipe_set_selection()
670 format->height = sel->r.height; in mxc_isi_pipe_set_selection()
674 return -EINVAL; in mxc_isi_pipe_set_selection()
677 dev_dbg(pipe->isi->dev, "%s, target %#x: (%d,%d)/%dx%d", __func__, in mxc_isi_pipe_set_selection()
678 sel->target, sel->r.left, sel->r.top, sel->r.width, in mxc_isi_pipe_set_selection()
679 sel->r.height); in mxc_isi_pipe_set_selection()
700 /* -----------------------------------------------------------------------------
707 const struct mxc_isi_ier_reg *ier_reg = pipe->isi->pdata->ier_reg; in mxc_isi_pipe_irq_handler()
713 if (!WARN_ON(!pipe->irq_handler)) in mxc_isi_pipe_irq_handler()
714 pipe->irq_handler(pipe, status); in mxc_isi_pipe_irq_handler()
720 dev_dbg(pipe->isi->dev, "%s: IRQ AXI Error stat=0x%X\n", in mxc_isi_pipe_irq_handler()
723 if (status & (ier_reg->panic_y_buf_en.mask | in mxc_isi_pipe_irq_handler()
724 ier_reg->panic_u_buf_en.mask | in mxc_isi_pipe_irq_handler()
725 ier_reg->panic_v_buf_en.mask)) in mxc_isi_pipe_irq_handler()
726 dev_dbg(pipe->isi->dev, "%s: IRQ Panic OFLW Error stat=0x%X\n", in mxc_isi_pipe_irq_handler()
729 if (status & (ier_reg->oflw_y_buf_en.mask | in mxc_isi_pipe_irq_handler()
730 ier_reg->oflw_u_buf_en.mask | in mxc_isi_pipe_irq_handler()
731 ier_reg->oflw_v_buf_en.mask)) in mxc_isi_pipe_irq_handler()
732 dev_dbg(pipe->isi->dev, "%s: IRQ OFLW Error stat=0x%X\n", in mxc_isi_pipe_irq_handler()
735 if (status & (ier_reg->excs_oflw_y_buf_en.mask | in mxc_isi_pipe_irq_handler()
736 ier_reg->excs_oflw_u_buf_en.mask | in mxc_isi_pipe_irq_handler()
737 ier_reg->excs_oflw_v_buf_en.mask)) in mxc_isi_pipe_irq_handler()
738 dev_dbg(pipe->isi->dev, "%s: IRQ EXCS OFLW Error stat=0x%X\n", in mxc_isi_pipe_irq_handler()
744 /* -----------------------------------------------------------------------------
754 struct mxc_isi_pipe *pipe = &isi->pipes[id]; in mxc_isi_pipe_init()
755 struct v4l2_subdev *sd; in mxc_isi_pipe_init() local
759 pipe->id = id; in mxc_isi_pipe_init()
760 pipe->isi = isi; in mxc_isi_pipe_init()
761 pipe->regs = isi->regs + id * isi->pdata->reg_offset; in mxc_isi_pipe_init()
763 mutex_init(&pipe->lock); in mxc_isi_pipe_init()
765 pipe->available_res = MXC_ISI_CHANNEL_RES_LINE_BUF in mxc_isi_pipe_init()
767 pipe->acquired_res = 0; in mxc_isi_pipe_init()
768 pipe->chained_res = 0; in mxc_isi_pipe_init()
769 pipe->chained = false; in mxc_isi_pipe_init()
771 sd = &pipe->sd; in mxc_isi_pipe_init()
772 v4l2_subdev_init(sd, &mxc_isi_pipe_subdev_ops); in mxc_isi_pipe_init()
773 sd->internal_ops = &mxc_isi_pipe_internal_ops; in mxc_isi_pipe_init()
774 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in mxc_isi_pipe_init()
775 snprintf(sd->name, sizeof(sd->name), "mxc_isi.%d", pipe->id); in mxc_isi_pipe_init()
776 sd->dev = isi->dev; in mxc_isi_pipe_init()
778 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; in mxc_isi_pipe_init()
779 sd->entity.ops = &mxc_isi_pipe_entity_ops; in mxc_isi_pipe_init()
781 pipe->pads[MXC_ISI_PIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; in mxc_isi_pipe_init()
782 pipe->pads[MXC_ISI_PIPE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; in mxc_isi_pipe_init()
784 ret = media_entity_pads_init(&sd->entity, MXC_ISI_PIPE_PADS_NUM, in mxc_isi_pipe_init()
785 pipe->pads); in mxc_isi_pipe_init()
789 ret = v4l2_subdev_init_finalize(sd); in mxc_isi_pipe_init()
796 irq = platform_get_irq(to_platform_device(isi->dev), id); in mxc_isi_pipe_init()
802 ret = devm_request_irq(isi->dev, irq, mxc_isi_pipe_irq_handler, in mxc_isi_pipe_init()
803 0, dev_name(isi->dev), pipe); in mxc_isi_pipe_init()
805 dev_err(isi->dev, "failed to request IRQ (%d)\n", ret); in mxc_isi_pipe_init()
812 media_entity_cleanup(&sd->entity); in mxc_isi_pipe_init()
813 mutex_destroy(&pipe->lock); in mxc_isi_pipe_init()
820 struct v4l2_subdev *sd = &pipe->sd; in mxc_isi_pipe_cleanup() local
822 media_entity_cleanup(&sd->entity); in mxc_isi_pipe_cleanup()
823 mutex_destroy(&pipe->lock); in mxc_isi_pipe_cleanup()
833 struct v4l2_subdev *sd = &pipe->sd; in mxc_isi_pipe_acquire() local
838 state = v4l2_subdev_lock_and_get_active_state(sd); in mxc_isi_pipe_acquire()
843 sink_info = mxc_isi_bus_format_by_code(sink_fmt->code, in mxc_isi_pipe_acquire()
845 src_info = mxc_isi_bus_format_by_code(src_fmt->code, in mxc_isi_pipe_acquire()
848 bypass = sink_fmt->width == src_fmt->width && in mxc_isi_pipe_acquire()
849 sink_fmt->height == src_fmt->height && in mxc_isi_pipe_acquire()
850 sink_info->encoding == src_info->encoding; in mxc_isi_pipe_acquire()
857 if (sink_fmt->width > MXC_ISI_MAX_WIDTH_UNCHAINED) { in mxc_isi_pipe_acquire()